Compare commits

...

8 commits

Author SHA1 Message Date
Mike Cao
f5896f071b Handle user account redirect.
Some checks are pending
Node.js CI / build (postgresql, 18.18, 10) (push) Waiting to run
2025-12-01 23:33:57 -08:00
Mike Cao
06251e1317
Merge pull request #3803 from imsyedabdullah/3802-team-to-user-switch
Issue#3802 - Team to user switch fixed
2025-12-01 23:15:00 -08:00
Mike Cao
9a2827b50d
Merge pull request #3811 from IndraGunawan/support-uuidv7
add support for UUID v7
2025-12-01 23:11:23 -08:00
Mike Cao
3071ee8b88
Merge branch 'dev' into 3802-team-to-user-switch 2025-12-01 10:12:19 -08:00
Indra Gunawan
b16b98ffe8
Merge branch 'dev' into support-uuidv7 2025-12-01 17:02:26 +08:00
Indra Gunawan
4d70c3baf1 add support for UUID v7 2025-12-01 16:48:58 +08:00
Syed Abdullah
50bfee3328 Moved the redirect to else statement 2025-11-28 06:30:22 +00:00
Syed Abdullah
a645dc7ba5 Issue#3802 - Team to user switch fixed 2025-11-28 06:10:19 +00:00
4 changed files with 25 additions and 12 deletions

2
pnpm-lock.yaml generated
View file

@ -328,6 +328,8 @@ importers:
specifier: ^5.9.3 specifier: ^5.9.3
version: 5.9.3 version: 5.9.3
dist: {}
packages: packages:
'@ampproject/remapping@2.3.0': '@ampproject/remapping@2.3.0':

View file

@ -2,7 +2,7 @@
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { LAST_TEAM_CONFIG } from '@/lib/constants'; import { LAST_TEAM_CONFIG } from '@/lib/constants';
import { getItem, removeItem } from '@/lib/storage'; import { getItem } from '@/lib/storage';
export default function RootPage() { export default function RootPage() {
useEffect(() => { useEffect(() => {
@ -11,8 +11,6 @@ export default function RootPage() {
if (lastTeam) { if (lastTeam) {
redirect(`/teams/${lastTeam}/websites`); redirect(`/teams/${lastTeam}/websites`);
} else { } else {
removeItem(LAST_TEAM_CONFIG);
redirect(`/websites`); redirect(`/websites`);
} }
}, []); }, []);

View file

@ -14,6 +14,7 @@ import {
Text, Text,
} from '@umami/react-zen'; } from '@umami/react-zen';
import { ArrowRight } from 'lucide-react'; import { ArrowRight } from 'lucide-react';
import type { Key } from 'react';
import { import {
useConfig, useConfig,
useLoginQuery, useLoginQuery,
@ -33,7 +34,8 @@ import {
Users, Users,
} from '@/components/icons'; } from '@/components/icons';
import { Switch } from '@/components/svg'; import { Switch } from '@/components/svg';
import { DOCS_URL } from '@/lib/constants'; import { DOCS_URL, LAST_TEAM_CONFIG } from '@/lib/constants';
import { removeItem } from '@/lib/storage';
export interface TeamsButtonProps { export interface TeamsButtonProps {
showText?: boolean; showText?: boolean;
@ -44,7 +46,7 @@ export function NavButton({ showText = true }: TeamsButtonProps) {
const { user } = useLoginQuery(); const { user } = useLoginQuery();
const { cloudMode } = useConfig(); const { cloudMode } = useConfig();
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();
const { teamId } = useNavigation(); const { teamId, router } = useNavigation();
const { isMobile } = useMobile(); 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']);
@ -54,7 +56,16 @@ export function NavButton({ showText = true }: TeamsButtonProps) {
return cloudMode ? `${process.env.cloudUrl}${url}` : url; return cloudMode ? `${process.env.cloudUrl}${url}` : url;
}; };
const handleAction = async () => {}; const handleAction = async (key: Key) => {
if (key === 'user') {
removeItem(LAST_TEAM_CONFIG);
if (cloudMode) {
window.location.href = '/';
} else {
router.push('/');
}
}
};
return ( return (
<MenuTrigger> <MenuTrigger>
@ -84,16 +95,16 @@ export function NavButton({ showText = true }: TeamsButtonProps) {
</Pressable> </Pressable>
<Popover placement="bottom start"> <Popover placement="bottom start">
<Column minWidth="300px"> <Column minWidth="300px">
<Menu autoFocus="last" onAction={handleAction}> <Menu autoFocus="last">
<SubmenuTrigger> <SubmenuTrigger>
<MenuItem id="teams" showChecked={false} showSubMenuIcon> <MenuItem id="teams" showChecked={false} showSubMenuIcon>
<IconLabel icon={<Switch />} label={formatMessage(labels.switchAccount)} /> <IconLabel icon={<Switch />} label={formatMessage(labels.switchAccount)} />
</MenuItem> </MenuItem>
<Popover placement={isMobile ? 'bottom start' : 'right top'}> <Popover placement={isMobile ? 'bottom start' : 'right top'}>
<Column minWidth="300px"> <Column minWidth="300px">
<Menu selectionMode="single" selectedKeys={selectedKeys}> <Menu selectionMode="single" selectedKeys={selectedKeys} onAction={handleAction}>
<MenuSection title={formatMessage(labels.myAccount)}> <MenuSection title={formatMessage(labels.myAccount)}>
<MenuItem id="user" href={getUrl('/')}> <MenuItem id="user">
<IconLabel icon={<User />} label={user.username} /> <IconLabel icon={<User />} label={user.username} />
</MenuItem> </MenuItem>
</MenuSection> </MenuSection>

View file

@ -1,5 +1,5 @@
import crypto from 'node:crypto'; import crypto from 'node:crypto';
import { v4, v5 } from 'uuid'; import { v4, v5, v7 } from 'uuid';
const ALGORITHM = 'aes-256-gcm'; const ALGORITHM = 'aes-256-gcm';
const IV_LENGTH = 16; const IV_LENGTH = 16;
@ -57,7 +57,9 @@ export function secret() {
} }
export function uuid(...args: any) { export function uuid(...args: any) {
if (!args.length) return v4(); if (args.length) {
return v5(hash(...args, secret()), v5.DNS);
}
return v5(hash(...args, secret()), v5.DNS); return process.env.USE_UUIDV7 ? v7() : v4();
} }