Embed workflow UI and isolate workspace assets
This commit is contained in:
@@ -138,6 +138,20 @@ function resolveStoredProfile(): UserProfile {
|
||||
return { name: '管理员', avatarSeed, avatarStyle: pickDicebearStyle(avatarSeed) };
|
||||
}
|
||||
}
|
||||
|
||||
function profileFromUsername(username: string, current?: UserProfile): UserProfile {
|
||||
const name = username.trim();
|
||||
const avatarSeed = current?.avatarSeed?.trim() || createRandomAvatarSeed();
|
||||
const avatarStyle = current?.avatarStyle?.trim() || pickDicebearStyle(avatarSeed);
|
||||
return {
|
||||
name: name || current?.name || '用户',
|
||||
avatarSeed,
|
||||
avatarStyle: DICEBEAR_STYLES.includes(avatarStyle as DicebearStyle)
|
||||
? avatarStyle
|
||||
: pickDicebearStyle(avatarSeed),
|
||||
};
|
||||
}
|
||||
|
||||
function UserProfileModal({
|
||||
open,
|
||||
profile,
|
||||
@@ -560,6 +574,35 @@ function AppShell() {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [location.pathname, userAuthed]);
|
||||
useEffect(() => {
|
||||
if (
|
||||
!userAuthed
|
||||
|| !location.pathname.startsWith('/user/')
|
||||
|| ['/user/login', '/user/register'].includes(location.pathname)
|
||||
) return;
|
||||
let cancelled = false;
|
||||
const syncUserProfile = async () => {
|
||||
try {
|
||||
const response = await userApi.me();
|
||||
if (cancelled) return;
|
||||
const user = (response as any)?.user || (response as any)?.data || {};
|
||||
const username = typeof user.username === 'string' ? user.username.trim() : '';
|
||||
if (!username) return;
|
||||
setUserProfile((current) => {
|
||||
if ((current.name || '').trim() === username) return current;
|
||||
const next = profileFromUsername(username, current);
|
||||
localStorage.setItem(USER_PROFILE_STORAGE_KEY, JSON.stringify(next));
|
||||
return next;
|
||||
});
|
||||
} catch {
|
||||
// Keep the local profile if the user profile endpoint is temporarily unavailable.
|
||||
}
|
||||
};
|
||||
void syncUserProfile();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [location.pathname, userAuthed]);
|
||||
useEffect(() => {
|
||||
const handler = (e: MouseEvent) => {
|
||||
if (userMenuRef.current && !userMenuRef.current.contains(e.target as Node)) {
|
||||
|
||||
@@ -425,7 +425,9 @@ export default function Workspace() {
|
||||
</button>
|
||||
)}
|
||||
<div style={detailMetaStyle}>
|
||||
<div><span>用户</span><strong>{selected.userId ?? '管理员/系统'}</strong></div>
|
||||
{audience !== 'user' && (
|
||||
<div><span>用户</span><strong>{selected.userId ?? '管理员/系统'}</strong></div>
|
||||
)}
|
||||
<div><span>模型</span><strong>{selected.model || '未记录'}</strong></div>
|
||||
<div><span>大小</span><strong>{formatBytes(selected.sizeBytes)}</strong></div>
|
||||
<div><span>文件</span><strong>{selected.hasLocalFile ? '本地归档' : '远程引用'}</strong></div>
|
||||
|
||||
Reference in New Issue
Block a user