fix(canvas): right-click menu actions actually work + clearer labels (#1441)
Operator reported "non of the right click functionalites working other than the open in new tab". Root cause: the previous handler only mutated urlFoldedSet, which had no visible effect when the clicked group was folded by the depth default (same class of bug toggleFold had before #1439). The menu items also had confusing labels ("Fold to level N" stepped GLOBAL depth, not subtree-relative). Rewrite to use the same compose-state pattern toggleFold uses: - "Show only this group" — switch to depth=all + fold every OTHER group. Only the clicked group's subtree expands; sibling groups stay collapsed. - "Hide this group" — switch to depth=default + add clicked group to urlFoldedSet. Group renders as a folded bubble; its subtree hidden. - "Expand subtree" — switch to depth=all + remove this group and all its descendant groups from urlFoldedSet. Fully unfolded subtree. - "Open in new tab" — unchanged (was working since #1435). Dropped the misleading "Fold to level N" item (was just stepDepth(-1)). The depth chip ◀▶ at the top-right is the canonical global depth control. Co-authored-by: e3mrah <1234567+e3mrah@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c80d43c6d8
commit
0fe0cacc15
@ -379,16 +379,16 @@ export function FlowPage({
|
||||
const flowActions = useMemo<FlowOrganicAction[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'fold-subtree',
|
||||
label: 'Fold subtree',
|
||||
id: 'show-only-this',
|
||||
label: 'Show only this group',
|
||||
},
|
||||
{
|
||||
id: 'fold-to-level',
|
||||
label: 'Fold to level N',
|
||||
id: 'hide-this',
|
||||
label: 'Hide this group',
|
||||
},
|
||||
{
|
||||
id: 'expand-all-under',
|
||||
label: 'Expand all under here',
|
||||
label: 'Expand subtree',
|
||||
},
|
||||
{
|
||||
id: 'open-new-tab',
|
||||
@ -401,46 +401,70 @@ export function FlowPage({
|
||||
const handleNodeAction = useCallback(
|
||||
(nodeId: string, actionId: string) => {
|
||||
switch (actionId) {
|
||||
case 'fold-subtree': {
|
||||
if (adapter.groupIds.has(nodeId)) {
|
||||
const next = new Set(urlFoldedSet)
|
||||
next.add(nodeId)
|
||||
setSearchPatch({
|
||||
folded: next.size > 0 ? [...next].join(',') : undefined,
|
||||
})
|
||||
case 'show-only-this': {
|
||||
// "Show only this group" — unfold the clicked group and fold
|
||||
// every OTHER group on the canvas. Same composed-state pattern
|
||||
// as toggleFold's unfold branch: switch to depth=all so the
|
||||
// group itself stays addressable, then put every OTHER group
|
||||
// into the explicit folded set. The operator gets exactly one
|
||||
// expanded subtree with all sibling groups collapsed —
|
||||
// matching the "expand only the respective parent" UX the
|
||||
// operator asked for.
|
||||
if (!adapter.groupIds.has(nodeId)) return
|
||||
const otherGroups = new Set<string>()
|
||||
for (const gid of adapter.groupIds) {
|
||||
if (gid !== nodeId) otherGroups.add(gid)
|
||||
}
|
||||
const arr = [...otherGroups].filter(Boolean)
|
||||
setSearchPatch({
|
||||
depth: 'all',
|
||||
folded: arr.length > 0 ? arr.join(',') : undefined,
|
||||
})
|
||||
return
|
||||
}
|
||||
case 'fold-to-level': {
|
||||
// Folds to one level deeper than the clicked node's own depth.
|
||||
// Best-effort: step the global chip up by one if there's room.
|
||||
stepDepth(-1)
|
||||
case 'hide-this': {
|
||||
// "Hide this group" — collapse the clicked group regardless
|
||||
// of current depth. Setting depth=2 puts other groups at the
|
||||
// default elide state; adding the clicked group to the URL
|
||||
// fold set keeps it visible as a folded bubble (its subtree
|
||||
// hidden). Without depth=2 the FE's depth=all overrides would
|
||||
// keep the rest of the canvas in fully-expanded mode.
|
||||
if (!adapter.groupIds.has(nodeId)) return
|
||||
const next = new Set(urlFoldedSet)
|
||||
next.add(nodeId)
|
||||
const arr = [...next].filter(Boolean)
|
||||
setSearchPatch({
|
||||
depth: undefined,
|
||||
folded: arr.length > 0 ? arr.join(',') : undefined,
|
||||
})
|
||||
return
|
||||
}
|
||||
case 'expand-all-under': {
|
||||
if (adapter.groupIds.has(nodeId)) {
|
||||
const next = new Set(urlFoldedSet)
|
||||
next.delete(nodeId)
|
||||
// Also remove any descendants of nodeId that were manually
|
||||
// folded — best-effort using the live job graph.
|
||||
const byId = new Map(adapter.jobs.map((j) => [j.id, j]))
|
||||
const stack = [nodeId]
|
||||
const seen = new Set<string>()
|
||||
while (stack.length > 0) {
|
||||
const id = stack.pop()!
|
||||
if (seen.has(id)) continue
|
||||
seen.add(id)
|
||||
const j = byId.get(id)
|
||||
if (!j) continue
|
||||
for (const c of j.childIds ?? []) {
|
||||
next.delete(c)
|
||||
stack.push(c)
|
||||
}
|
||||
// "Expand subtree" — fully unfold this group and any nested
|
||||
// groups beneath it. Switch to depth=all + remove this group
|
||||
// and all its descendant groups from the URL fold set.
|
||||
if (!adapter.groupIds.has(nodeId)) return
|
||||
const next = new Set(urlFoldedSet)
|
||||
next.delete(nodeId)
|
||||
const byId = new Map(adapter.jobs.map((j) => [j.id, j]))
|
||||
const stack = [nodeId]
|
||||
const seen = new Set<string>()
|
||||
while (stack.length > 0) {
|
||||
const id = stack.pop()!
|
||||
if (seen.has(id)) continue
|
||||
seen.add(id)
|
||||
const j = byId.get(id)
|
||||
if (!j) continue
|
||||
for (const c of j.childIds ?? []) {
|
||||
next.delete(c)
|
||||
stack.push(c)
|
||||
}
|
||||
setSearchPatch({
|
||||
folded: next.size > 0 ? [...next].join(',') : undefined,
|
||||
})
|
||||
}
|
||||
const arr = [...next].filter(Boolean)
|
||||
setSearchPatch({
|
||||
depth: 'all',
|
||||
folded: arr.length > 0 ? arr.join(',') : undefined,
|
||||
})
|
||||
return
|
||||
}
|
||||
case 'open-new-tab': {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user