0.3.5 共享功能修复
This commit is contained in:
@@ -42,6 +42,7 @@ import { PrivateTree } from "@/components/sidebar/private-tree";
|
||||
import { buildSidebarSectionsFromTree, flattenDocumentTree } from "@/lib/sidebar-tree";
|
||||
import { useSearchPaletteStore } from "@/store/search-palette";
|
||||
import { useEditorBridgeStore } from "@/store/editor-bridge";
|
||||
import { useCurrentDocumentStore } from "@/store/current-document";
|
||||
import { FileTree } from "@/components/sidebar/file-tree";
|
||||
import { buildVisibleRows } from "@/lib/file-tree/rows";
|
||||
import type { FileTreeSelectionState } from "@/lib/file-tree/selection";
|
||||
@@ -179,16 +180,23 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
const [topPanel, setTopPanel] = useState<"starred" | "public" | "shared" | "templates" | null>(null);
|
||||
const [shareSummary, setShareSummary] = useState<{
|
||||
incoming: Array<{
|
||||
workspaceId: string;
|
||||
workspaceName: string | null;
|
||||
documentId: string;
|
||||
documentTitle: string | null;
|
||||
permission: "read" | "edit";
|
||||
includeDescendants: boolean;
|
||||
createdBy: string;
|
||||
updatedAt: string;
|
||||
}>;
|
||||
outgoing: Array<{
|
||||
workspaceId: string;
|
||||
workspaceName: string | null;
|
||||
documentId: string;
|
||||
documentTitle: string | null;
|
||||
includeDescendants: boolean;
|
||||
sharedWithCount: number;
|
||||
updatedAt: string;
|
||||
}>;
|
||||
} | null>(null);
|
||||
const [shareSummaryError, setShareSummaryError] = useState<string | null>(null);
|
||||
@@ -209,7 +217,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
allowIncludeDescendants: boolean;
|
||||
} | null>(null);
|
||||
const [groupManagerOpen, setGroupManagerOpen] = useState(false);
|
||||
const [workspaceMenuOpen, setWorkspaceMenuOpen] = useState(false);
|
||||
const [signingOut, setSigningOut] = useState(false);
|
||||
const [trashOpen, setTrashOpen] = useState(false);
|
||||
const [trashSearch, setTrashSearch] = useState("");
|
||||
@@ -230,8 +237,8 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
focusedRowId: null,
|
||||
}));
|
||||
|
||||
const workspaceMenuRef = useRef<HTMLDivElement>(null);
|
||||
const fileTreeContainerRef = useRef<HTMLDivElement>(null);
|
||||
const creatingDocumentUnderParentRef = useRef<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
setTree(() => {
|
||||
@@ -261,38 +268,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
setOpen(false);
|
||||
}, [activeId, setOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: Event) => {
|
||||
const custom = event as CustomEvent<{ docId?: string; asset?: MediaAsset }>;
|
||||
const asset = custom.detail?.asset as MediaAsset | undefined;
|
||||
if (asset?.id) {
|
||||
if (asset.asset_type === "mindmap") {
|
||||
setMindmapAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
} else if (asset.asset_type === "luckysheet") {
|
||||
setTableAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
} else {
|
||||
setMediaAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
}
|
||||
}
|
||||
void sidebarQuery.refetch();
|
||||
};
|
||||
window.addEventListener(ASSETS_CHANGED_EVENT, handler);
|
||||
window.addEventListener(DOCUMENTS_CHANGED_EVENT, handler);
|
||||
return () => {
|
||||
window.removeEventListener(ASSETS_CHANGED_EVENT, handler);
|
||||
window.removeEventListener(DOCUMENTS_CHANGED_EVENT, handler);
|
||||
};
|
||||
}, [sidebarQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
const onSaved = () => void sidebarQuery.refetch();
|
||||
const onDeleted = () => void sidebarQuery.refetch();
|
||||
@@ -309,27 +284,22 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
}, [sidebarQuery]);
|
||||
|
||||
const refreshShareSummary = useCallback(async () => {
|
||||
const workspaceId = sidebarData.activeWorkspaceId;
|
||||
if (!workspaceId) {
|
||||
setShareSummary(null);
|
||||
setShareSummaryError(null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await convex.query(api.documentShares.listShareRootsByWorkspace, { workspaceId });
|
||||
const resp = await convex.query(api.documentShares.listMyShareRoots, {});
|
||||
setShareSummary(resp as any);
|
||||
setShareSummaryError(null);
|
||||
} catch (e: any) {
|
||||
const msg = e?.message ?? "加载共享摘要失败";
|
||||
if (String(msg).includes("Could not find public function for 'documentShares:listShareRootsByWorkspace'")) {
|
||||
setShareSummaryError("共享功能后端未部署/未更新:请在 `wolai-frontend` 目录执行 `npx convex dev --env-file .env.local` 或 `npx convex deploy --env-file .env.local`。");
|
||||
if (String(msg).includes("Could not find public function for 'documentShares:listMyShareRoots'")) {
|
||||
setShareSummaryError(
|
||||
"共享功能后端未部署/未更新:请在 `wolai-frontend` 目录执行 `npx convex dev --env-file .env.local` 或 `npx convex deploy --env-file .env.local`。",
|
||||
);
|
||||
} else {
|
||||
setShareSummaryError(msg);
|
||||
}
|
||||
setShareSummary(null);
|
||||
}
|
||||
}, [convex, sidebarData.activeWorkspaceId]);
|
||||
}, [convex]);
|
||||
|
||||
useEffect(() => {
|
||||
void refreshShareSummary();
|
||||
@@ -374,6 +344,70 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
void refreshGroupPublicSummary();
|
||||
}, [refreshGroupPublicSummary]);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (event: Event) => {
|
||||
const custom = event as CustomEvent<{ docId?: string; asset?: MediaAsset }>;
|
||||
const asset = custom.detail?.asset as MediaAsset | undefined;
|
||||
if (asset?.id) {
|
||||
if (asset.asset_type === "mindmap") {
|
||||
setMindmapAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
} else if (asset.asset_type === "luckysheet") {
|
||||
setTableAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
} else {
|
||||
setMediaAssets((prev) => {
|
||||
if (prev.find((item) => item.id === asset.id)) return prev;
|
||||
return [asset, ...prev];
|
||||
});
|
||||
}
|
||||
}
|
||||
void sidebarQuery.refetch();
|
||||
// 同步刷新共享/公共摘要,避免跨页面操作后出现“幽灵共享条目”(点开 404 / 无标题)。
|
||||
void refreshShareSummary();
|
||||
void refreshGroupPublicSummary();
|
||||
};
|
||||
window.addEventListener(ASSETS_CHANGED_EVENT, handler);
|
||||
window.addEventListener(DOCUMENTS_CHANGED_EVENT, handler);
|
||||
return () => {
|
||||
window.removeEventListener(ASSETS_CHANGED_EVENT, handler);
|
||||
window.removeEventListener(DOCUMENTS_CHANGED_EVENT, handler);
|
||||
};
|
||||
}, [sidebarQuery, refreshShareSummary, refreshGroupPublicSummary]);
|
||||
|
||||
useEffect(() => {
|
||||
// 说明:shareSummary/groupPublicSummary 目前走的是一次性 query + 本地 state,
|
||||
// 为了让 A 侧删除/清空回收站后,B 侧能自动消失(而不是保留 404 幽灵项),这里做轻量轮询刷新。
|
||||
if (topPanel !== "shared" && topPanel !== "public") {
|
||||
return;
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
if (topPanel === "shared") void refreshShareSummary();
|
||||
if (topPanel === "public") void refreshGroupPublicSummary();
|
||||
};
|
||||
|
||||
refresh();
|
||||
const intervalId = window.setInterval(refresh, 2500);
|
||||
|
||||
const onFocus = () => {
|
||||
if (document.visibilityState && document.visibilityState !== "visible") return;
|
||||
refresh();
|
||||
};
|
||||
|
||||
window.addEventListener("focus", onFocus);
|
||||
document.addEventListener("visibilitychange", onFocus);
|
||||
return () => {
|
||||
window.clearInterval(intervalId);
|
||||
window.removeEventListener("focus", onFocus);
|
||||
document.removeEventListener("visibilitychange", onFocus);
|
||||
};
|
||||
}, [topPanel, refreshShareSummary, refreshGroupPublicSummary]);
|
||||
|
||||
const sections = useMemo(() => buildSidebarSectionsFromTree(tree), [tree]);
|
||||
const starredNodes = useMemo(() => sections.find((section) => section.id === "starred")?.nodes ?? [], [sections]);
|
||||
const publicNodes = useMemo(() => sections.find((section) => section.id === "public")?.nodes ?? [], [sections]);
|
||||
@@ -395,19 +429,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
return map;
|
||||
}, [tree]);
|
||||
|
||||
const outgoingSharedRootNodes = useMemo(() => {
|
||||
const ids = new Set((shareSummary?.outgoing ?? []).map((o) => o.documentId));
|
||||
const nodes: DocumentNode[] = [];
|
||||
for (const id of ids) {
|
||||
const node = nodeById.get(id);
|
||||
if (node) nodes.push(node);
|
||||
}
|
||||
// 说明:同一个页面被共享给多个用户时,只展示一份。
|
||||
const uniq = new Map<string, DocumentNode>();
|
||||
nodes.forEach((n) => uniq.set(n.id, n));
|
||||
return Array.from(uniq.values());
|
||||
}, [nodeById, shareSummary?.outgoing]);
|
||||
|
||||
const publicGroupNodesByGroupId = useMemo(() => {
|
||||
const map = new Map<string, DocumentNode[]>();
|
||||
for (const g of groupPublicSummary) {
|
||||
@@ -698,6 +719,8 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
target.searchParams.set("fileName", asset.file_name ?? `未命名.${officeFileType}`);
|
||||
target.searchParams.set("fileType", officeFileType);
|
||||
target.searchParams.set("assetId", asset.id);
|
||||
target.searchParams.set("documentId", asset.document_id);
|
||||
target.searchParams.set("mode", "edit");
|
||||
window.open(target.toString(), "_blank", "noopener,noreferrer");
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
@@ -978,7 +1001,17 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
await copyText(path, "存储路径已复制");
|
||||
}, []);
|
||||
|
||||
const handleDownloadAsset = useCallback(async (asset: MediaAsset) => {
|
||||
const handleDownloadAsset = useCallback(async (asset: MediaAsset) => {
|
||||
const current = useCurrentDocumentStore.getState();
|
||||
if (
|
||||
current.disableDownload &&
|
||||
current.documentId &&
|
||||
asset.document_id &&
|
||||
String(asset.document_id) === String(current.documentId)
|
||||
) {
|
||||
window.alert("该页面已禁止下载");
|
||||
return;
|
||||
}
|
||||
if (asset.asset_type === "mindmap") {
|
||||
const resp = await fetch(`/api/mindmap/${asset.document_id}/${asset.id}`);
|
||||
if (!resp.ok) {
|
||||
@@ -1284,6 +1317,12 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
|
||||
const handleCreate = useCallback(
|
||||
async (parentId: string | null) => {
|
||||
const creatingKey = parentId ?? "__root__";
|
||||
if (creatingDocumentUnderParentRef.current.has(creatingKey)) {
|
||||
return;
|
||||
}
|
||||
creatingDocumentUnderParentRef.current.add(creatingKey);
|
||||
try {
|
||||
const response = await fetch("/api/documents/create", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -1306,7 +1345,18 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
children: [],
|
||||
};
|
||||
|
||||
setTree((prev) => insertNode(prev, parentId, Number.MAX_SAFE_INTEGER, nextNode));
|
||||
setTree((prev) => {
|
||||
// 防止同一节点被插入多次(会导致重复 key / 列表出现“同一个页面两条记录”)
|
||||
const exists = (nodes: DocumentNode[]): boolean => {
|
||||
for (const node of nodes) {
|
||||
if (node.id === nextNode.id) return true;
|
||||
if (node.children.length > 0 && exists(node.children)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (exists(prev)) return prev;
|
||||
return insertNode(prev, parentId, Number.MAX_SAFE_INTEGER, nextNode);
|
||||
});
|
||||
setExpanded((prev) => {
|
||||
const next = new Set(prev);
|
||||
if (parentId) {
|
||||
@@ -1320,6 +1370,9 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
|
||||
await refreshTree();
|
||||
router.push(`/documents/${nextNode.id}`);
|
||||
} finally {
|
||||
creatingDocumentUnderParentRef.current.delete(creatingKey);
|
||||
}
|
||||
},
|
||||
[refreshTree, router],
|
||||
);
|
||||
@@ -1847,23 +1900,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
[confirmTrashAction, refreshTree, sidebarQuery],
|
||||
);
|
||||
|
||||
const handleWorkspaceSwitch = useCallback(
|
||||
async (workspaceId: string) => {
|
||||
if (workspaceId === sidebarData.activeWorkspaceId) {
|
||||
setWorkspaceMenuOpen(false);
|
||||
return;
|
||||
}
|
||||
await fetch("/api/workspaces/switch", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ workspaceId }),
|
||||
});
|
||||
setWorkspaceMenuOpen(false);
|
||||
await sidebarQuery.refetch();
|
||||
},
|
||||
[sidebarData.activeWorkspaceId, sidebarQuery],
|
||||
);
|
||||
|
||||
const handleSignOut = useCallback(async () => {
|
||||
if (signingOut) {
|
||||
return;
|
||||
@@ -1874,7 +1910,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
setSigningOut(true);
|
||||
try {
|
||||
await signOut();
|
||||
setWorkspaceMenuOpen(false);
|
||||
router.replace("/auth");
|
||||
router.refresh();
|
||||
} catch (error: any) {
|
||||
@@ -1941,22 +1976,6 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
return () => window.removeEventListener("click", closeMenu);
|
||||
}, [contextMenu]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspaceMenuOpen) {
|
||||
return;
|
||||
}
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
workspaceMenuRef.current &&
|
||||
!workspaceMenuRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setWorkspaceMenuOpen(false);
|
||||
}
|
||||
};
|
||||
window.addEventListener("click", handleClickOutside);
|
||||
return () => window.removeEventListener("click", handleClickOutside);
|
||||
}, [workspaceMenuOpen]);
|
||||
|
||||
const sidebarBody = (
|
||||
<div className="flex h-full min-w-0 flex-col">
|
||||
<div className="border-b border-[#f1f1f1] p-3">
|
||||
@@ -1966,51 +1985,30 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
<div className="text-base font-semibold text-gray-900">{activeWorkspace?.name ?? "我的空间"}</div>
|
||||
<div className="text-xs text-gray-500">{activeWorkspace?.type === "team" ? "团队空间" : "个人空间"}</div>
|
||||
</div>
|
||||
<div className="relative" ref={workspaceMenuRef}>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-md border border-[#e1e1e1] px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
setWorkspaceMenuOpen((prev) => !prev);
|
||||
}}
|
||||
>
|
||||
切换
|
||||
</button>
|
||||
{workspaceMenuOpen && (
|
||||
<div className="absolute right-0 z-20 mt-2 w-56 rounded-md border border-[#eaeaea] bg-white shadow-lg">
|
||||
{sidebarData.workspaces.map((workspace) => (
|
||||
<button
|
||||
type="button"
|
||||
key={workspace.id}
|
||||
className={cn(
|
||||
"flex w-full items-center justify-between px-3 py-2 text-left text-sm hover:bg-gray-50",
|
||||
workspace.id === activeWorkspace?.id && "bg-[#f5f7fb]",
|
||||
)}
|
||||
onClick={() => void handleWorkspaceSwitch(workspace.id)}
|
||||
>
|
||||
<span>{workspace.name}</span>
|
||||
{workspace.id === activeWorkspace?.id ? (
|
||||
<span className="text-xs text-[#2563eb]">当前</span>
|
||||
) : (
|
||||
<span className="text-xs text-gray-400">{workspace.memberCount} 人</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
<div className="border-t border-[#f1f1f1] p-1">
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center gap-2 rounded-md px-3 py-2 text-left text-sm text-red-600 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
onClick={() => void handleSignOut()}
|
||||
disabled={signingOut}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
<span>{signingOut ? "正在退出..." : "退出登录"}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-md border border-[#e1e1e1] px-2 py-1 text-xs text-gray-400"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
window.alert("工作空间切换功能暂时停用(正在修复中)。");
|
||||
}}
|
||||
>
|
||||
切换(暂停)
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-gray-400">
|
||||
提示:当前工作空间切换暂时停用;共享/群组相关内容会在「共享页面」与「成员」里跨工作空间展示。
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-2 rounded-md px-2 py-1 text-xs text-red-600 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
onClick={() => void handleSignOut()}
|
||||
disabled={signingOut}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
<span>{signingOut ? "正在退出..." : "退出登录"}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2067,6 +2065,70 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
};
|
||||
|
||||
if (topPanel === "shared") {
|
||||
const groupByWorkspace = (
|
||||
rows: Array<{
|
||||
workspaceId: string;
|
||||
workspaceName: string | null;
|
||||
documentId: string;
|
||||
documentTitle: string | null;
|
||||
includeDescendants: boolean;
|
||||
permission?: "read" | "edit";
|
||||
sharedWithCount?: number;
|
||||
}>,
|
||||
) => {
|
||||
const map = new Map<string, { workspaceName: string | null; rows: typeof rows }>();
|
||||
for (const r of rows) {
|
||||
const existing = map.get(r.workspaceId);
|
||||
if (!existing) {
|
||||
map.set(r.workspaceId, { workspaceName: r.workspaceName ?? null, rows: [r] });
|
||||
} else {
|
||||
existing.rows.push(r);
|
||||
}
|
||||
}
|
||||
return Array.from(map.entries()).map(([workspaceId, v]) => ({
|
||||
workspaceId,
|
||||
workspaceName: v.workspaceName,
|
||||
rows: v.rows,
|
||||
}));
|
||||
};
|
||||
|
||||
const renderShareRows = (rows: Array<any>) => {
|
||||
if (!rows || rows.length === 0) {
|
||||
return <div className="px-2 py-2 text-xs text-gray-400">暂无内容</div>;
|
||||
}
|
||||
const groups = groupByWorkspace(rows);
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{groups.map((g) => (
|
||||
<div key={g.workspaceId}>
|
||||
<div className="px-2 pb-1 text-xs font-medium text-gray-500">
|
||||
{g.workspaceName ?? g.workspaceId}
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{g.rows.map((r) => (
|
||||
<Link
|
||||
key={`${r.workspaceId}:${r.documentId}`}
|
||||
href={`/documents/${r.documentId}`}
|
||||
className="block truncate rounded-md px-2 py-1 text-sm text-gray-600 hover:bg-[#f5f7fb] hover:text-[#2563eb]"
|
||||
>
|
||||
{r.documentTitle || "无标题"}
|
||||
{typeof r.permission === "string" ? (
|
||||
<span className="ml-2 text-xs text-gray-400">
|
||||
{r.permission === "edit" ? "可编辑" : "只读"}
|
||||
</span>
|
||||
) : null}
|
||||
{typeof r.sharedWithCount === "number" ? (
|
||||
<span className="ml-2 text-xs text-gray-400">{r.sharedWithCount} 人</span>
|
||||
) : null}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{shareSummaryError ? (
|
||||
@@ -2077,14 +2139,14 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
<div className="px-2 pb-1 text-xs font-medium text-gray-500">
|
||||
共享给我的({shareSummary?.incoming?.length ?? 0})
|
||||
</div>
|
||||
{renderList(sharedNodes)}
|
||||
{renderShareRows(shareSummary?.incoming ?? [])}
|
||||
</div>
|
||||
|
||||
<div className="border-t border-[#f1f1f1] pt-2">
|
||||
<div className="px-2 pb-1 text-xs font-medium text-gray-500">
|
||||
我共享出去的({shareSummary?.outgoing?.length ?? 0})
|
||||
</div>
|
||||
{renderList(outgoingSharedRootNodes)}
|
||||
{renderShareRows(shareSummary?.outgoing ?? [])}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -2334,13 +2396,11 @@ function SidebarContent({ initialData, sidebarQuery }: SidebarContentProps) {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{sidebarData.activeWorkspaceId ? (
|
||||
<GroupManagerDialog
|
||||
open={groupManagerOpen}
|
||||
onOpenChange={setGroupManagerOpen}
|
||||
workspaceId={sidebarData.activeWorkspaceId}
|
||||
/>
|
||||
) : null}
|
||||
<GroupManagerDialog
|
||||
open={groupManagerOpen}
|
||||
onOpenChange={setGroupManagerOpen}
|
||||
workspaceId={sidebarData.activeWorkspaceId || ""}
|
||||
/>
|
||||
<MoveEmbedPickerDialog
|
||||
open={moveEmbedOpen}
|
||||
onOpenChange={setMoveEmbedOpen}
|
||||
|
||||
Reference in New Issue
Block a user