Added menu options for cloud mode. Async fixes.

This commit is contained in:
Mike Cao 2025-09-23 09:14:01 -07:00
parent 4df6f06485
commit f639bb07f4
12 changed files with 47 additions and 27 deletions

View file

@ -17,7 +17,7 @@ export function PixelDeleteButton({
const { mutateAsync, isPending, error } = useDeleteQuery(`/pixels/${pixelId}`);
const { touch } = useModified();
const handleConfirm = (close: () => void) => {
const handleConfirm = async (close: () => void) => {
await mutateAsync(null, {
onSuccess: () => {
touch('pixels');

View file

@ -9,7 +9,7 @@ export function PixelEditButton({ pixelId }: { pixelId: string }) {
return (
<ActionButton title={formatMessage(labels.edit)} icon={<Edit />}>
<Dialog title={formatMessage(labels.pixel)} style={{ width: 800, minHeight: 300 }}>
<Dialog title={formatMessage(labels.pixel)} style={{ width: 600, minHeight: 300 }}>
{({ close }) => {
return <PixelEditForm pixelId={pixelId} onClose={close} />;
}}

View file

@ -106,10 +106,7 @@ export function PixelEditForm({
allowCopy
style={{ width: '100%' }}
/>
<Button
variant="quiet"
onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })}
>
<Button onPress={() => setValue('slug', handleSlug(), { shouldDirty: true })}>
<Icon>
<RefreshCw />
</Icon>

View file

@ -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, Pixel } from '@/components/icons';
import { ExternalLink, Grid2x2 } 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} icon={<Pixel />}>
<PageHeader title={pixel.name} description={pixel.slug} icon={<Grid2x2 />}>
<LinkButton href={getSlugUrl(pixel.slug)} target="_blank">
<Icon>
<ExternalLink />

View file

@ -1,8 +1,8 @@
import { PixelPage } from './PixelPage';
import { Metadata } from 'next';
export default async function ({ params }: { params: Promise<{ pixelId: string }> }) {
const { pixelId } = await params;
export default function ({ params }: { params: { pixelId: string } }) {
const { pixelId } = params;
return <PixelPage pixelId={pixelId} />;
}

View file

@ -4,7 +4,7 @@ import { Grid, Column } from '@umami/react-zen';
import { useMessages, useNavigation } from '@/components/hooks';
import { PageBody } from '@/components/common/PageBody';
import { SideMenu } from '@/components/common/SideMenu';
import { UserCircle, Users, Knobs } from '@/components/icons';
import { UserCircle, Users, Settings2 } from '@/components/icons';
export function SettingsLayout({ children }: { children: ReactNode }) {
const { formatMessage, labels } = useMessages();
@ -18,7 +18,7 @@ export function SettingsLayout({ children }: { children: ReactNode }) {
id: 'preferences',
label: formatMessage(labels.preferences),
path: renderUrl('/settings/preferences'),
icon: <Knobs />,
icon: <Settings2 />,
},
],
},

View file

@ -8,7 +8,7 @@ import {
Search,
Type,
SquareSlash,
SquareArrowRight,
Share2,
Megaphone,
Earth,
Globe,
@ -20,7 +20,7 @@ import {
Monitor,
Cpu,
LightningSvg,
LucideCaseSensitive,
Network,
Tag,
} from '@/components/icons';
@ -80,7 +80,7 @@ export function WebsiteExpandedView({
id: 'referrer',
label: formatMessage(labels.referrer),
path: updateParams({ view: 'referrer' }),
icon: <SquareArrowRight />,
icon: <Share2 />,
},
{
id: 'channel',
@ -167,7 +167,7 @@ export function WebsiteExpandedView({
id: 'hostname',
label: formatMessage(labels.hostname),
path: updateParams({ view: 'hostname' }),
icon: <LucideCaseSensitive />,
icon: <Network />,
},
{
id: 'tag',

View file

@ -10,7 +10,7 @@ import {
MagnetSvg,
Tag,
MoneySvg,
Network,
NetworkSvg,
ChartPie,
UserPlus,
CompareSvg,
@ -137,7 +137,7 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) {
{
id: 'attribution',
label: formatMessage(labels.attribution),
icon: <Network />,
icon: <NetworkSvg />,
path: renderPath('/attribution'),
},
],

View file

@ -1,6 +1,7 @@
import { List, ListItem } from '@umami/react-zen';
import { useWebsiteSegmentsQuery } from '@/components/hooks';
import { LoadingPanel } from '@/components/common/LoadingPanel';
import { Empty } from '@/components/common/Empty';
export interface SegmentFiltersProps {
websiteId: string;
@ -23,6 +24,7 @@ export function SegmentFilters({
return (
<LoadingPanel data={data} isLoading={isLoading} isFetching={isFetching} overflowY="auto">
{data?.data?.length === 0 && <Empty />}
<List selectionMode="single" value={[segmentId]} onChange={id => handleChange(id[0])}>
{data?.data?.map(item => {
return (

View file

@ -10,23 +10,27 @@ import {
MenuSection,
} from '@umami/react-zen';
import { useMessages, useLoginQuery, useNavigation, useConfig } from '@/components/hooks';
import { LogOut, LockKeyhole, Settings, UserCircle } from '@/components/icons';
import { LogOut, LockKeyhole, Settings, UserCircle, LifeBuoy, BookText } from '@/components/icons';
import { DOCS_URL } from '@/lib/constants';
export function SettingsButton() {
const { formatMessage, labels } = useMessages();
const { user } = useLoginQuery();
const { router, renderUrl } = useNavigation();
const { router } = useNavigation();
const { cloudMode } = useConfig();
const handleAction = (id: Key) => {
const url = `/${id}`;
const url = id.toString();
if (cloudMode) {
window.location.href = url;
return;
if (url === '/docs') {
window.open(DOCS_URL, '_blank');
} else {
window.location.href = url;
}
} else {
router.push(url);
}
router.push(renderUrl(url));
};
return (
@ -40,12 +44,26 @@ export function SettingsButton() {
<Menu autoFocus="last" onAction={handleAction}>
<MenuSection title={user.username}>
<MenuSeparator />
<MenuItem id="settings" icon={<Settings />} label={formatMessage(labels.settings)} />
<MenuItem id="/settings" icon={<Settings />} label={formatMessage(labels.settings)} />
{!cloudMode && user.isAdmin && (
<MenuItem id="admin" icon={<LockKeyhole />} label={formatMessage(labels.admin)} />
)}
{cloudMode && (
<>
<MenuItem
id="/docs"
icon={<BookText />}
label={formatMessage(labels.documentation)}
/>
<MenuItem
id="/settings/support"
icon={<LifeBuoy />}
label={formatMessage(labels.support)}
/>
</>
)}
<MenuSeparator />
<MenuItem id="logout" icon={<LogOut />} label={formatMessage(labels.logout)} />
<MenuItem id="/logout" icon={<LogOut />} label={formatMessage(labels.logout)} />
</MenuSection>
</Menu>
</Popover>

View file

@ -360,6 +360,8 @@ export const labels = defineMessages({
environment: { id: 'label.environment', defaultMessage: 'Environment' },
criteria: { id: 'label.criteria', defaultMessage: 'Criteria' },
share: { id: 'label.share', defaultMessage: 'Share' },
support: { id: 'label.support', defaultMessage: 'Support' },
documentation: { id: 'label.documentation', defaultMessage: 'Documentation' },
});
export const messages = defineMessages({

View file

@ -8,6 +8,7 @@ export const DASHBOARD_CONFIG = 'umami.dashboard';
export const VERSION_CHECK = 'umami.version-check';
export const SHARE_TOKEN_HEADER = 'x-umami-share-token';
export const HOMEPAGE_URL = 'https://umami.is';
export const DOCS_URL = 'https://umami.is/docs';
export const REPO_URL = 'https://github.com/umami-software/umami';
export const UPDATES_URL = 'https://api.umami.is/v1/updates';
export const TELEMETRY_PIXEL = 'https://i.umami.is/a.png';