fix: multi owner

This commit is contained in:
tao.chen
2026-08-12 18:58:18 +08:00
parent 495018de34
commit 8abe505d17
3 changed files with 40 additions and 26 deletions
@@ -178,25 +178,29 @@ export function ScriptExplorer({
</div> </div>
) : ( ) : (
<> <>
{memberScriptGroups.map((group) => ( {memberScriptGroups.map((group) => {
<WorkspaceTreeGroup const ownerKey = group.user?.user_id ?? "anon";
key={group.user?.user_id ?? "anon"} return (
title={`${group.user?.display_name}`} <WorkspaceTreeGroup
scripts={group.scripts} key={ownerKey}
directories={group.directories} groupKey={`__group__${ownerKey}`}
selectedId={selectedId} title={`${group.user?.display_name}`}
onSelect={onSelect} scripts={group.scripts}
onContextMenu={ directories={group.directories}
group.user?.user_id === user?.user_id selectedId={selectedId}
? onContextMenu onSelect={onSelect}
: undefined onContextMenu={
} group.user?.user_id === user?.user_id
readOnly={group.user?.user_id !== user?.user_id} ? onContextMenu
expandedPaths={expandedPaths} : undefined
onToggle={onToggle} }
loadingChildrenPaths={loadingChildrenPaths} readOnly={group.user?.user_id !== user?.user_id}
/> expandedPaths={expandedPaths}
))} onToggle={onToggle}
loadingChildrenPaths={loadingChildrenPaths}
/>
);
})}
{filteredScripts.length === 0 && ( {filteredScripts.length === 0 && (
<div className="tree-empty"> <div className="tree-empty">
<span className="tree-empty__icon"> <span className="tree-empty__icon">
@@ -1,4 +1,4 @@
import { type MouseEvent as ReactMouseEvent } from "react"; import { type MouseEvent as ReactMouseEvent, useEffect } from "react";
import Icon from "../../components/common/Icon"; import Icon from "../../components/common/Icon";
import type { import type {
@@ -23,12 +23,14 @@ type WorkspaceTreeProps = {
target: WorkspaceTreeTarget, target: WorkspaceTreeTarget,
) => void; ) => void;
readOnly?: boolean; readOnly?: boolean;
// 唯一标识此 group(通常 `__group__<owner_user_id>`),让多个 owner 的 group 各自独立展开。
groupKey: string;
expandedPaths: Set<string>; expandedPaths: Set<string>;
onToggle: (path: string) => void; onToggle: (path: string) => void;
loadingChildrenPaths: Set<string>; loadingChildrenPaths: Set<string>;
}; };
type WorkspaceTreeItemsProps = Omit<WorkspaceTreeProps, "title" | "readOnly"> & { type WorkspaceTreeItemsProps = Omit<WorkspaceTreeProps, "title" | "readOnly" | "groupKey"> & {
path: string; path: string;
depth: number; depth: number;
}; };
@@ -65,19 +67,27 @@ export function WorkspaceTreeGroup({
onSelect, onSelect,
onContextMenu, onContextMenu,
readOnly = false, readOnly = false,
groupKey,
expandedPaths, expandedPaths,
onToggle, onToggle,
loadingChildrenPaths, loadingChildrenPaths,
}: WorkspaceTreeProps) { }: WorkspaceTreeProps) {
const open = expandedPaths.has(""); const open = expandedPaths.has(groupKey);
const childrenLoading = loadingChildrenPaths.has(""); // 首次挂载自动展开(保留原本 useState(true) 的默认展开行为)。
// toggleExpanded 内识别 `__group__` 前缀,不会触发 loadChildren。
useEffect(() => {
if (!expandedPaths.has(groupKey)) {
void onToggle(groupKey);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [groupKey]);
return ( return (
<div className="tree-group"> <div className="tree-group">
<button <button
className={`tree-group__title${open ? " is-open" : ""}`} className={`tree-group__title${open ? " is-open" : ""}`}
type="button" type="button"
aria-expanded={open} aria-expanded={open}
onClick={() => onToggle("")} onClick={() => onToggle(groupKey)}
onContextMenu={onContextMenu onContextMenu={onContextMenu
? (event) => onContextMenu(event, { kind: "root", path: "" }) ? (event) => onContextMenu(event, { kind: "root", path: "" })
: undefined} : undefined}
@@ -86,7 +96,6 @@ export function WorkspaceTreeGroup({
<Icon name="folder" size={17} /> <Icon name="folder" size={17} />
<span>{title}</span> <span>{title}</span>
<em>{scripts.length}</em> <em>{scripts.length}</em>
{childrenLoading && <span className="loading-spinner" />}
</button> </button>
{open && ( {open && (
<div className="tree-group__items"> <div className="tree-group__items">
@@ -293,7 +293,8 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
next.delete(path); next.delete(path);
} else { } else {
next.add(path); next.add(path);
if (!state.loadedChildPaths.has(path)) { // group key (`__group__<owner_id>`) 不是 workspace 路径,不调 loadChildren
if (!path.startsWith("__group__") && !state.loadedChildPaths.has(path)) {
void get().loadChildren(path); void get().loadChildren(path);
} }
} }