diff --git a/graph-ui/src/galaxy/GalaxyPanel.layers.test.tsx b/graph-ui/src/galaxy/GalaxyPanel.layers.test.tsx index 25432074b..2addac6a2 100644 --- a/graph-ui/src/galaxy/GalaxyPanel.layers.test.tsx +++ b/graph-ui/src/galaxy/GalaxyPanel.layers.test.tsx @@ -70,6 +70,10 @@ it('K8: shows loaded nodes and edges while a layer loads, and "−" cancels back await settle(() => expect(status()?.textContent).toBe('3 nodes · 2 edges')); await act(async () => { release(); }); await settle(() => expect(status()?.textContent).toBe('3 nodes · 2 edges')); + // A cancelled layer is a step back, not a new step: Forward retries it, and the history holds no duplicate. + expect(seam().history.entries).toEqual(['All graph', 'n1 · 1 layer', 'n1 · 2 layers']); + expect(seam().history.index).toBe(1); + expect(host.querySelector('button[aria-label="Forward"]')?.title).toBe('Forward to n1 · 2 layers (Alt+Right)'); }); it('K8: a layer past the render limit stops there, says it is partial and cannot be expanded further', async () => { diff --git a/graph-ui/src/galaxy/GalaxyPanel.tsx b/graph-ui/src/galaxy/GalaxyPanel.tsx index 34190a6a6..2e5d55d4c 100644 --- a/graph-ui/src/galaxy/GalaxyPanel.tsx +++ b/graph-ui/src/galaxy/GalaxyPanel.tsx @@ -1946,10 +1946,11 @@ export default function GalaxyPanel(props: GalaxyPanelProps): JSX.Element { setTrailStep(0); setBackgroundCleared(false); setNote(''); - // A symbol scope reports its root itself once it is complete (see `notifiedScopedSymbol`). - if (entry.scope) selectOnComplete.current = entry.scope.kind === 'symbol' ? undefined : scopeIdentity(entry.scope); + // A symbol scope reports its root itself once it is complete (see `notifiedScopedSymbol`); the same root stays selected. + const sameRoot = entry.scope && scope.scope && scopeIdentity(entry.scope) === scopeIdentity(scope.scope); + if (entry.scope && !sameRoot) selectOnComplete.current = entry.scope.kind === 'symbol' ? undefined : scopeIdentity(entry.scope); else { setHighlighted(null); props.onClearSelection?.(); } - }, [scope.restore, changeTraceTypes, project, props.onClearSelection]); + }, [scope.restore, scope.scope, changeTraceTypes, project, props.onClearSelection]); const historyBack = peekNavigation(history, -1); const historyForward = peekNavigation(history, 1); const goHistory = useCallback((step: -1 | 1) => { @@ -2029,6 +2030,17 @@ export default function GalaxyPanel(props: GalaxyPanelProps): JSX.Element { const outsideLimits = props.workspaceExpanded && data && shown && (shown.nodes.length < data.nodes.length || shown.edges.length < data.edges.length) ? galaxyToolbarText.outsideLimits(data.nodes.length - shown.nodes.length, data.edges.length - shown.edges.length) : undefined; + /* + * "−" waehrend des Ladens ist ein Abbruch (K8), und ein Abbruch ist ein + * Schritt zurueck und kein neuer: steht die vorige Ebene direkt davor im + * Verlauf, geht es dorthin, und Vor laedt die abgebrochene Ebene wieder. + */ + const cancelOrRemoveLayer = () => { + const previous = historyEntry && { ...historyEntry, depth: scope.depth - 1 }; + if (scope.loading && previous && historyBack && galaxyHistoryOptions.key(historyBack) === galaxyHistoryOptions.key(previous)) goHistory(-1); + else scope.setDepth(scope.depth - 1); + }; + /* Was die Leiste ueber das Laden der Ebenen sagt (Handtest K8). */ const partial = scope.complete ? scope.result?.partial : undefined; const scopeState = scope.validating ? 'checking' : scope.loading ? 'loading' : organicTask.loading ? 'arranging' @@ -2556,7 +2568,7 @@ export default function GalaxyPanel(props: GalaxyPanelProps): JSX.Element { */} + onClick={cancelOrRemoveLayer} aria-label="Remove graph layer">− {scope.depth} {scope.depth === 1 ? 'layer' : 'layers'}