@principal-ai/subsystems-react 0.55.0 → 0.55.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/graphify/index.d.ts +2 -0
- package/dist/graphify/index.d.ts.map +1 -1
- package/dist/graphify/index.js +1 -0
- package/dist/graphify/index.js.map +1 -1
- package/dist/graphify/symbolFocus.d.ts +49 -0
- package/dist/graphify/symbolFocus.d.ts.map +1 -0
- package/dist/graphify/symbolFocus.js +139 -0
- package/dist/graphify/symbolFocus.js.map +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/pierre/PierreTrailCodeView.d.ts +1 -1
- package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -1
- package/dist/stories/Canvases/Aggregate/aggregateViewFixture.d.ts.map +1 -0
- package/dist/stories/Canvases/Aggregate/aggregateViewFixture.js.map +1 -0
- package/dist/stories/Canvases/Subsystem/fixtures.d.ts.map +1 -0
- package/dist/stories/Canvases/Subsystem/fixtures.js.map +1 -0
- package/dist/subsystem/ComponentDeclaration.d.ts +1 -1
- package/dist/subsystem/ComponentDeclaration.d.ts.map +1 -1
- package/dist/subsystem/ComponentDeclaration.js +1 -1
- package/dist/subsystem/ComponentDeclaration.js.map +1 -1
- package/dist/subsystem/ConstructsCatalog.d.ts +1 -1
- package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts +36 -2
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +250 -35
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/SymbolFocusedView.d.ts +30 -0
- package/dist/subsystem/SymbolFocusedView.d.ts.map +1 -0
- package/dist/subsystem/SymbolFocusedView.js +24 -0
- package/dist/subsystem/SymbolFocusedView.js.map +1 -0
- package/dist/subsystem/SymbolInspectionCard.d.ts +1 -1
- package/dist/subsystem/SymbolInspectionCard.d.ts.map +1 -1
- package/dist/subsystem/SymbolInspectionCard.js +1 -1
- package/dist/subsystem/SymbolInspectionCard.js.map +1 -1
- package/dist/subsystem/TrailsPanel.d.ts +16 -1
- package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
- package/dist/subsystem/TrailsPanel.js +71 -9
- package/dist/subsystem/TrailsPanel.js.map +1 -1
- package/dist/subsystem/graphChrome.d.ts +13 -0
- package/dist/subsystem/graphChrome.d.ts.map +1 -1
- package/dist/subsystem/graphChrome.js +19 -1
- package/dist/subsystem/graphChrome.js.map +1 -1
- package/dist/subsystem/model.d.ts +40 -4
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +38 -7
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/{declarationRef.d.ts → sourceSpan.d.ts} +1 -1
- package/dist/subsystem/sourceSpan.d.ts.map +1 -0
- package/dist/subsystem/{declarationRef.js → sourceSpan.js} +1 -1
- package/dist/subsystem/sourceSpan.js.map +1 -0
- package/package.json +2 -2
- package/src/graphify/index.ts +6 -0
- package/src/graphify/symbolFocus.test.ts +163 -0
- package/src/graphify/symbolFocus.ts +190 -0
- package/src/index.ts +9 -2
- package/src/pierre/PierreTrailCodeView.tsx +1 -1
- package/src/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/AggregateFrameGraph.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4CardGrow.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Component.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Container.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4NodeGallery.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4ToComponentDrill.stories.tsx +1 -1
- package/src/stories/{Subsystem/C4Graph → Canvases/C4}/C4Transition.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/AnimatedProgression.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Appearance.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Basics.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Captures.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Constructs.stories.tsx +2 -2
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/CustomEntities.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Deprecated.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/DetailPanel.stories.tsx +2 -2
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Diagnostics.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/EdgeViews.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/FrameworkStereotype.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/GraphTitle.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Issues.stories.tsx +1 -1
- package/src/stories/Canvases/Subsystem/LayoutDirection.stories.tsx +122 -0
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ModuleBadges.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ModulePathNesting.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Modules.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/NodeAnatomy.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Packages.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Processes.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Proposed.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/ProposedTrails.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Reorder.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Scenarios.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Spotlights.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/StoreValueType.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/TrailAutoplay.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/Trails.stories.tsx +78 -2
- package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/WorkspacePackageFrames.stories.tsx +1 -1
- package/src/stories/Canvases/SymbolFocusedView/SymbolFocusedView.stories.tsx +163 -0
- package/src/stories/{Subsystem → Components}/AgentsPanel.stories.tsx +1 -1
- package/src/stories/{Subsystem/ComponentDeclarationAudit.stories.tsx → Components/ComponentDeclaration/Audit.stories.tsx} +4 -4
- package/src/stories/{Subsystem/ComponentDeclarationSymbols.stories.tsx → Components/ComponentDeclaration/Symbols.stories.tsx} +5 -5
- package/src/stories/{Subsystem → Components}/ConstructsCatalog.stories.tsx +2 -2
- package/src/stories/{Subsystem/Sidebar → Components}/GraphSidebar.stories.tsx +4 -4
- package/src/stories/{Subsystem/IssueIcons.stories.tsx → Components/IssueList.stories.tsx} +1 -1
- package/src/stories/{Subsystem/StoreValueTypeDeclaration.stories.tsx → Components/StoreValueType.stories.tsx} +1 -1
- package/src/subsystem/ComponentDeclaration.tsx +2 -2
- package/src/subsystem/ConstructsCatalog.tsx +1 -1
- package/src/subsystem/SubsystemComponentGraph.tsx +334 -28
- package/src/subsystem/SymbolFocusedView.tsx +80 -0
- package/src/subsystem/SymbolInspectionCard.tsx +2 -2
- package/src/subsystem/TrailsPanel.tsx +114 -5
- package/src/subsystem/graphChrome.tsx +22 -1
- package/src/subsystem/layoutDirection.test.ts +26 -0
- package/src/subsystem/model.test.ts +17 -0
- package/src/subsystem/model.ts +70 -10
- package/src/subsystem/{declarationRef.test.ts → sourceSpan.test.ts} +1 -1
- package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.d.ts.map +0 -1
- package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js.map +0 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +0 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +0 -1
- package/dist/subsystem/declarationRef.d.ts.map +0 -1
- package/dist/subsystem/declarationRef.js.map +0 -1
- package/src/stories/Subsystem/EgoGraph/EgoGraph.stories.tsx +0 -351
- /package/dist/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.d.ts +0 -0
- /package/dist/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.js +0 -0
- /package/dist/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.d.ts +0 -0
- /package/dist/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.js +0 -0
- /package/src/graphify/__fixtures__/{ego-samples.json → symbol-focused-samples.json} +0 -0
- /package/src/stories/{Subsystem/AggregateGraph → Canvases/Aggregate}/aggregateViewFixture.ts +0 -0
- /package/src/stories/{Subsystem/ComponentGraph → Canvases/Subsystem}/fixtures.ts +0 -0
- /package/src/subsystem/{declarationRef.ts → sourceSpan.ts} +0 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { ReactNode } from 'react';
|
|
16
16
|
import { type SubsystemComponent } from './model';
|
|
17
|
-
import type { SubsystemOpenFileOptions } from './
|
|
17
|
+
import type { SubsystemOpenFileOptions } from './sourceSpan';
|
|
18
18
|
import type { ComponentVerificationState } from './ComponentDeclaration';
|
|
19
19
|
import type { DeclarationSymbolRef, SymbolInspection } from './symbolRefs';
|
|
20
20
|
import { type SubsystemDiagnostic } from './DiagnosticToggle';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConstructsCatalog.d.ts","sourceRoot":"","sources":["../../src/subsystem/ConstructsCatalog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"ConstructsCatalog.d.ts","sourceRoot":"","sources":["../../src/subsystem/ConstructsCatalog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAKzF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,uBAAuB,CAAC,EAAE,SAAS,CAAC;IACpC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,wBAAwB,KAAK,SAAS,CAAC;IAChF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,qBAAqB,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAC1D,gFAAgF;IAChF,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,oBAAoB,CAAC;KAC3B,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,gBAAgB,GAAG,IAAI,CAAC;CAClE;AAyHD,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,QAAQ,EACR,KAAK,EACL,WAAW,EACX,WAAW,EACX,eAAe,EAAE,mBAAmB,EACpC,uBAAuB,EACvB,UAAU,EACV,YAAY,EACZ,uBAAuB,EACvB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,eAAe,GAChB,EAAE,sBAAsB,+BAm5BxB"}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* injection, onNodeClick) adapted to the subsystem model — read-only.
|
|
16
16
|
*/
|
|
17
17
|
import type { ReactNode } from 'react';
|
|
18
|
-
import { type SubsystemComponentEdge, type SubsystemComponent, type SubsystemEdgeView, type SubsystemGraphifyRelation, type SubsystemTrail } from './model';
|
|
19
|
-
import type { SubsystemOpenFileOptions } from './
|
|
18
|
+
import { type SubsystemComponentEdge, type SubsystemComponent, type SubsystemEdgeView, type SubsystemLayoutDirection, type SubsystemGraphifyRelation, type SubsystemTrail } from './model';
|
|
19
|
+
import type { SubsystemOpenFileOptions } from './sourceSpan';
|
|
20
20
|
import { type SubsystemAgentsPanelProps } from './AgentsPanel';
|
|
21
21
|
import { type MaintainLivePanelProps } from '../components/maintain-events/MaintainLivePanel';
|
|
22
22
|
import type { TrailSymbolQuery } from '../pierre/PierreTrailCodeView';
|
|
@@ -77,6 +77,40 @@ export interface SubsystemComponentGraphProps {
|
|
|
77
77
|
* `line` for this to have any effect. @default false
|
|
78
78
|
*/
|
|
79
79
|
orderByLine?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Flow direction of the layered layout. `horizontal` (default) runs layers
|
|
82
|
+
* left-to-right; `vertical` runs them top-to-bottom. Edge-less containment
|
|
83
|
+
* graphs keep their DOWN + grid treatment either way.
|
|
84
|
+
*
|
|
85
|
+
* Pass this to control the direction from the host; leave it unset to let
|
|
86
|
+
* the graph own it (seeded by `defaultLayoutDirection`, updated by the
|
|
87
|
+
* built-in toggle, and persisted under `persistKey`).
|
|
88
|
+
*/
|
|
89
|
+
layoutDirection?: SubsystemLayoutDirection;
|
|
90
|
+
/**
|
|
91
|
+
* Initial flow direction when uncontrolled. Ignored when `layoutDirection`
|
|
92
|
+
* is provided. @default 'horizontal'
|
|
93
|
+
*/
|
|
94
|
+
defaultLayoutDirection?: SubsystemLayoutDirection;
|
|
95
|
+
/**
|
|
96
|
+
* Fired when the built-in toggle (or a host control) requests a different
|
|
97
|
+
* direction. Hosts that pass `layoutDirection` must update it here; hosts
|
|
98
|
+
* that don't can use it to observe the change.
|
|
99
|
+
*/
|
|
100
|
+
onLayoutDirectionChange?: (direction: SubsystemLayoutDirection) => void;
|
|
101
|
+
/**
|
|
102
|
+
* Hide the built-in horizontal/vertical toggle in the canvas corner.
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
hideLayoutToggle?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Refit the camera to the new layout after a layout flip — a direction
|
|
108
|
+
* change or a trail-focus change. On by default: a vertical layout grows
|
|
109
|
+
* downward and would otherwise leave the graph half off-screen. Turn off for
|
|
110
|
+
* embeds that own their own camera.
|
|
111
|
+
* @default true
|
|
112
|
+
*/
|
|
113
|
+
refocusOnLayoutFlip?: boolean;
|
|
80
114
|
/**
|
|
81
115
|
* Deep-link target: when set, the matching trail is selected on mount
|
|
82
116
|
* — its steps expanded and its flow focused on the canvas. Hosts use this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubsystemComponentGraph.d.ts","sourceRoot":"","sources":["../../src/subsystem/SubsystemComponentGraph.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAiC,SAAS,EAAE,MAAM,OAAO,CAAC;AAkBtE,OAAO,
|
|
1
|
+
{"version":3,"file":"SubsystemComponentGraph.d.ts","sourceRoot":"","sources":["../../src/subsystem/SubsystemComponentGraph.tsx"],"names":[],"mappings":"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"}
|
|
@@ -18,9 +18,9 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
18
18
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
19
19
|
import { ReactFlow, ReactFlowProvider, useReactFlow, useViewport, applyNodeChanges, } from '@xyflow/react';
|
|
20
20
|
import { useTheme } from '@principal-ade/industry-theme';
|
|
21
|
-
import { FileText, X } from 'lucide-react';
|
|
21
|
+
import { FileText, ArrowDown, ArrowRight, Unlink, X } from 'lucide-react';
|
|
22
22
|
import { IndustryMarkdownSlide } from 'themed-markdown';
|
|
23
|
-
import { buildSubsystemGraph, deriveGraphEdges, isConstructsOnlyModel, moduleGroupNodeId, processGroupNodeId, isTrailMechanism, edgeColor, MECHANISM_DESCRIPTIONS, subsystemGraphLayoutKey, trailStepGraphEdgeId, } from './model';
|
|
23
|
+
import { buildSubsystemGraph, deriveGraphEdges, isConstructsOnlyModel, moduleGroupNodeId, processGroupNodeId, isTrailMechanism, edgeColor, MECHANISM_DESCRIPTIONS, subsystemGraphLayoutKey, trailStepGraphEdgeId, unroutedEdgeIds, } from './model';
|
|
24
24
|
import { ConstructsCatalog } from './ConstructsCatalog';
|
|
25
25
|
import { SubsystemAgentsPanel, } from './AgentsPanel';
|
|
26
26
|
import { MaintainLivePanel, } from '../components/maintain-events/MaintainLivePanel';
|
|
@@ -29,7 +29,7 @@ import { SubsystemDiagnosticToggle } from './DiagnosticToggle';
|
|
|
29
29
|
import { SubsystemIssueList, issueCategory, issueKindOrder, issueRung, ISSUE_KIND_ICON, ISSUE_RUNG_ORDER, } from './IssueList';
|
|
30
30
|
import { SubsystemFileTree } from './SubsystemFileTree';
|
|
31
31
|
import { GraphLayoutCover } from './GraphLayoutCover';
|
|
32
|
-
import { GRAPH_CANVAS_CLASS, GRAPH_NAV_PROPS, GraphChrome, GraphLayerStyle } from './graphChrome';
|
|
32
|
+
import { GRAPH_CANVAS_CLASS, GRAPH_NAV_PROPS, GraphChrome, GraphLayerStyle, LAYOUT_FLIP_CLASS, LAYOUT_FLIP_EDGE_MS, LAYOUT_FLIP_NODE_MS } from './graphChrome';
|
|
33
33
|
import { ComponentDeclaration } from './ComponentDeclaration';
|
|
34
34
|
import { FileDrawer, FILE_DRAWER_HEIGHT_MS } from './FileDrawer';
|
|
35
35
|
import { GraphWithSidebar } from './GraphWithSidebar';
|
|
@@ -128,7 +128,7 @@ const TrailDrawerContent = memo(function TrailDrawerContent({ render, trail, ste
|
|
|
128
128
|
onVisibleStepChange,
|
|
129
129
|
}) }));
|
|
130
130
|
});
|
|
131
|
-
function Inner({ components, trails, graphifyRelations, orderByLine, initialTrailId, onTrailSelect, onTrailStepHover, onReorderTrails, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, moduleNesting, edgeView, title, hideSidebar, trailStepMode = 'focus', autoPlayTrails = false, trailAutoPlayIntervalMs = TRAIL_PLAY_PAUSE_MS, zoomOnTrailFocus = true, trailFocusDurationMs = 300, graphTitle, showTrailTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, laneStatus, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileViewer, renderTrailViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, codeProcessKeys, hideDrawer = false, persistKey, liveEvents, agentsPanel }) {
|
|
131
|
+
function Inner({ components, trails, graphifyRelations, orderByLine, layoutDirection: layoutDirectionProp, defaultLayoutDirection = 'horizontal', onLayoutDirectionChange, hideLayoutToggle = false, refocusOnLayoutFlip = true, initialTrailId, onTrailSelect, onTrailStepHover, onReorderTrails, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showSingletonFrames = true, moduleNesting, edgeView, title, hideSidebar, trailStepMode = 'focus', autoPlayTrails = false, trailAutoPlayIntervalMs = TRAIL_PLAY_PAUSE_MS, zoomOnTrailFocus = true, trailFocusDurationMs = 300, graphTitle, showTrailTitle = false, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, diagnostic, issues, showIssues, focusIssueCategory, laneStatus, onSelectIssue, onApplyIssueFix, onHoverIssue, renderFileViewer, renderTrailViewer, onFileSelect, componentVerification, onInspectSymbol, boundaryColors, codeProcessKeys, hideDrawer = false, persistKey, liveEvents, agentsPanel }) {
|
|
132
132
|
const { theme } = useTheme();
|
|
133
133
|
const { fitView, fitBounds, screenToFlowPosition } = useReactFlow();
|
|
134
134
|
const viewport = useViewport();
|
|
@@ -142,6 +142,139 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
142
142
|
absoluteRects: new Map(),
|
|
143
143
|
});
|
|
144
144
|
const [layoutReady, setLayoutReady] = useState(false);
|
|
145
|
+
// --- Layout direction -----------------------------------------------------
|
|
146
|
+
// The graph owns direction unless the host passes `layoutDirection`. A change
|
|
147
|
+
// is sequenced so old edge routes never cut across the new layout: edges fade
|
|
148
|
+
// out, ELK re-lays out while the nodes slide to their new slots, then the
|
|
149
|
+
// edges fade back in. Two values keep that honest: `requestedDirection` is
|
|
150
|
+
// what the toggle shows, `committedDirection` is what ELK last ran with.
|
|
151
|
+
const [ownDirection, setOwnDirection] = useState(() => persisted.layoutDirection ?? defaultLayoutDirection);
|
|
152
|
+
const requestedDirection = layoutDirectionProp ?? ownDirection;
|
|
153
|
+
const [committedDirection, setCommittedDirection] = useState(requestedDirection);
|
|
154
|
+
const [layoutFlipping, setLayoutFlipping] = useState(false);
|
|
155
|
+
const flipSawPendingLayoutRef = useRef(false);
|
|
156
|
+
/** Pending fade-out timer; non-null only between request and commit. */
|
|
157
|
+
const flipFadeTimerRef = useRef(null);
|
|
158
|
+
/** Set when a layout flip starts; the camera refits once layout lands. */
|
|
159
|
+
const refitAfterLayoutRef = useRef(false);
|
|
160
|
+
/** Solo layout: only this trail's components and edges are laid out. */
|
|
161
|
+
const [layoutTrailId, setLayoutTrailId] = useState(null);
|
|
162
|
+
const [committedTrailId, setCommittedTrailId] = useState(null);
|
|
163
|
+
const changeLayoutDirection = useCallback((next) => {
|
|
164
|
+
if (next === requestedDirection)
|
|
165
|
+
return;
|
|
166
|
+
if (layoutDirectionProp == null)
|
|
167
|
+
setOwnDirection(next);
|
|
168
|
+
onLayoutDirectionChange?.(next);
|
|
169
|
+
}, [layoutDirectionProp, onLayoutDirectionChange, requestedDirection]);
|
|
170
|
+
const toggleLayoutFocus = useCallback((trailId) => {
|
|
171
|
+
setLayoutTrailId((cur) => (cur === trailId ? null : trailId));
|
|
172
|
+
}, []);
|
|
173
|
+
// A focused trail that disappears (model reload) releases the solo layout
|
|
174
|
+
// instead of pinning the canvas to a slice that no longer exists.
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (layoutTrailId && !(trails ?? []).some((t) => t.id === layoutTrailId)) {
|
|
177
|
+
setLayoutTrailId(null);
|
|
178
|
+
}
|
|
179
|
+
}, [trails, layoutTrailId]);
|
|
180
|
+
const requestedLayoutKey = `${requestedDirection}|${layoutTrailId ?? ''}`;
|
|
181
|
+
const committedLayoutKey = `${committedDirection}|${committedTrailId ?? ''}`;
|
|
182
|
+
// Beat 1: request → fade the edges out, then commit the direction / focus
|
|
183
|
+
// (which re-runs ELK). Reduced-motion users get the new layout immediately.
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (requestedLayoutKey === committedLayoutKey) {
|
|
186
|
+
// A host can revert a request before the fade-out commits. Drop the
|
|
187
|
+
// pending flip instead of leaving the canvas edge-less until the safety
|
|
188
|
+
// timeout. A normal commit also lands here (request now equals
|
|
189
|
+
// committed), but by then the timer ref is already null — and the
|
|
190
|
+
// pending refit must survive that pass.
|
|
191
|
+
if (flipFadeTimerRef.current != null) {
|
|
192
|
+
clearTimeout(flipFadeTimerRef.current);
|
|
193
|
+
flipFadeTimerRef.current = null;
|
|
194
|
+
setLayoutFlipping(false);
|
|
195
|
+
refitAfterLayoutRef.current = false;
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
refitAfterLayoutRef.current = refocusOnLayoutFlip;
|
|
200
|
+
const reduceMotion = typeof window !== 'undefined' &&
|
|
201
|
+
typeof window.matchMedia === 'function' &&
|
|
202
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
203
|
+
if (reduceMotion) {
|
|
204
|
+
setCommittedDirection(requestedDirection);
|
|
205
|
+
setCommittedTrailId(layoutTrailId);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
flipSawPendingLayoutRef.current = false;
|
|
209
|
+
setLayoutFlipping(true);
|
|
210
|
+
flipFadeTimerRef.current = window.setTimeout(() => {
|
|
211
|
+
flipFadeTimerRef.current = null;
|
|
212
|
+
setCommittedDirection(requestedDirection);
|
|
213
|
+
setCommittedTrailId(layoutTrailId);
|
|
214
|
+
}, LAYOUT_FLIP_EDGE_MS);
|
|
215
|
+
return () => {
|
|
216
|
+
if (flipFadeTimerRef.current != null) {
|
|
217
|
+
clearTimeout(flipFadeTimerRef.current);
|
|
218
|
+
flipFadeTimerRef.current = null;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}, [
|
|
222
|
+
requestedLayoutKey,
|
|
223
|
+
committedLayoutKey,
|
|
224
|
+
refocusOnLayoutFlip,
|
|
225
|
+
requestedDirection,
|
|
226
|
+
layoutTrailId,
|
|
227
|
+
]);
|
|
228
|
+
// Beat 3: the committed layout has settled → the node slide is over, fade
|
|
229
|
+
// the edges back in. The ref keeps the OLD `layoutReady` (still true until
|
|
230
|
+
// the new pass 1 commits) from ending the flip before the layout swaps.
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (!layoutFlipping)
|
|
233
|
+
return;
|
|
234
|
+
if (!layoutReady) {
|
|
235
|
+
flipSawPendingLayoutRef.current = true;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (!flipSawPendingLayoutRef.current)
|
|
239
|
+
return;
|
|
240
|
+
const t = setTimeout(() => setLayoutFlipping(false), LAYOUT_FLIP_NODE_MS);
|
|
241
|
+
return () => clearTimeout(t);
|
|
242
|
+
}, [layoutFlipping, layoutReady]);
|
|
243
|
+
// Camera: a direction flip moves the whole graph, and a vertical layout grows
|
|
244
|
+
// downward, so keeping the old viewport would leave most of it off-screen.
|
|
245
|
+
// Refit once the new layout is final — for both the animated flip and the
|
|
246
|
+
// reduced-motion instant swap. The edge reveal is separate (beat 3 above).
|
|
247
|
+
// Keyed on `built` as well as `layoutReady`: whichever of the two passes
|
|
248
|
+
// lands last is the one that has the final positions.
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
if (!layoutReady || !refitAfterLayoutRef.current)
|
|
251
|
+
return;
|
|
252
|
+
refitAfterLayoutRef.current = false;
|
|
253
|
+
requestAnimationFrame(() => {
|
|
254
|
+
fitView({
|
|
255
|
+
padding: 0.1,
|
|
256
|
+
includeHiddenNodes: false,
|
|
257
|
+
minZoom: 0.05,
|
|
258
|
+
maxZoom: 2,
|
|
259
|
+
duration: LAYOUT_FLIP_NODE_MS,
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
}, [built, layoutReady, fitView]);
|
|
263
|
+
// Persist the choice so a model reopens the way it was left.
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
if (!persistKey)
|
|
266
|
+
return;
|
|
267
|
+
writeViewState(persistKey, { layoutDirection: requestedDirection });
|
|
268
|
+
}, [persistKey, requestedDirection]);
|
|
269
|
+
// Safety net: never leave the canvas edge-less if a layout pass stalls
|
|
270
|
+
// (measurement never lands, ELK hangs). The edges come back; the layout
|
|
271
|
+
// stays wherever it got to.
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
if (!layoutFlipping)
|
|
274
|
+
return;
|
|
275
|
+
const t = setTimeout(() => setLayoutFlipping(false), 5000);
|
|
276
|
+
return () => clearTimeout(t);
|
|
277
|
+
}, [layoutFlipping]);
|
|
145
278
|
const [selected, setSelected] = useState(null);
|
|
146
279
|
/** Bottom drawer: single file or trail multi-snippet mode. */
|
|
147
280
|
const [drawerTarget, setDrawerTarget] = useState(null);
|
|
@@ -248,14 +381,18 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
248
381
|
// Trails draws runtime step edges. Without visible tabs (no trails,
|
|
249
382
|
// or a sidebar-less embed) fall back to trail edges.
|
|
250
383
|
const sidebarTabsVisible = !hideSidebar && (trails?.length ?? 0) > 0;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
384
|
+
// A solo trail layout only draws that flow's steps, so the trail edge source
|
|
385
|
+
// is the only one that can render anything.
|
|
386
|
+
const resolvedEdgeView = committedTrailId
|
|
387
|
+
? 'trails'
|
|
388
|
+
: edgeView ??
|
|
389
|
+
(sidebarTabsVisible
|
|
390
|
+
? (sidebarView === 'trails' ? 'trails' : 'graphify')
|
|
391
|
+
: (trails?.length ?? 0) > 0
|
|
392
|
+
? 'trails'
|
|
393
|
+
: (graphifyRelations?.length ?? 0) > 0
|
|
394
|
+
? 'graphify'
|
|
395
|
+
: 'trails');
|
|
259
396
|
// Trail flows the user has expanded (via the title row). Closed by
|
|
260
397
|
// default so a graph with several flows doesn't dump every step list at once.
|
|
261
398
|
// Restored from the persisted view state when a `persistKey` is set.
|
|
@@ -424,7 +561,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
424
561
|
return { index: visibleStepIndex ?? drawerStepIndex, total: focusedTrail.steps.length };
|
|
425
562
|
}, [drawerStepIndex, focusedTrail, visibleStepIndex]);
|
|
426
563
|
// Refresh selected component when the components list updates (e.g. verify
|
|
427
|
-
// writes back
|
|
564
|
+
// writes back declarationSpan).
|
|
428
565
|
useEffect(() => {
|
|
429
566
|
if (!selected)
|
|
430
567
|
return;
|
|
@@ -434,14 +571,37 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
434
571
|
}, [components, selected]);
|
|
435
572
|
// Pass 1: build with estimated widths so React Flow can measure the DOM.
|
|
436
573
|
// The pane stays hidden until Pass 2 completes. Key off layout-affecting
|
|
437
|
-
// fields only —
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
574
|
+
// fields only — declarationSpan updates after verify must not re-run ELK.
|
|
575
|
+
// Solo layout: a trail focus filters the model down to that flow's endpoints
|
|
576
|
+
// (and drops graphify relations) before it reaches ELK. Built from the
|
|
577
|
+
// COMMITTED trail, not the requested one, so the swap happens behind the
|
|
578
|
+
// edge fade like every other layout flip.
|
|
579
|
+
const layoutDoc = useMemo(() => {
|
|
580
|
+
if (!committedTrailId)
|
|
581
|
+
return { components, trails };
|
|
582
|
+
const trail = (trails ?? []).find((t) => t.id === committedTrailId);
|
|
583
|
+
if (!trail)
|
|
584
|
+
return { components, trails };
|
|
585
|
+
const aliases = new Set();
|
|
586
|
+
for (const step of trail.steps) {
|
|
587
|
+
aliases.add(step.from);
|
|
588
|
+
aliases.add(step.to);
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
components: components.filter((c) => aliases.has(c.alias)),
|
|
592
|
+
trails: [trail],
|
|
593
|
+
};
|
|
594
|
+
}, [components, trails, committedTrailId]);
|
|
595
|
+
const layoutRelations = committedTrailId ? undefined : graphifyRelations;
|
|
596
|
+
const layoutKey = useMemo(() => subsystemGraphLayoutKey({
|
|
597
|
+
components: layoutDoc.components,
|
|
598
|
+
trails: layoutDoc.trails,
|
|
599
|
+
graphifyRelations: layoutRelations,
|
|
600
|
+
}), [layoutDoc, layoutRelations]);
|
|
601
|
+
const layoutDocRef = useRef(layoutDoc);
|
|
602
|
+
const layoutRelationsRef = useRef(layoutRelations);
|
|
603
|
+
layoutDocRef.current = layoutDoc;
|
|
604
|
+
layoutRelationsRef.current = layoutRelations;
|
|
445
605
|
// Track measured dimensions from React Flow's dimension changes.
|
|
446
606
|
// These arrive as { type: 'dimensions', id, dimensions } in onNodesChange.
|
|
447
607
|
// Retained across same-id layoutKey updates so Pass 2 can run without a remount.
|
|
@@ -456,17 +616,15 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
456
616
|
prevMeasuredSigRef.current = '';
|
|
457
617
|
// Bump generation so any in-flight Pass 2 from the prior layoutKey is ignored.
|
|
458
618
|
pass2GenRef.current += 1;
|
|
459
|
-
const doc =
|
|
460
|
-
components: componentsRef.current,
|
|
461
|
-
trails: trailsRef.current,
|
|
462
|
-
};
|
|
619
|
+
const doc = layoutDocRef.current;
|
|
463
620
|
void buildSubsystemGraph(doc, {
|
|
464
621
|
maxNodeWidth,
|
|
465
622
|
showEdgeLabels,
|
|
466
623
|
showSingletonFrames,
|
|
467
624
|
moduleNesting,
|
|
468
|
-
graphifyRelations:
|
|
625
|
+
graphifyRelations: layoutRelationsRef.current,
|
|
469
626
|
orderByLine,
|
|
627
|
+
layoutDirection: committedDirection,
|
|
470
628
|
codeProcessKeys,
|
|
471
629
|
})
|
|
472
630
|
.then(({ nodes, edges: e, absoluteRects }) => {
|
|
@@ -491,7 +649,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
491
649
|
setLayoutReady(true);
|
|
492
650
|
});
|
|
493
651
|
return () => { alive = false; };
|
|
494
|
-
}, [layoutKey, maxNodeWidth, showEdgeLabels, moduleNesting]);
|
|
652
|
+
}, [layoutKey, maxNodeWidth, showEdgeLabels, moduleNesting, committedDirection]);
|
|
495
653
|
// Pass 2: once every leaf node has a measured dimension, re-run ELK.
|
|
496
654
|
// Group parents are sized by ELK, not measured — exclude them or pass 2
|
|
497
655
|
// would wait forever for dimensions that never arrive.
|
|
@@ -518,7 +676,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
518
676
|
const measuredWidths = new Map(leafNodes.map((n) => [n.id, dims.get(n.id).width]));
|
|
519
677
|
const measuredHeights = new Map(leafNodes.map((n) => [n.id, dims.get(n.id).height]));
|
|
520
678
|
const gen = ++pass2GenRef.current;
|
|
521
|
-
void buildSubsystemGraph(
|
|
679
|
+
void buildSubsystemGraph(layoutDoc, { maxNodeWidth, showEdgeLabels, measuredWidths, measuredHeights, showSingletonFrames, moduleNesting, graphifyRelations: layoutRelations, orderByLine, layoutDirection: committedDirection, codeProcessKeys })
|
|
522
680
|
.then(({ nodes, edges: e, absoluteRects }) => {
|
|
523
681
|
if (gen !== pass2GenRef.current)
|
|
524
682
|
return;
|
|
@@ -532,7 +690,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
532
690
|
// Reveal Pass 1 layout rather than leaving the cover up forever.
|
|
533
691
|
setLayoutReady(true);
|
|
534
692
|
});
|
|
535
|
-
}, [built.nodes,
|
|
693
|
+
}, [built.nodes, layoutDoc, layoutRelations, orderByLine, maxNodeWidth, showEdgeLabels, moduleNesting, committedDirection]);
|
|
536
694
|
// After Pass 1 commits, try Pass 2 immediately with retained measurements.
|
|
537
695
|
// Same-id live updates often get no new React Flow `dimensions` events, so
|
|
538
696
|
// waiting only on onNodesChange leaves the cover stuck.
|
|
@@ -1144,6 +1302,8 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
1144
1302
|
}
|
|
1145
1303
|
return proposedStampedEdges.map((e) => ({ ...e, hidden: !edgeInView(e) }));
|
|
1146
1304
|
}, [proposedStampedEdges, selectedEdgeId, openedEdgeIds, focusEdgeIds, previewEdgeIds, issueFocusEdgeIds, resolvedEdgeView]);
|
|
1305
|
+
// Gated on layoutReady so the pre-reveal Pass 1 swap never flashes a count.
|
|
1306
|
+
const unroutedIds = useMemo(() => (layoutReady ? unroutedEdgeIds(dispEdges) : []), [dispEdges, layoutReady]);
|
|
1147
1307
|
const onNodesChange = useCallback((changes) => {
|
|
1148
1308
|
// Capture dimension changes (React Flow's measurement callback).
|
|
1149
1309
|
// Group parents are ELK-sized — ignore their measurements.
|
|
@@ -1164,6 +1324,10 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
1164
1324
|
}, [dispNodes, triggerPass2]);
|
|
1165
1325
|
const onEdgesChange = useCallback((_changes) => dispEdges, [dispEdges]);
|
|
1166
1326
|
useEffect(() => {
|
|
1327
|
+
// A layout flip runs its own camera refit when the new layout lands. This
|
|
1328
|
+
// mount/edit fit would otherwise fire mid-flip and fight it.
|
|
1329
|
+
if (layoutFlipping)
|
|
1330
|
+
return;
|
|
1167
1331
|
const t = setTimeout(() => {
|
|
1168
1332
|
fitView({ padding: 0.1, includeHiddenNodes: false, minZoom: 0.05, maxZoom: 2, duration: 200 });
|
|
1169
1333
|
}, 200);
|
|
@@ -2065,7 +2229,14 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2065
2229
|
}, children: _jsx(FileText, { size: 14 }) }))] })] })), description && descriptionVisible && (_jsx("div", { style: { fontSize: theme.fontSizes[0], lineHeight: 1.5 }, children: _jsx(IndustryMarkdownSlide, { content: description, slideIdPrefix: "subsystem-desc", slideIndex: 0, isVisible: true, theme: theme, disableScroll: true, disableBasePadding: true, enableKeyboardScrolling: false, autoFocusOnVisible: false }) })), sidebarAfterDescription] }));
|
|
2066
2230
|
// Lower panel: the Issues/Agents diagnostics stack, or the Files/Trails
|
|
2067
2231
|
// stack with the trail flow list / repo file tree.
|
|
2068
|
-
const sidebarBody = issuesActive ? (diagnosticsTab === 'agents' && agentsPanel ? (_jsx(SubsystemAgentsPanel, { ...agentsPanel })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, laneStatus: laneStatus, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))) : sidebarView === 'trails' && trails && trails.length > 0 ? (_jsx(TrailsPanel, { trails: trails, expandedTrails: expandedTrails, focusedTrailId: focusedTrailId, focusedStepIndex: focusedStepIndex, hoveredTrailStep: hoveredTrailStep, onToggleCollapsed: toggleTrailCollapsed, onFocusFlow:
|
|
2232
|
+
const sidebarBody = issuesActive ? (diagnosticsTab === 'agents' && agentsPanel ? (_jsx(SubsystemAgentsPanel, { ...agentsPanel })) : (_jsx(SubsystemIssueList, { issues: issues ?? [], focusCategory: focusIssueCategory, laneStatus: laneStatus, onSelectIssue: focusIssueTarget, onDeselectIssue: unfocusIssueTarget, onApplyFix: onApplyIssueFix, onHoverIssue: onHoverIssue, onExpandedCategoriesChange: handleExpandedCategoriesChange }))) : sidebarView === 'trails' && trails && trails.length > 0 ? (_jsx(TrailsPanel, { trails: trails, expandedTrails: expandedTrails, focusedTrailId: focusedTrailId, focusedStepIndex: focusedStepIndex, hoveredTrailStep: hoveredTrailStep, onToggleCollapsed: toggleTrailCollapsed, onFocusFlow: (tl) => {
|
|
2233
|
+
// While a solo layout is on, following the selection keeps the canvas
|
|
2234
|
+
// and the highlighted flow in agreement instead of leaving the graph
|
|
2235
|
+
// pinned to a flow the user just navigated away from.
|
|
2236
|
+
if (layoutTrailId != null)
|
|
2237
|
+
setLayoutTrailId(tl.id);
|
|
2238
|
+
focusTrailEdges(tl);
|
|
2239
|
+
}, onClearFocus: clearTrailFocus, onFocusStep: focusTrailStep, onHoverStep: (tl, i) => {
|
|
2069
2240
|
setHoveredTrailStep({ trailId: tl.id, stepIndex: i });
|
|
2070
2241
|
onTrailStepHover?.({ trailId: tl.id, stepIndex: i });
|
|
2071
2242
|
}, onHoverFlow: (tl) => {
|
|
@@ -2074,7 +2245,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2074
2245
|
}, onLeaveStep: () => {
|
|
2075
2246
|
setHoveredTrailStep(null);
|
|
2076
2247
|
onTrailStepHover?.(null);
|
|
2077
|
-
}, onReorder: onReorderTrails, proposedAliases: proposedAliases })) : treeFilePaths.length > 0 ? (_jsx(_Fragment, { children: repoGroups.groups.map((group, i) => {
|
|
2248
|
+
}, onReorder: onReorderTrails, proposedAliases: proposedAliases, layoutFocusedTrailId: layoutTrailId, onFocusLayout: toggleLayoutFocus })) : treeFilePaths.length > 0 ? (_jsx(_Fragment, { children: repoGroups.groups.map((group, i) => {
|
|
2078
2249
|
const groupKey = group.repoKey ?? '__no-repo__';
|
|
2079
2250
|
const collapsed = collapsedRepos.has(groupKey);
|
|
2080
2251
|
return (_jsxs("div", { style: {
|
|
@@ -2087,7 +2258,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2087
2258
|
}) })) : null;
|
|
2088
2259
|
return (_jsx(GraphWithSidebar, { hidden: !sidebarVisible, bodyHidden: !sidebarBodyVisible, stretchHeader: showDesc, header: sidebarHeader, tabs: sidebarTabs, activeTab: activeSidebarTab, onTabChange: (id) => issuesActive
|
|
2089
2260
|
? setDiagnosticsTab(id)
|
|
2090
|
-
: changeSidebarView(id), sidebarBody: sidebarBody, tabListLabel: issuesActive ? 'Diagnostics view' : 'Sidebar view', defaultWidth: persisted.sidebarWidth ?? 450, minWidth: 240, maxWidth: sidebarMaxWidth, persistKey: persistKey, onResizeEnd: () => requestAnimationFrame(() => fitView()), children: _jsxs("div", { style: { flex: 1, position: 'relative', display: 'flex', flexDirection: 'column', minHeight: 0 }, children: [_jsxs("div", { style: {
|
|
2261
|
+
: changeSidebarView(id), sidebarBody: sidebarBody, tabListLabel: issuesActive ? 'Diagnostics view' : 'Sidebar view', defaultWidth: persisted.sidebarWidth ?? 450, minWidth: 240, maxWidth: sidebarMaxWidth, persistKey: persistKey, onResizeEnd: () => requestAnimationFrame(() => fitView()), children: _jsxs("div", { style: { flex: 1, position: 'relative', display: 'flex', flexDirection: 'column', minHeight: 0 }, children: [_jsxs("div", { className: layoutFlipping ? LAYOUT_FLIP_CLASS : undefined, style: {
|
|
2091
2262
|
position: 'relative',
|
|
2092
2263
|
flex: collapseCanvas ? 0 : 1,
|
|
2093
2264
|
minHeight: 0,
|
|
@@ -2101,6 +2272,8 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2101
2272
|
overflow: 'hidden',
|
|
2102
2273
|
pointerEvents: 'none',
|
|
2103
2274
|
zIndex: 5,
|
|
2275
|
+
opacity: layoutFlipping ? 0 : 1,
|
|
2276
|
+
transition: `opacity ${LAYOUT_FLIP_EDGE_MS}ms ease`,
|
|
2104
2277
|
}, children: edgeLabels.map((lbl) => {
|
|
2105
2278
|
const mechanism = lbl.mechanism;
|
|
2106
2279
|
const isGraphify = lbl.provenance === 'graphify';
|
|
@@ -2200,13 +2373,55 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2200
2373
|
lineHeight: 1,
|
|
2201
2374
|
}, children: lbl.stepIssue.count }))] }));
|
|
2202
2375
|
})()] }, lbl.id));
|
|
2203
|
-
}) })), _jsx(GraphLayerStyle, {}), _jsx(ReactFlow, { nodes: dispNodes, edges: dispEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, className: GRAPH_CANVAS_CLASS,
|
|
2376
|
+
}) })), _jsx(GraphLayerStyle, {}), _jsx(ReactFlow, { nodes: dispNodes, edges: dispEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, className: GRAPH_CANVAS_CLASS,
|
|
2377
|
+
// The key above remounts ReactFlow when the node/edge SET changes (a
|
|
2378
|
+
// trail-focus layout, a filtered model). A remount otherwise resets the
|
|
2379
|
+
// viewport to identity — a visible jump to scale 1 before the post-flip
|
|
2380
|
+
// refit. Seed the new instance with the viewport the old one had.
|
|
2381
|
+
defaultViewport: viewport, ...GRAPH_NAV_PROPS, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onEdgeClick: onEdgeClick, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, proOptions: { hideAttribution: true }, onPaneClick: onPaneClick, style: {
|
|
2204
2382
|
width: '100%',
|
|
2205
2383
|
height: '100%',
|
|
2206
2384
|
flex: 1,
|
|
2207
2385
|
minHeight: 0,
|
|
2208
2386
|
background: theme.colors.background,
|
|
2209
|
-
}, children: _jsx(GraphChrome, {}) }, `${baseNodesKey}-${baseEdgesKey}`),
|
|
2387
|
+
}, children: _jsx(GraphChrome, {}) }, `${baseNodesKey}-${baseEdgesKey}`), !hideLayoutToggle && (_jsxs("button", { type: "button", onClick: () => changeLayoutDirection(requestedDirection === 'horizontal' ? 'vertical' : 'horizontal'), disabled: layoutFlipping, title: requestedDirection === 'horizontal'
|
|
2388
|
+
? 'Switch to a vertical layout (top-to-bottom)'
|
|
2389
|
+
: 'Switch to a horizontal layout (left-to-right)', "aria-label": requestedDirection === 'horizontal'
|
|
2390
|
+
? 'Switch to vertical layout'
|
|
2391
|
+
: 'Switch to horizontal layout', style: {
|
|
2392
|
+
position: 'absolute',
|
|
2393
|
+
top: 10,
|
|
2394
|
+
right: 10,
|
|
2395
|
+
zIndex: 6,
|
|
2396
|
+
display: 'inline-flex',
|
|
2397
|
+
alignItems: 'center',
|
|
2398
|
+
gap: 5,
|
|
2399
|
+
padding: '4px 9px',
|
|
2400
|
+
border: `1px solid ${theme.colors.border}`,
|
|
2401
|
+
borderRadius: 6,
|
|
2402
|
+
background: theme.colors.backgroundSecondary ?? theme.colors.background,
|
|
2403
|
+
color: theme.colors.textSecondary,
|
|
2404
|
+
fontFamily: theme.fonts.monospace,
|
|
2405
|
+
fontSize: theme.fontSizes[0],
|
|
2406
|
+
cursor: layoutFlipping ? 'default' : 'pointer',
|
|
2407
|
+
opacity: layoutFlipping ? 0.55 : 1,
|
|
2408
|
+
}, children: [requestedDirection === 'horizontal' ? (_jsx(ArrowDown, { size: 13, "aria-hidden": "true" })) : (_jsx(ArrowRight, { size: 13, "aria-hidden": "true" })), requestedDirection === 'horizontal' ? 'Vertical' : 'Horizontal'] })), unroutedIds.length > 0 && (_jsxs("div", { role: "status", title: `Edges with no routed path (not drawn):\n${unroutedIds.join('\n')}`, style: {
|
|
2409
|
+
position: 'absolute',
|
|
2410
|
+
top: 10,
|
|
2411
|
+
left: 10,
|
|
2412
|
+
zIndex: 6,
|
|
2413
|
+
display: 'inline-flex',
|
|
2414
|
+
alignItems: 'center',
|
|
2415
|
+
gap: 6,
|
|
2416
|
+
padding: '4px 10px',
|
|
2417
|
+
fontSize: theme.fontSizes[0],
|
|
2418
|
+
fontFamily: theme.fonts.body,
|
|
2419
|
+
color: theme.colors.text,
|
|
2420
|
+
background: theme.colors.backgroundSecondary ?? theme.colors.background,
|
|
2421
|
+
border: `1px solid ${theme.colors.warning ?? '#d4a017'}`,
|
|
2422
|
+
borderRadius: 6,
|
|
2423
|
+
boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
|
|
2424
|
+
}, children: [_jsx(Unlink, { size: 13, color: theme.colors.warning ?? '#d4a017', "aria-hidden": true }), unroutedIds.length, " ", unroutedIds.length === 1 ? 'edge' : 'edges', " not drawn"] })), (graphTitle || overlayTrailTitle || overlayTrailStep) && (_jsxs("div", { style: {
|
|
2210
2425
|
position: 'absolute',
|
|
2211
2426
|
top: 10,
|
|
2212
2427
|
left: '50%',
|
|
@@ -2338,7 +2553,7 @@ function Inner({ components, trails, graphifyRelations, orderByLine, initialTrai
|
|
|
2338
2553
|
fontFamily: theme.fonts.monospace,
|
|
2339
2554
|
fontSize: theme.fontSizes[0],
|
|
2340
2555
|
color: theme.colors.textMuted ?? theme.colors.textSecondary,
|
|
2341
|
-
}, children: fileOverlay.file }), _jsx(FileOverlayCloseButton, { onClose: closeFileOverlay })] }), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto' }, children: _jsx(FileDrawerContent, { render: renderDrawerContent, file: fileOverlay.file, startLine: fileOverlay.startLine, endLine: fileOverlay.endLine, fullFile: true }) })] })), _jsx(GraphLayoutCover, { revealed: layoutReady }), canvasOverlay, liveEvents ? _jsx(MaintainLivePanel, { ...liveEvents }) : null] }) }));
|
|
2556
|
+
}, children: fileOverlay.file }), _jsx(FileOverlayCloseButton, { onClose: closeFileOverlay })] }), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto' }, children: _jsx(FileDrawerContent, { render: renderDrawerContent, file: fileOverlay.file, startLine: fileOverlay.startLine, endLine: fileOverlay.endLine, fullFile: true }) })] })), _jsx(GraphLayoutCover, { revealed: layoutReady || layoutFlipping }), canvasOverlay, liveEvents ? _jsx(MaintainLivePanel, { ...liveEvents }) : null] }) }));
|
|
2342
2557
|
}
|
|
2343
2558
|
/** Sidebar header for one repo's tree: owner avatar + repo name + file count.
|
|
2344
2559
|
* Clicking toggles the tree's visibility. */
|