diff --git a/package.json b/package.json index 455dff953..f4ccbc640 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "@react-spring/web": "^10.0.1", "@svgr/cli": "^8.1.0", "@tanstack/react-query": "^5.85.5", - "@umami/react-zen": "^0.184.0", + "@umami/react-zen": "^0.181.0", "@umami/redis-client": "^0.29.0", "bcryptjs": "^3.0.2", "chalk": "^5.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c71a6ef7d..865d02cf1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,8 +45,8 @@ importers: specifier: ^5.85.5 version: 5.85.5(react@19.1.1) '@umami/react-zen': - specifier: ^0.184.0 - version: 0.184.0(@babel/core@7.28.3)(@types/react@19.1.12)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) + specifier: ^0.181.0 + version: 0.181.0(@babel/core@7.28.3)(@types/react@19.1.12)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) '@umami/redis-client': specifier: ^0.29.0 version: 0.29.0 @@ -1061,8 +1061,8 @@ packages: '@fontsource/inter@5.2.6': resolution: {integrity: sha512-CZs9S1CrjD0jPwsNy9W6j0BhsmRSQrgwlTNkgQXTsAeDRM42LBRLo3eo9gCzfH4GvV7zpyf78Ozfl773826csw==} - '@fontsource/jetbrains-mono@5.2.8': - resolution: {integrity: sha512-6w8/SG4kqvIMu7xd7wt6x3idn1Qux3p9N62s6G3rfldOUYHpWcc2FKrqf+Vo44jRvqWj2oAtTHrZXEP23oSKwQ==} + '@fontsource/jetbrains-mono@5.2.6': + resolution: {integrity: sha512-nz//dBr99hXZmHp10wgNI00qThWImkzRR5PQjvRM+rpmuHO5rYBJCqPPWufidCvmkkryXx/GOP/lgqsM3R3Org==} '@formatjs/cli@4.8.4': resolution: {integrity: sha512-zZI8QYVl5CHaT6j9OHjS+0mMnWzopBVH0un4n5b4IhIJRzIKnxwFTkxBp5Ifqj6FntrwzIGqP+D6v8u7MPYsmw==} @@ -1539,8 +1539,8 @@ packages: '@prisma/get-platform@6.16.0': resolution: {integrity: sha512-eaJOOvAoGslSUTjiQrtE9E0hoBdfL43j8SymOGD6LbdrKRNtIoiy6qiBaEr2fNYD+R/Qns7QOwPhl7SVHJayKA==} - '@react-aria/autocomplete@3.0.0-rc.2': - resolution: {integrity: sha512-55KVj5FePFTHk8nWfUUNN8m7rBL+aSRE0CxHI2t8JG3uam3nY7jyuAJy34RBuDEdTsVlMO9Fri/1JragePC2dg==} + '@react-aria/autocomplete@3.0.0-rc.1': + resolution: {integrity: sha512-4/+XHkCq9nkC0TNfgPsbuMTu3iwM6Gz4j67rTQRMXrWwCTAqAHJJEmDz/YDt/04Rg+dkGPsauHHMqDxwxZV24Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -1569,8 +1569,8 @@ packages: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/collections@3.0.0-rc.7': - resolution: {integrity: sha512-JMktVhe+OT6rZVcGdmSWgNj3VBq4Owm3L5LD8iMwJrV6SgPGmyzpguX7JTnz1hnSWO/wD2vrwMWEAlcuL7acBg==} + '@react-aria/collections@3.0.0-rc.6': + resolution: {integrity: sha512-N4AzRqzFJ4BztM1x56ot33smDUUsYQ6pzlbz6m4f8ARSqQYl0a2FsM13PYDtuNI5Dt9KtkL6rK/tLaZlTghLyg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -2735,8 +2735,8 @@ packages: '@prisma/client': ^6.1.0 '@prisma/extension-read-replicas': ^0.4.1 - '@umami/react-zen@0.184.0': - resolution: {integrity: sha512-XfxTiP4ljumflx02ymDMXLnhcJW+mOxxKCPEVEjuDrQfR6VUlbHg0EdH04S4gvCJZJC/WnP6guyO2eabhJL88Q==} + '@umami/react-zen@0.181.0': + resolution: {integrity: sha512-Hs5dXPWVOtgHwAksolVTZw8n8EucHq+Xj+++a6RpfzHix3m2sWQXo1qNwd11GasxytqDf6JSxETj109LCUJiSA==} '@umami/redis-client@0.29.0': resolution: {integrity: sha512-Jaqh++jskqDB7ny75pfC02OvKp1JTS4asGDsFrRL3qy8sxL3PAl9+/mybCJe4/6vWrXDJKqpgkSfUDJq2bFjyw==} @@ -6302,14 +6302,14 @@ packages: rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} - react-aria-components@1.12.2: - resolution: {integrity: sha512-BTA697VWy6Who9cpSbll447kqqpwxYvN6QF3/+AmXO+M+KgUXtPZAaNXu/9Sv2LdshU0zhIea4w27ZOt57UzPQ==} + react-aria-components@1.12.1: + resolution: {integrity: sha512-UTn2y2Pr1QuapXLRoGE/GWHrjcZZSuMf+zhbJjInOHgS+MC4hqXiINufvjQrdjQDzS1llc2aepP9op6+z6QSxA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-aria@3.43.2: - resolution: {integrity: sha512-CfaXi3S69SeOkpp6pGc1w5FH8OvGPFphiMrO2tNSlqpYIecgk3gKoXjkqaAr6N+O1gasLMfAAF9sxtvS141qWg==} + react-aria@3.43.1: + resolution: {integrity: sha512-/PmZGiw+Ya/YtzXmiLW4ALD4SMuDnbwhMaVh33VCduTl8vVujIUzUTIi5g4C+YHLDs/Z4edsN3aQsPMqFfg1xA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 @@ -6324,8 +6324,8 @@ packages: peerDependencies: react: '>=16.13.1' - react-hook-form@7.63.0: - resolution: {integrity: sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==} + react-hook-form@7.62.0: + resolution: {integrity: sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -8062,7 +8062,7 @@ snapshots: '@fontsource/inter@5.2.6': {} - '@fontsource/jetbrains-mono@5.2.8': {} + '@fontsource/jetbrains-mono@5.2.6': {} '@formatjs/cli@4.8.4(ts-jest@29.4.1(@babel/core@7.28.3)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.3))(esbuild@0.25.9)(jest-util@30.0.5)(jest@29.7.0(@types/node@24.3.0)(ts-node@10.9.2(@types/node@24.3.0)(typescript@5.9.2)))(typescript@5.9.2))': dependencies: @@ -8650,7 +8650,7 @@ snapshots: dependencies: '@prisma/debug': 6.16.0 - '@react-aria/autocomplete@3.0.0-rc.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@react-aria/autocomplete@3.0.0-rc.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@react-aria/combobox': 3.13.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-aria/focus': 3.21.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -8723,7 +8723,7 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - '@react-aria/collections@3.0.0-rc.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + '@react-aria/collections@3.0.0-rc.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@react-aria/interactions': 3.25.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-aria/ssr': 3.9.10(react@19.1.1) @@ -10323,9 +10323,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@umami/react-zen@0.184.0(@babel/core@7.28.3)(@types/react@19.1.12)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.1)(use-sync-external-store@1.5.0(react@19.1.1))': + '@umami/react-zen@0.181.0(@babel/core@7.28.3)(@types/react@19.1.12)(babel-plugin-react-compiler@19.1.0-rc.2)(immer@10.1.1)(use-sync-external-store@1.5.0(react@19.1.1))': dependencies: - '@fontsource/jetbrains-mono': 5.2.8 + '@fontsource/jetbrains-mono': 5.2.6 '@internationalized/date': 3.9.0 '@react-aria/focus': 3.21.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-spring/web': 9.7.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -10335,9 +10335,9 @@ snapshots: lucide-react: 0.511.0(react@19.1.1) next: 15.5.3(@babel/core@7.28.3)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 - react-aria-components: 1.12.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-aria-components: 1.12.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-dom: 19.1.1(react@19.1.1) - react-hook-form: 7.63.0(react@19.1.1) + react-hook-form: 7.62.0(react@19.1.1) react-icons: 5.5.0(react@19.1.1) thenby: 1.3.4 zustand: 5.0.8(@types/react@19.1.12)(immer@10.1.1)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) @@ -14375,12 +14375,12 @@ snapshots: defu: 6.1.4 destr: 2.0.5 - react-aria-components@1.12.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + react-aria-components@1.12.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@internationalized/date': 3.9.0 '@internationalized/string': 3.2.7 - '@react-aria/autocomplete': 3.0.0-rc.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - '@react-aria/collections': 3.0.0-rc.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/autocomplete': 3.0.0-rc.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/collections': 3.0.0-rc.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-aria/dnd': 3.11.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-aria/focus': 3.21.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-aria/interactions': 3.25.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -14404,12 +14404,12 @@ snapshots: '@swc/helpers': 0.5.17 client-only: 0.0.1 react: 19.1.1 - react-aria: 3.43.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-aria: 3.43.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-dom: 19.1.1(react@19.1.1) react-stately: 3.41.0(react@19.1.1) use-sync-external-store: 1.5.0(react@19.1.1) - react-aria@3.43.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + react-aria@3.43.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@internationalized/string': 3.2.7 '@react-aria/breadcrumbs': 3.5.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -14466,7 +14466,7 @@ snapshots: '@babel/runtime': 7.28.3 react: 19.1.1 - react-hook-form@7.63.0(react@19.1.1): + react-hook-form@7.62.0(react@19.1.1): dependencies: react: 19.1.1 diff --git a/src/app/(main)/SideNav.tsx b/src/app/(main)/SideNav.tsx index c351ef47f..df989f5e4 100644 --- a/src/app/(main)/SideNav.tsx +++ b/src/app/(main)/SideNav.tsx @@ -8,7 +8,7 @@ import { SidebarProps, ThemeButton, } from '@umami/react-zen'; -import { Globe, LinkIcon, LogoSvg, Grid2x2, PanelLeft } from '@/components/icons'; +import { Globe, Link as LinkIcon, Logo, Pixel, PanelLeft } from '@/components/icons'; import { useMessages, useNavigation, useGlobalState } from '@/components/hooks'; import { TeamsButton } from '@/components/input/TeamsButton'; import { PanelButton } from '@/components/input/PanelButton'; @@ -39,7 +39,7 @@ export function SideNav(props: SidebarProps) { id: 'pixels', label: formatMessage(labels.pixels), path: '/pixels', - icon: , + icon: , }, ]; @@ -53,7 +53,7 @@ export function SideNav(props: SidebarProps) { setIsCollapsed(false)}> : } + icon={isCollapsed && !hasNav ? : } style={{ maxHeight: 40 }} > {!isCollapsed && !hasNav && } diff --git a/src/app/(main)/links/LinkEditForm.tsx b/src/app/(main)/links/LinkEditForm.tsx index ab1b0e40d..23aaab1e6 100644 --- a/src/app/(main)/links/LinkEditForm.tsx +++ b/src/app/(main)/links/LinkEditForm.tsx @@ -13,7 +13,7 @@ import { } from '@umami/react-zen'; import { useConfig, useLinkQuery } from '@/components/hooks'; import { useMessages } from '@/components/hooks'; -import { RefreshCw } from '@/components/icons'; +import { Refresh } from '@/components/icons'; import { getRandomChars } from '@/lib/generate'; import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; import { LINKS_URL } from '@/lib/constants'; @@ -127,7 +127,7 @@ export function LinkEditForm({ onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })} > - + diff --git a/src/app/(main)/pixels/PixelEditForm.tsx b/src/app/(main)/pixels/PixelEditForm.tsx index b85d363bb..61971e795 100644 --- a/src/app/(main)/pixels/PixelEditForm.tsx +++ b/src/app/(main)/pixels/PixelEditForm.tsx @@ -12,7 +12,7 @@ import { } from '@umami/react-zen'; import { useConfig, usePixelQuery } from '@/components/hooks'; import { useMessages } from '@/components/hooks'; -import { RefreshCw } from '@/components/icons'; +import { Refresh } from '@/components/icons'; import { getRandomChars } from '@/lib/generate'; import { useUpdateQuery } from '@/components/hooks/queries/useUpdateQuery'; import { useEffect, useState } from 'react'; @@ -111,7 +111,7 @@ export function PixelEditForm({ onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })} > - + diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx index 7237dc9c7..a91b41e9b 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx @@ -1,7 +1,7 @@ import { Grid, Column, Row, Text, Icon, ProgressBar, Dialog, Box } from '@umami/react-zen'; import { useMessages, useResultQuery } from '@/components/hooks'; import { LoadingPanel } from '@/components/common/LoadingPanel'; -import { File, LightningSvg, User } from '@/components/icons'; +import { File, Lightning, User } from '@/components/icons'; import { formatLongNumber } from '@/lib/format'; import { ReportEditButton } from '@/components/input/ReportEditButton'; import { FunnelEditForm } from './FunnelEditForm'; @@ -92,7 +92,7 @@ export function Funnel({ id, name, type, parameters, websiteId }) { - {type === 'path' ? : } + {type === 'path' ? : } {value} diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx index 01940beb0..57675bdf7 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx @@ -14,7 +14,7 @@ import { Column, } from '@umami/react-zen'; import { useMessages, useReportQuery, useUpdateQuery } from '@/components/hooks'; -import { X, Plus } from '@/components/icons'; +import { Close, Plus } from '@/components/icons'; import { ActionSelect } from '@/components/input/ActionSelect'; import { LookupField } from '@/components/input/LookupField'; @@ -36,8 +36,6 @@ export function FunnelEditForm({ const { mutate, error, isPending, touch } = useUpdateQuery(`/reports${id ? `/${id}` : ''}`); const handleSubmit = async ({ name, ...parameters }) => { - // - mutate( { ...data, id, name, type: 'funnel', websiteId, parameters }, { @@ -77,13 +75,7 @@ export function FunnelEditForm({ > - value.length > 1 || 'At least two steps are required', - }} - > + {({ fields, append, remove, getValues }) => { return ( @@ -112,7 +104,7 @@ export function FunnelEditForm({ diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx index d930a9b71..9ef5840cf 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx @@ -1,7 +1,7 @@ import { Grid, Row, Column, Text, Icon, ProgressBar, Dialog } from '@umami/react-zen'; import { ReportEditButton } from '@/components/input/ReportEditButton'; import { useMessages, useResultQuery } from '@/components/hooks'; -import { File, LightningSvg, User } from '@/components/icons'; +import { File, Lightning, User } from '@/components/icons'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { formatLongNumber } from '@/lib/format'; import { GoalEditForm } from './GoalEditForm'; @@ -68,7 +68,7 @@ export function Goal({ id, name, type, parameters, websiteId, startDate, endDate - {parameters.type === 'path' ? : } + {parameters.type === 'path' ? : } {parameters.value} diff --git a/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx index 581d69abe..965e7a31f 100644 --- a/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx +++ b/src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx @@ -3,7 +3,7 @@ import { TooltipTrigger, Tooltip, Focusable, Icon, Text, Row, Column } from '@um import { firstBy } from 'thenby'; import classNames from 'classnames'; import { useEscapeKey, useMessages, useResultQuery } from '@/components/hooks'; -import { File, LightningSvg } from '@/components/icons'; +import { File, Lightning } from '@/components/icons'; import { objectToArray } from '@/lib/data'; import { formatLongNumber } from '@/lib/format'; import { LoadingPanel } from '@/components/common/LoadingPanel'; @@ -215,7 +215,7 @@ export function Journey({ websiteId, steps, startStep, endStep }: JourneyProps) onClick={() => handleClick(name, columnIndex, paths)} > - {name.startsWith('/') ? : } + {name.startsWith('/') ? : } {name}
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx index 239d51332..28a0c0017 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx @@ -2,27 +2,6 @@ import { Grid, Column } from '@umami/react-zen'; import { useMessages, useNavigation } from '@/components/hooks'; import { MetricsExpandedTable } from '@/components/metrics/MetricsExpandedTable'; import { SideMenu } from '@/components/common/SideMenu'; -import { - LogOut, - LogIn, - Search, - Type, - SquareSlash, - SquareArrowRight, - Megaphone, - Earth, - Globe, - Landmark, - MapPin, - AppWindow, - Laptop, - Languages, - Monitor, - Cpu, - LightningSvg, - LucideCaseSensitive, - Tag, -} from '@/components/icons'; export function WebsiteExpandedView({ websiteId, @@ -45,31 +24,26 @@ export function WebsiteExpandedView({ id: 'path', label: formatMessage(labels.path), path: updateParams({ view: 'path' }), - icon: , }, { id: 'entry', label: formatMessage(labels.entry), path: updateParams({ view: 'entry' }), - icon: , }, { id: 'exit', label: formatMessage(labels.exit), path: updateParams({ view: 'exit' }), - icon: , }, { id: 'title', label: formatMessage(labels.title), path: updateParams({ view: 'title' }), - icon: , }, { id: 'query', label: formatMessage(labels.query), path: updateParams({ view: 'query' }), - icon: , }, ], }, @@ -80,19 +54,16 @@ export function WebsiteExpandedView({ id: 'referrer', label: formatMessage(labels.referrer), path: updateParams({ view: 'referrer' }), - icon: , }, { id: 'channel', label: formatMessage(labels.channel), path: updateParams({ view: 'channel' }), - icon: , }, { id: 'domain', label: formatMessage(labels.domain), path: updateParams({ view: 'domain' }), - icon: , }, ], }, @@ -103,19 +74,16 @@ export function WebsiteExpandedView({ id: 'country', label: formatMessage(labels.country), path: updateParams({ view: 'country' }), - icon: , }, { id: 'region', label: formatMessage(labels.region), path: updateParams({ view: 'region' }), - icon: , }, { id: 'city', label: formatMessage(labels.city), path: updateParams({ view: 'city' }), - icon: , }, ], }, @@ -126,31 +94,26 @@ export function WebsiteExpandedView({ id: 'browser', label: formatMessage(labels.browser), path: updateParams({ view: 'browser' }), - icon: , }, { id: 'os', label: formatMessage(labels.os), path: updateParams({ view: 'os' }), - icon: , }, { id: 'device', label: formatMessage(labels.device), path: updateParams({ view: 'device' }), - icon: , }, { id: 'language', label: formatMessage(labels.language), path: updateParams({ view: 'language' }), - icon: , }, { id: 'screen', label: formatMessage(labels.screen), path: updateParams({ view: 'screen' }), - icon: , }, ], }, @@ -161,19 +124,16 @@ export function WebsiteExpandedView({ id: 'event', label: formatMessage(labels.event), path: updateParams({ view: 'event' }), - icon: , }, { id: 'hostname', label: formatMessage(labels.hostname), path: updateParams({ view: 'hostname' }), - icon: , }, { id: 'tag', label: formatMessage(labels.tag), path: updateParams({ view: 'tag' }), - icon: , }, ], }, @@ -182,7 +142,7 @@ export function WebsiteExpandedView({ return ( - + , + icon: , path: renderPath('/events'), }, { @@ -62,7 +62,7 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) { { id: 'compare', label: formatMessage(labels.compare), - icon: , + icon: , path: renderPath('/compare'), }, { @@ -79,25 +79,25 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) { { id: 'goals', label: formatMessage(labels.goals), - icon: , + icon: , path: renderPath('/goals'), }, { id: 'funnel', label: formatMessage(labels.funnels), - icon: , + icon: , path: renderPath('/funnels'), }, { id: 'journeys', label: formatMessage(labels.journeys), - icon: , + icon: , path: renderPath('/journeys'), }, { id: 'retention', label: formatMessage(labels.retention), - icon: , + icon: , path: renderPath('/retention'), }, ], @@ -131,7 +131,7 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) { { id: 'revenue', label: formatMessage(labels.revenue), - icon: , + icon: , path: renderPath('/revenue'), }, { diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionInfo.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionInfo.tsx index 2ec515f90..629e1da66 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionInfo.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionInfo.tsx @@ -2,7 +2,7 @@ import { ReactNode } from 'react'; import { Icon, TextField, Column, Row, Label, Text } from '@umami/react-zen'; import { useFormat, useLocale, useMessages, useRegionNames } from '@/components/hooks'; import { TypeIcon } from '@/components/common/TypeIcon'; -import { LocationSvg, KeyRound, Calendar } from '@/components/icons'; +import { Location, KeyRound, Calendar } from '@/components/icons'; import { DateDistance } from '@/components/common/DateDistance'; export function SessionInfo({ data }) { @@ -36,11 +36,11 @@ export function SessionInfo({ data }) { {formatValue(data?.country, 'country')} - }> + }> {getRegionName(data?.region)} - }> + }> {data?.city} diff --git a/src/app/api/batch/route.ts b/src/app/api/batch/route.ts index 6feab06b6..87e04110d 100644 --- a/src/app/api/batch/route.ts +++ b/src/app/api/batch/route.ts @@ -2,9 +2,8 @@ import { z } from 'zod'; import * as send from '@/app/api/send/route'; import { parseRequest } from '@/lib/request'; import { json, serverError } from '@/lib/response'; -import { anyObjectParam } from '@/lib/schema'; -const schema = z.array(anyObjectParam); +const schema = z.array(z.object({}).passthrough()); export async function POST(request: Request) { try { diff --git a/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts b/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts index b784fa5ae..4418cfe57 100644 --- a/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts +++ b/src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts @@ -1,7 +1,7 @@ import { canDeleteWebsite, canUpdateWebsite, canViewWebsite } from '@/permissions'; import { parseRequest } from '@/lib/request'; import { json, notFound, ok, unauthorized } from '@/lib/response'; -import { anyObjectParam, segmentTypeParam } from '@/lib/schema'; +import { segmentTypeParam } from '@/lib/schema'; import { deleteSegment, getSegment, updateSegment } from '@/queries'; import { z } from 'zod'; @@ -33,7 +33,7 @@ export async function POST( const schema = z.object({ type: segmentTypeParam, name: z.string().max(200), - parameters: anyObjectParam, + parameters: z.object({}).passthrough(), }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/api/websites/[websiteId]/segments/route.ts b/src/app/api/websites/[websiteId]/segments/route.ts index e842dcc79..fcc2e0a3c 100644 --- a/src/app/api/websites/[websiteId]/segments/route.ts +++ b/src/app/api/websites/[websiteId]/segments/route.ts @@ -2,7 +2,7 @@ import { canUpdateWebsite, canViewWebsite } from '@/permissions'; import { uuid } from '@/lib/crypto'; import { getQueryFilters, parseRequest } from '@/lib/request'; import { json, unauthorized } from '@/lib/response'; -import { segmentTypeParam, searchParams, anyObjectParam } from '@/lib/schema'; +import { segmentTypeParam, searchParams } from '@/lib/schema'; import { createSegment, getWebsiteSegments } from '@/queries'; import { z } from 'zod'; @@ -42,7 +42,7 @@ export async function POST( const schema = z.object({ type: segmentTypeParam, name: z.string().max(200), - parameters: anyObjectParam, + parameters: z.object({}).passthrough(), }); const { auth, body, error } = await parseRequest(request, schema); diff --git a/src/app/login/LoginForm.tsx b/src/app/login/LoginForm.tsx index 3dcbadef7..c0cff75a9 100644 --- a/src/app/login/LoginForm.tsx +++ b/src/app/login/LoginForm.tsx @@ -13,7 +13,7 @@ import { useRouter } from 'next/navigation'; import { useMessages, useUpdateQuery } from '@/components/hooks'; import { setUser } from '@/store/app'; import { setClientAuthToken } from '@/lib/client'; -import { LogoSvg } from '@/components/icons'; +import { Logo } from '@/components/icons'; export function LoginForm() { const { formatMessage, labels, getErrorMessage } = useMessages(); @@ -34,7 +34,7 @@ export function LoginForm() { return ( - + umami
diff --git a/src/components/common/ErrorMessage.tsx b/src/components/common/ErrorMessage.tsx index 6bf9003cc..8d3ef8c98 100644 --- a/src/components/common/ErrorMessage.tsx +++ b/src/components/common/ErrorMessage.tsx @@ -1,6 +1,6 @@ import { Icon, Text, Row } from '@umami/react-zen'; import { useMessages } from '@/components/hooks'; -import { AlertTriangle } from '@/components/icons'; +import { Alert } from '@/components/icons'; export function ErrorMessage() { const { formatMessage, messages } = useMessages(); @@ -8,7 +8,7 @@ export function ErrorMessage() { return ( - + {formatMessage(messages.error)} diff --git a/src/components/common/FilterRecord.tsx b/src/components/common/FilterRecord.tsx index 7278d23cf..6b7a6e043 100644 --- a/src/components/common/FilterRecord.tsx +++ b/src/components/common/FilterRecord.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { Grid, Column, TextField, Label, Select, Icon, Button, ListItem } from '@umami/react-zen'; import { useFilters, useFormat, useWebsiteValuesQuery } from '@/components/hooks'; -import { X } from '@/components/icons'; +import { Close } from '@/components/icons'; import { isSearchOperator } from '@/lib/params'; import { Empty } from '@/components/common/Empty'; @@ -107,7 +107,7 @@ export function FilterRecord({ diff --git a/src/components/common/Pager.tsx b/src/components/common/Pager.tsx index c65e2f6ab..abc0c172a 100644 --- a/src/components/common/Pager.tsx +++ b/src/components/common/Pager.tsx @@ -1,6 +1,6 @@ import { Button, Icon, Row, Text } from '@umami/react-zen'; import { useMessages } from '@/components/hooks'; -import { ChevronRight } from '@/components/icons'; +import { Chevron } from '@/components/icons'; export interface PagerProps { page: string | number; @@ -45,12 +45,12 @@ export function Pager({ page, pageSize, count, onPageChange }: PagerProps) { diff --git a/src/components/common/Panel.tsx b/src/components/common/Panel.tsx index 51f0aa762..00a988000 100644 --- a/src/components/common/Panel.tsx +++ b/src/components/common/Panel.tsx @@ -9,7 +9,7 @@ import { Tooltip, Heading, } from '@umami/react-zen'; -import { Maximize, X } from '@/components/icons'; +import { Maximize, Close } from '@/components/icons'; import { useMessages } from '@/components/hooks'; export interface PanelProps extends ColumnProps { @@ -59,7 +59,7 @@ export function Panel({ {formatMessage(labels.maximize)} diff --git a/src/components/icons.ts b/src/components/icons.ts index 0280c31a5..287dc650c 100644 --- a/src/components/icons.ts +++ b/src/components/icons.ts @@ -1,17 +1,71 @@ -export * from 'lucide-react'; export { - Logo as LogoSvg, - Bolt as BoltSvg, - Change as ChangeSvg, - Compare as CompareSvg, - Funnel as FunnelSvg, - Lightbulb as LightbulbSvg, - Lightning as LightningSvg, - Location as LocationSvg, - Magnet as MagnetSvg, - Money as MoneySvg, - Network as NetworkSvg, - Path as PathSvg, - Tag as TagSvg, - Target as TargetSvg, + AlertTriangle as Alert, + ArrowRight as Arrow, + Bookmark, + Calendar, + ChartPie, + ChevronRight as Chevron, + Clock, + Copy, + Database, + Download, + Edit, + Ellipsis, + Equal, + Eye, + ExternalLink, + File, + FileJson, + FileText, + Globe, + Grid2X2 as Pixel, + KeyRound, + LayoutDashboard, + Link, + ListCheck, + ListFilter, + LockKeyhole, + LogOut, + Maximize, + Menu, + Minimize, + Moon, + MoreHorizontal as More, + Paperclip, + PanelLeft, + Plus, + RefreshCw as Refresh, + Settings, + Settings2 as Knobs, + Share, + Sheet, + Slash, + SquarePen, + SquarePlus, + Sun, + Trash, + Upload, + User, + CircleUserRound as UserCircle, + Users, + UserPlus, + X as Close, +} from 'lucide-react'; +export { + Logo, + Bolt, + Change, + Compare, + Funnel, + Lightbulb, + Lightning, + Location, + Magnet, + Money, + Network, + Path, + Tag, + Target, + AddUser, + Visitor, } from '@/components/svg'; diff --git a/src/components/input/FilterBar.tsx b/src/components/input/FilterBar.tsx index 96ad51b4f..971baab26 100644 --- a/src/components/input/FilterBar.tsx +++ b/src/components/input/FilterBar.tsx @@ -16,7 +16,7 @@ import { useFilters, useWebsiteSegmentQuery, } from '@/components/hooks'; -import { X, Bookmark } from '@/components/icons'; +import { Close, Bookmark } from '@/components/icons'; import { isSearchOperator } from '@/lib/params'; import { SegmentEditForm } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditForm'; @@ -111,7 +111,7 @@ export function FilterBar({ websiteId }: { websiteId: string }) { @@ -146,7 +146,7 @@ const FilterItem = ({ name, label, operator, value, onRemove }) => { onRemove(name)} size="xs" style={{ cursor: 'pointer' }}> - + diff --git a/src/components/input/ReportEditButton.tsx b/src/components/input/ReportEditButton.tsx index 38fa17dd3..0569ed6fd 100644 --- a/src/components/input/ReportEditButton.tsx +++ b/src/components/input/ReportEditButton.tsx @@ -13,7 +13,7 @@ import { Text, Row, } from '@umami/react-zen'; -import { Edit, MoreHorizontal, Trash } from '@/components/icons'; +import { Edit, More, Trash } from '@/components/icons'; export function ReportEditButton({ id, @@ -61,7 +61,7 @@ export function ReportEditButton({ @@ -90,7 +90,9 @@ export function ReportEditButton({ onCancel={handleClose} isDanger > - {formatMessage(messages.confirmDelete, { target: name })} + + {formatMessage(messages.confirmDelete, { target: {name} })} + )} diff --git a/src/components/input/TeamsButton.tsx b/src/components/input/TeamsButton.tsx index 3ddcdc555..274e6c87c 100644 --- a/src/components/input/TeamsButton.tsx +++ b/src/components/input/TeamsButton.tsx @@ -13,7 +13,7 @@ import { Loading, } from '@umami/react-zen'; import { useLoginQuery, useMessages, useUserTeamsQuery, useNavigation } from '@/components/hooks'; -import { ChevronRight, User, Users } from '@/components/icons'; +import { Chevron, User, Users } from '@/components/icons'; export interface TeamsButtonProps { showText?: boolean; @@ -50,7 +50,7 @@ export function TeamsButton({ showText = true, onAction }: TeamsButtonProps) { {showText && ( - + )} diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx index 475fce44a..47cc82bb9 100644 --- a/src/components/input/WebsiteDateFilter.tsx +++ b/src/components/input/WebsiteDateFilter.tsx @@ -1,6 +1,6 @@ import { Button, Icon, Row, Text, Select, ListItem } from '@umami/react-zen'; import { isAfter } from 'date-fns'; -import { ChevronRight } from '@/components/icons'; +import { Chevron } from '@/components/icons'; import { useDateRange, useMessages, useNavigation } from '@/components/hooks'; import { DateFilter } from './DateFilter'; @@ -49,17 +49,17 @@ export function WebsiteDateFilter({ )} - + {!neutral && ( - + )} {children || value} diff --git a/src/components/metrics/MetricsExpandedTable.tsx b/src/components/metrics/MetricsExpandedTable.tsx index e15d2d56d..164a92ef7 100644 --- a/src/components/metrics/MetricsExpandedTable.tsx +++ b/src/components/metrics/MetricsExpandedTable.tsx @@ -2,7 +2,7 @@ import { ReactNode, useState } from 'react'; import { Button, Column, DataColumn, DataTable, Icon, Row, SearchField } from '@umami/react-zen'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import { useMessages, useWebsiteExpandedMetricsQuery } from '@/components/hooks'; -import { X } from '@/components/icons'; +import { Close } from '@/components/icons'; import { DownloadButton } from '@/components/input/DownloadButton'; import { formatShortTime } from '@/lib/format'; import { MetricLabel } from '@/components/metrics/MetricLabel'; @@ -55,7 +55,7 @@ export function MetricsExpandedTable({ {onClose && ( )} diff --git a/src/lib/schema.ts b/src/lib/schema.ts index 965eae079..36bf50daa 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -57,7 +57,7 @@ export const userRoleParam = z.enum(['admin', 'user', 'view-only']); export const teamRoleParam = z.enum(['team-member', 'team-view-only', 'team-manager']); -export const anyObjectParam = z.record(z.string(), z.any()); +export const anyObjectParam = z.object({}).passthrough(); export const urlOrPathParam = z.string().refine( value => { @@ -202,7 +202,7 @@ export const reportBaseSchema = z.object({ type: reportTypeParam, name: z.string().max(200), description: z.string().max(500).optional(), - parameters: anyObjectParam, + parameters: z.object({}).passthrough(), }); export const reportTypeSchema = z.discriminatedUnion('type', [ diff --git a/src/permissions/website.ts b/src/permissions/website.ts index 7badce1c5..11e8dc650 100644 --- a/src/permissions/website.ts +++ b/src/permissions/website.ts @@ -14,10 +14,6 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri const website = await getWebsite(websiteId); - if (!website) { - return false; - } - if (website.userId) { return user.id === website.userId; } @@ -50,10 +46,6 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) { const website = await getWebsite(websiteId); - if (!website) { - return false; - } - if (website.userId) { return user.id === website.userId; } @@ -74,10 +66,6 @@ export async function canDeleteWebsite({ user }: Auth, websiteId: string) { const website = await getWebsite(websiteId); - if (!website) { - return false; - } - if (website.userId) { return user.id === website.userId; } @@ -94,10 +82,6 @@ export async function canDeleteWebsite({ user }: Auth, websiteId: string) { export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string, userId: string) { const website = await getWebsite(websiteId); - if (!website) { - return false; - } - if (website.teamId && user.id === userId) { const teamUser = await getTeamUser(website.teamId, userId); @@ -110,10 +94,6 @@ export async function canTransferWebsiteToUser({ user }: Auth, websiteId: string export async function canTransferWebsiteToTeam({ user }: Auth, websiteId: string, teamId: string) { const website = await getWebsite(websiteId); - if (!website) { - return false; - } - if (website.userId && website.userId === user.id) { const teamUser = await getTeamUser(teamId, user.id); diff --git a/src/store/app.ts b/src/store/app.ts index 9ed3641c3..3f22756db 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -11,9 +11,17 @@ import { import { getItem } from '@/lib/storage'; import { getTimezone } from '@/lib/date'; +function getDefaultTheme() { + return typeof window !== 'undefined' + ? window?.matchMedia('(prefers-color-scheme: dark)')?.matches + ? 'dark' + : 'light' + : 'light'; +} + const initialState = { locale: getItem(LOCALE_CONFIG) || process.env.defaultLocale || DEFAULT_LOCALE, - theme: getItem(THEME_CONFIG) || DEFAULT_THEME, + theme: getItem(THEME_CONFIG) || getDefaultTheme() || DEFAULT_THEME, timezone: getItem(TIMEZONE_CONFIG) || getTimezone(), dateRangeValue: getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE, shareToken: null,