feat(web): space roles, upload queue with pipelined frames, background resume and faster sending

This commit is contained in:
justme committed 2026-10-16 19:42:33 +08:00
1 parent 96c4335cb5
commit a574583943
39 files changed
+1515 -194

No files matched your search

+7 -2
View File
@@ -15,6 +15,8 @@ import { Icon, type IconName } from '@/ui/Icon';
import { SpaceHeader, SpaceRail } from './SpaceRail';
import { MobileDrawer } from './MobileDrawer';
import { MobileTopBar } from './MobileTopBar';
import { useAccount } from '@/store/account';
import { permissionsOf } from '@/lib/roles';
import { ThreadSidebar } from './ThreadSidebar';
import { ChatPane } from './ChatPane';
import { FileExplorer } from './FileExplorer';
@@ -82,6 +84,9 @@ export function Workspace({ onCreateChannel }: { onCreateChannel: () => void })
const activeFolderId = activeFolders.some((folder) => folder.id === folderId) ? folderId : undefined;
const enabled = Boolean(activeThreadId && channel?.canUpload);
const owner = channel?.role === 'owner';
const roles = useWorkspace((s) => s.roles);
const self = useAccount((s) => s.username);
const perms = permissionsOf(roles, self ?? undefined, owner);
const files = useWorkspace(useShallow((s) => s.order.filter((id) => {
const item = s.byId[id]; return item?.kind === 'file' && !item.metadataHidden && item.threadId === activeThreadId
&& (item.folderId ?? undefined) === activeFolderId && matchesFilter(item, filter);
@@ -126,7 +131,7 @@ export function Workspace({ onCreateChannel }: { onCreateChannel: () => void })
const channelId = channel?.id;
useEffect(() => { setDrawerOpen(false); }, [channelId]);
const rail = <SpaceRail id={channel?.id} onCreate={onCreateChannel} onJoin={() => setScanOpen(true)} />;
const threadSidebar = <ThreadSidebar threads={threads} groups={groups} selectedThreadId={activeThreadId} enabled={Boolean(channel?.canManageStructure)} owner={channel?.role === 'owner'} onHistory={setChannelHistory}
const threadSidebar = <ThreadSidebar threads={threads} groups={groups} selectedThreadId={activeThreadId} enabled={Boolean(channel?.canManageStructure) || perms.has('structure.manage')} canCreate={owner} owner={owner} onHistory={setChannelHistory}
onSelectThread={(id) => { selectThread(id); setDrawerOpen(false); setMobileView('chat'); }} onCreateThread={createThread} onRenameThread={renameThread}
onCreateGroup={createGroup} onRenameGroup={renameGroup} onDeleteGroup={deleteGroup} onGroupThread={groupThread} />;
const navigation = <><SpaceHeader />{threadSidebar}{desktop ? <Notepad /> : null}</>;
@@ -143,7 +148,7 @@ export function Workspace({ onCreateChannel }: { onCreateChannel: () => void })
onDownloadItems={downloadItems} onDeleteItems={deleteFiles} onMoveItems={async (ids, target) => { if (activeThreadId) { await moveItems(ids, activeThreadId, target); setChecked(new Set()); setSelectedId(undefined); } }} />
{restricted.length ? <div className={styles.pendingCatalog}><span>等待同步文件目录</span>{restricted.map((id) => <Button variant="ghost" key={id} onClick={() => setPreviewId(id)}>查看受限文件</Button>)}</div> : null}
</>;
const members = <MembersPane owner={owner} refreshKey={memberRevision} onInvite={() => setInviteOpen(true)} />;
const members = <MembersPane owner={owner} canRemove={perms.has('members.remove')} refreshKey={memberRevision} onInvite={() => setInviteOpen(true)} />;
function goMobile(view: 'chat' | 'files' | 'members') { setMobileView(view); setDrawerOpen(false); }
const moreRows: { icon: IconName; label: string; run: () => void }[] = [
{ icon: 'settings', label: '空间设置', run: () => setSettingsOpen(true) },