feat: implement logout on 401 response and update query handling

refactor: replace Button with div for consistent styling in AIEditorLink

refactor: update navigation handling in AppVersionList and remove LayoutMain wrapper

refactor: remove unused LayoutMain imports and components across various pages

fix: ensure user app list is set correctly in useUserAppStore

fix: update login URL format in AuthProvider

fix: adjust layout styles in EnvPage and other pages for better responsiveness

chore: update route definitions and create new routes for apps, config, domain, flowme, org, remote, token, user, and users

style: replace Button with div for delete confirmation in various components

fix: ensure correct handling of user profile image source
This commit is contained in:
2026-02-22 03:24:14 +08:00
parent f3c269dd83
commit 66ee0d7f60
44 changed files with 740 additions and 761 deletions

View File

@@ -20,9 +20,8 @@ export const AIEditorLink = (props: Props) => {
return (
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div
className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
if (!layoutUser.user) {
toast.error('请先登录');
@@ -39,7 +38,7 @@ export const AIEditorLink = (props: Props) => {
openLink(openUrl, '_blank');
}}>
<Folder className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>

View File

@@ -17,8 +17,7 @@ import { Controller, useForm } from 'react-hook-form';
import { pick } from 'es-toolkit';
import { useAppDeleteModalStore, AppDeleteModal } from '../modules/AppDeleteModal';
import { AIEditorLink } from './AIEditorLink';
import { openLink } from '@/modules/basename';
import { LayoutMain } from '@/modules/layout';
import { useNavigate } from '@tanstack/react-router';
const FormModal = () => {
const { control, handleSubmit, reset } = useForm();
@@ -130,6 +129,7 @@ export const AppVersionList = () => {
}),
);
const [isUpload, setIsUpload] = useState(false);
const navigate = useNavigate();
useEffect(() => {
// fetch app version list
if (appKey) {
@@ -170,8 +170,7 @@ export const AppVersionList = () => {
variant='ghost'
size='icon'
onClick={() => {
// navigate('/app/edit/list');
history.back();
navigate({ to: '/apps' });
}}>
<ChevronLeft className='h-4 w-4' />
</Button>
@@ -236,7 +235,7 @@ export const AppVersionList = () => {
if (isRunning) {
const origin = typeof window !== 'undefined' ? window.location.origin : '';
const link = new URL(`/test/${item.id}`, origin);
openLink(link.toString(), '_blank');
window.open(link.toString(), '_blank');
} else {
message.error('The app is not running');
}
@@ -372,7 +371,5 @@ export const AppVersionFile = () => {
};
export default () => {
return <LayoutMain>
<AppVersionList />
</LayoutMain>
return <AppVersionList />
};

View File

@@ -1,7 +0,0 @@
'use client';
import { LayoutMain } from '@/modules/layout';
export const Main = () => {
return <LayoutMain title='User Apps' />;
};

View File

@@ -34,18 +34,17 @@ import {
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { LayoutMain } from '@/modules/layout';
import { openLink } from '@/modules/basename';
import { useNavigate } from '@tanstack/react-router';
export const IconButton = (props: any) => {
return (
<button
<div
className={clsx(
'inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none',
props.className,
)}
{...props}>
{props.children}
</button>
</div>
);
};
const FormModal = () => {
@@ -276,6 +275,7 @@ export const List = () => {
useEffect(() => {
userAppStore.getList();
}, []);
const navigate = useNavigate();
return (
<div className='w-full h-full flex bg-slate-100'>
<div className='p-2 h-full bg-white flex flex-col gap-2'>
@@ -301,7 +301,7 @@ export const List = () => {
padding: '8px',
}}
onClick={() => {
openLink('/domain/', '_self');
navigate({ to: '/domain' });
}}>
<LinkIcon className='h-4 w-4' />
</IconButton>
@@ -367,68 +367,59 @@ export const List = () => {
<div className='mt-4 pt-3 border-t border-slate-100 flex gap-1 absolute bottom-0 left-0 right-0 px-4 pb-4 bg-white rounded-b-lg'>
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div
className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
userAppStore.getUserApp(item.id);
userAppStore.setFormData(item);
userAppStore.setShowEdit(true);
}}>
<Edit className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
const url = `/apps/app?appKey=${item.key}`;
openLink(url, '_self');
navigate({
to: `/apps/app?appKey=${item.key}`,
})
}}
>
<AppWindow className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
userAppStore.getUserApp(item.id);
userAppStore.setFormData(item);
userAppStore.setShowShareEdit(true);
}}>
<Share2 className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent className="whitespace-pre-wrap">{iText.share.tips}</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
appVersionStore.publishVersion({ appKey: item.key, version: item.version }, { showToast: true });
}}>
<RefreshCcw className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={() => {
if (isRunning) {
let baseUri = typeof window !== 'undefined' ? window.location.origin : '';
@@ -441,35 +432,33 @@ export const List = () => {
baseUri = new URL('https://' + item.domain).toString();
}
if (baseUri.endsWith('/')) {
openLink(baseUri, '_blank');
window.open(baseUri, '_blank');
}
console.log('baseUri', baseUri);
message.success('success');
return;
}
const link = new URL(`/${item.user}/${item.key}/`, baseUri);
openLink(link.toString(), '_blank');
window.open(link.toString(), '_blank');
} else {
message.error('应用未运行');
}
}}>
<ExternalLink className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>
<AIEditorLink pathname={item.key} />
<Tooltip>
<TooltipTrigger>
<Button
variant='ghost'
size='icon'
<div className='inline-flex items-center justify-center rounded-md p-2 transition-colors hover:bg-slate-100 disabled:opacity-50 disabled:pointer-events-none'
onClick={(e) => {
appDeleteModalStore.onClickDelete('user-app', item);
e.stopPropagation();
}}>
<Trash2 className='h-4 w-4' />
</Button>
</div>
</TooltipTrigger>
<TooltipContent></TooltipContent>
</Tooltip>

View File

@@ -43,7 +43,8 @@ export const useUserAppStore = create<UserAppStore>((set, get) => {
});
set({ loading: false });
if (res.code === 200) {
set({ list: res.data });
const list = res.data.list || [];
set({ list: list });
} else {
message.error(res.message || 'Request failed');
}