@principal-ai/subsystems-react 0.44.4 → 0.46.0
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 +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/pierre/{PierreWalkthroughCodeView.d.ts → PierreTrailCodeView.d.ts} +11 -11
- package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -0
- package/dist/pierre/{PierreWalkthroughCodeView.js → PierreTrailCodeView.js} +36 -36
- package/dist/pierre/PierreTrailCodeView.js.map +1 -0
- package/dist/pierre/index.d.ts +2 -2
- package/dist/pierre/index.d.ts.map +1 -1
- package/dist/pierre/index.js +1 -1
- package/dist/pierre/index.js.map +1 -1
- package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.d.ts.map +1 -1
- package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js +1 -1
- package/dist/stories/Subsystem/AggregateGraph/aggregateViewFixture.js.map +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +7 -11
- package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js +10 -26
- package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
- package/dist/subsystem/C4Graph.d.ts +2 -2
- package/dist/subsystem/C4Graph.js +2 -2
- package/dist/subsystem/ConstructsCatalog.d.ts +2 -3
- package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
- package/dist/subsystem/ConstructsCatalog.js +3 -14
- package/dist/subsystem/ConstructsCatalog.js.map +1 -1
- package/dist/subsystem/DiagnosticToggle.d.ts +1 -1
- package/dist/subsystem/DiagnosticToggle.js +1 -1
- package/dist/subsystem/FileDrawer.d.ts +2 -2
- package/dist/subsystem/FileDrawer.js +2 -2
- package/dist/subsystem/IssueList.d.ts +6 -6
- package/dist/subsystem/IssueList.d.ts.map +1 -1
- package/dist/subsystem/IssueList.js +9 -9
- package/dist/subsystem/IssueList.js.map +1 -1
- package/dist/subsystem/SubsystemAggregateGraph.d.ts +3 -3
- package/dist/subsystem/SubsystemAggregateGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemAggregateGraph.js +2 -2
- package/dist/subsystem/SubsystemComponentGraph.d.ts +45 -51
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +288 -292
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/SubsystemModelTransition.d.ts +10 -10
- package/dist/subsystem/SubsystemModelTransition.d.ts.map +1 -1
- package/dist/subsystem/SubsystemModelTransition.js +42 -42
- package/dist/subsystem/SubsystemModelTransition.js.map +1 -1
- package/dist/subsystem/TrailsPanel.d.ts +55 -0
- package/dist/subsystem/TrailsPanel.d.ts.map +1 -0
- package/dist/subsystem/{WalkthroughsPanel.js → TrailsPanel.js} +51 -51
- package/dist/subsystem/TrailsPanel.js.map +1 -0
- package/dist/subsystem/declarationRef.d.ts +1 -1
- package/dist/subsystem/declarationRef.d.ts.map +1 -1
- package/dist/subsystem/model.d.ts +40 -40
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +17 -17
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts +1 -1
- package/dist/subsystem/nodes.js +1 -1
- package/dist/subsystem/toC4.d.ts +2 -2
- package/dist/subsystem/toC4.d.ts.map +1 -1
- package/dist/subsystem/toC4.js +2 -2
- package/dist/subsystem/toC4.js.map +1 -1
- package/dist/subsystem/trailBrief.d.ts +18 -0
- package/dist/subsystem/trailBrief.d.ts.map +1 -0
- package/dist/subsystem/{walkthroughBrief.js → trailBrief.js} +8 -8
- package/dist/subsystem/trailBrief.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +15 -15
- package/src/pierre/{PierreWalkthroughCodeView.tsx → PierreTrailCodeView.tsx} +56 -56
- package/src/pierre/index.ts +2 -2
- package/src/stories/Pierre/CodeView.stories.tsx +3 -3
- package/src/stories/Subsystem/AggregateGraph/AggregateFrameGraph.stories.tsx +1 -1
- package/src/stories/Subsystem/AggregateGraph/aggregateViewFixture.ts +1 -1
- package/src/stories/Subsystem/C4Graph/c4Fixture.ts +1 -1
- package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +8 -8
- package/src/stories/Subsystem/ComponentGraph/AnimatedProgression.stories.tsx +13 -13
- package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -2
- package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +5 -5
- package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +8 -8
- package/src/stories/Subsystem/ComponentGraph/CustomEntities.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +6 -6
- package/src/stories/Subsystem/ComponentGraph/EdgeViews.stories.tsx +12 -12
- package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +36 -36
- package/src/stories/Subsystem/ComponentGraph/FrameworkStereotype.stories.tsx +7 -7
- package/src/stories/Subsystem/ComponentGraph/GraphTitle.stories.tsx +4 -4
- package/src/stories/Subsystem/ComponentGraph/IssueOverlay.stories.tsx +8 -8
- package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +4 -4
- package/src/stories/Subsystem/ComponentGraph/ModuleBadges.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +5 -5
- package/src/stories/Subsystem/ComponentGraph/Packages.stories.tsx +6 -6
- package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/Proposed.stories.tsx +4 -4
- package/src/stories/Subsystem/ComponentGraph/{ProposedWalkthroughs.stories.tsx → ProposedTrails.stories.tsx} +9 -9
- package/src/stories/Subsystem/ComponentGraph/Reorder.stories.tsx +19 -19
- package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +21 -21
- package/src/stories/Subsystem/ComponentGraph/{WalkthroughAutoplay.stories.tsx → TrailAutoplay.stories.tsx} +22 -22
- package/src/stories/Subsystem/ComponentGraph/WorkspacePackageFrames.stories.tsx +3 -3
- package/src/stories/Subsystem/ComponentGraph/fixtures.ts +17 -37
- package/src/subsystem/C4Graph.tsx +2 -2
- package/src/subsystem/ConstructsCatalog.tsx +2 -16
- package/src/subsystem/DiagnosticToggle.tsx +1 -1
- package/src/subsystem/FileDrawer.tsx +2 -2
- package/src/subsystem/IssueList.focus.test.tsx +4 -4
- package/src/subsystem/IssueList.icon.test.tsx +3 -3
- package/src/subsystem/IssueList.tsx +14 -14
- package/src/subsystem/SubsystemAggregateGraph.tsx +3 -3
- package/src/subsystem/SubsystemComponentGraph.tsx +380 -393
- package/src/subsystem/SubsystemModelTransition.tsx +61 -61
- package/src/subsystem/{WalkthroughsPanel.test.tsx → TrailsPanel.test.tsx} +16 -16
- package/src/subsystem/{WalkthroughsPanel.tsx → TrailsPanel.tsx} +81 -81
- package/src/subsystem/declarationRef.ts +1 -1
- package/src/subsystem/formatDeclaration.test.ts +6 -6
- package/src/subsystem/model.test.ts +25 -25
- package/src/subsystem/model.ts +51 -51
- package/src/subsystem/nodes.tsx +1 -1
- package/src/subsystem/toC4.test.ts +1 -1
- package/src/subsystem/toC4.ts +3 -3
- package/src/subsystem/{walkthroughBrief.test.ts → trailBrief.test.ts} +10 -10
- package/src/subsystem/{walkthroughBrief.ts → trailBrief.ts} +8 -8
- package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +0 -1
- package/dist/pierre/PierreWalkthroughCodeView.js.map +0 -1
- package/dist/subsystem/WalkthroughsPanel.d.ts +0 -55
- package/dist/subsystem/WalkthroughsPanel.d.ts.map +0 -1
- package/dist/subsystem/WalkthroughsPanel.js.map +0 -1
- package/dist/subsystem/walkthroughBrief.d.ts +0 -18
- package/dist/subsystem/walkthroughBrief.d.ts.map +0 -1
- package/dist/subsystem/walkthroughBrief.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* subsystem's
|
|
2
|
+
* TrailsPanel — the sidebar's flows panel: the ordered list of a
|
|
3
|
+
* subsystem's trails, each rendered as a collapsible `TrailFlow`
|
|
4
4
|
* row. Extracted from `SubsystemComponentGraph`'s `Inner` so the panel (and the
|
|
5
5
|
* drag-to-reorder controller it hosts) is a component boundary of its own.
|
|
6
6
|
*
|
|
7
|
-
* Ordering is authored order: the list renders `
|
|
7
|
+
* Ordering is authored order: the list renders `trails` in array order.
|
|
8
8
|
* When `onReorder` is supplied, each row grows a grip in its header and dropping
|
|
9
|
-
* a row onto another emits the reordered array (see `
|
|
9
|
+
* a row onto another emits the reordered array (see `reorderTrails`); the
|
|
10
10
|
* host owns persistence.
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -17,36 +17,36 @@ import { Check, ChevronDown, Copy, GripVertical, Pause, Play } from 'lucide-reac
|
|
|
17
17
|
import {
|
|
18
18
|
PROPOSED_COLOR,
|
|
19
19
|
reorderTargetIndex,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type
|
|
20
|
+
reorderTrails,
|
|
21
|
+
trailStepGraphEdgeId,
|
|
22
|
+
type SubsystemTrail,
|
|
23
23
|
} from './model';
|
|
24
|
-
import { buildStepBrief } from './
|
|
24
|
+
import { buildStepBrief } from './trailBrief';
|
|
25
25
|
|
|
26
|
-
/** Pause (ms) between steps when a
|
|
27
|
-
export const
|
|
26
|
+
/** Pause (ms) between steps when a trail autoplays. */
|
|
27
|
+
export const TRAIL_PLAY_PAUSE_MS = 2500;
|
|
28
28
|
|
|
29
29
|
/** How long a step's copy button flashes its "copied" checkmark (ms). */
|
|
30
30
|
export const STEP_COPY_FEEDBACK_MS = 2000;
|
|
31
31
|
|
|
32
|
-
/** Square size (px) of a
|
|
33
|
-
const
|
|
32
|
+
/** Square size (px) of a trail header's Play/Collapse control. */
|
|
33
|
+
const TRAIL_CONTROL_SIZE = 34;
|
|
34
34
|
|
|
35
35
|
/** Drag state handed to a row's grip while a reorder is in flight. */
|
|
36
|
-
interface
|
|
36
|
+
interface TrailReorderHandle {
|
|
37
37
|
index: number;
|
|
38
38
|
isDragging: boolean;
|
|
39
39
|
onDragStart: (index: number, e: ReactDragEvent) => void;
|
|
40
40
|
onDragEnd: () => void;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** One collapsible
|
|
43
|
+
/** One collapsible trail in the sidebar's flows panel. Clicking the
|
|
44
44
|
* title: closed → open + select; open with a step selected → select the whole
|
|
45
45
|
* flow (deselect the step, stay open); open with the whole flow selected →
|
|
46
46
|
* close + clear focus. The right-aligned close button collapses without
|
|
47
47
|
* selecting. A step row focuses that step's edge. */
|
|
48
|
-
function
|
|
49
|
-
|
|
48
|
+
function TrailFlow({
|
|
49
|
+
trail,
|
|
50
50
|
collapsed,
|
|
51
51
|
active,
|
|
52
52
|
onToggleCollapsed,
|
|
@@ -61,20 +61,20 @@ function WalkthroughFlow({
|
|
|
61
61
|
isHoverSuppressed,
|
|
62
62
|
proposedAliases,
|
|
63
63
|
}: {
|
|
64
|
-
|
|
64
|
+
trail: SubsystemTrail;
|
|
65
65
|
collapsed: boolean;
|
|
66
66
|
/** `{ stepIndex: null }` = whole flow focused; `{ stepIndex }` = one step. */
|
|
67
67
|
active: { stepIndex: number | null } | null;
|
|
68
68
|
onToggleCollapsed: (tlId: string) => void;
|
|
69
|
-
onFocusFlow: (tl:
|
|
69
|
+
onFocusFlow: (tl: SubsystemTrail) => void;
|
|
70
70
|
onClearFocus: () => void;
|
|
71
|
-
onFocusStep: (tl:
|
|
72
|
-
onHoverStep: (tl:
|
|
71
|
+
onFocusStep: (tl: SubsystemTrail, stepIndex: number) => void;
|
|
72
|
+
onHoverStep: (tl: SubsystemTrail, stepIndex: number) => void;
|
|
73
73
|
/** Preview the whole flow on the canvas (used while the row is collapsed). */
|
|
74
|
-
onHoverFlow: (tl:
|
|
74
|
+
onHoverFlow: (tl: SubsystemTrail) => void;
|
|
75
75
|
onLeaveStep: () => void;
|
|
76
76
|
/** When set, renders a grip in the header that starts a reorder drag. */
|
|
77
|
-
reorder?:
|
|
77
|
+
reorder?: TrailReorderHandle;
|
|
78
78
|
/** True while any row is mid-drag; used to reset stale hover styling. */
|
|
79
79
|
dragActive?: boolean;
|
|
80
80
|
/** True just after a drop; ignores the browser's synthetic hover until the pointer moves. */
|
|
@@ -93,7 +93,7 @@ function WalkthroughFlow({
|
|
|
93
93
|
// A step is "proposed" when either endpoint is a proposed component.
|
|
94
94
|
const stepProposed = (from: string, to: string) =>
|
|
95
95
|
proposedAliases != null && (proposedAliases.has(from) || proposedAliases.has(to));
|
|
96
|
-
const touchesProposed =
|
|
96
|
+
const touchesProposed = trail.steps.some((s) => stepProposed(s.from, s.to));
|
|
97
97
|
const [headerHover, setHeaderHover] = useState(false);
|
|
98
98
|
const [collapseHover, setCollapseHover] = useState(false);
|
|
99
99
|
const [playHover, setPlayHover] = useState(false);
|
|
@@ -125,7 +125,7 @@ function WalkthroughFlow({
|
|
|
125
125
|
|
|
126
126
|
const copyStep = useCallback(
|
|
127
127
|
(stepIndex: number) => {
|
|
128
|
-
const brief = buildStepBrief(
|
|
128
|
+
const brief = buildStepBrief(trail, stepIndex);
|
|
129
129
|
if (brief.length === 0) return;
|
|
130
130
|
const clipboard = navigator.clipboard;
|
|
131
131
|
if (!clipboard) return;
|
|
@@ -145,7 +145,7 @@ function WalkthroughFlow({
|
|
|
145
145
|
// best-effort — show nothing when the clipboard is unavailable
|
|
146
146
|
});
|
|
147
147
|
},
|
|
148
|
-
[
|
|
148
|
+
[trail],
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
useEffect(
|
|
@@ -167,9 +167,9 @@ function WalkthroughFlow({
|
|
|
167
167
|
}, [dragActive]);
|
|
168
168
|
|
|
169
169
|
const startPlaying = useCallback(() => {
|
|
170
|
-
if (collapsed) onToggleCollapsed(
|
|
171
|
-
if (active === null || active.stepIndex !== null) onFocusFlow(
|
|
172
|
-
const stepCount =
|
|
170
|
+
if (collapsed) onToggleCollapsed(trail.id);
|
|
171
|
+
if (active === null || active.stepIndex !== null) onFocusFlow(trail);
|
|
172
|
+
const stepCount = trail.steps.length;
|
|
173
173
|
if (stepCount === 0) return;
|
|
174
174
|
setPlaying(true);
|
|
175
175
|
let i = 0;
|
|
@@ -179,12 +179,12 @@ function WalkthroughFlow({
|
|
|
179
179
|
setPlaying(false);
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
182
|
-
onFocusStep(
|
|
182
|
+
onFocusStep(trail, i);
|
|
183
183
|
i += 1;
|
|
184
|
-
playTimerRef.current = window.setTimeout(tick,
|
|
184
|
+
playTimerRef.current = window.setTimeout(tick, TRAIL_PLAY_PAUSE_MS);
|
|
185
185
|
};
|
|
186
186
|
tick();
|
|
187
|
-
}, [collapsed, active, onToggleCollapsed, onFocusFlow,
|
|
187
|
+
}, [collapsed, active, onToggleCollapsed, onFocusFlow, trail, onFocusStep]);
|
|
188
188
|
|
|
189
189
|
const togglePlay = useCallback(() => {
|
|
190
190
|
if (playing) {
|
|
@@ -208,7 +208,7 @@ function WalkthroughFlow({
|
|
|
208
208
|
onMouseEnter={() => {
|
|
209
209
|
if (isHoverSuppressed?.()) return;
|
|
210
210
|
setHeaderHover(true);
|
|
211
|
-
if (collapsed) onHoverFlow(
|
|
211
|
+
if (collapsed) onHoverFlow(trail);
|
|
212
212
|
}}
|
|
213
213
|
onMouseLeave={() => {
|
|
214
214
|
setHeaderHover(false);
|
|
@@ -218,7 +218,7 @@ function WalkthroughFlow({
|
|
|
218
218
|
display: 'flex',
|
|
219
219
|
alignItems: 'center',
|
|
220
220
|
gap: 4,
|
|
221
|
-
height:
|
|
221
|
+
height: TRAIL_CONTROL_SIZE,
|
|
222
222
|
padding: '0 0 0 16px',
|
|
223
223
|
background: wholeFlowActive || headerHover ? hoverBg : 'transparent',
|
|
224
224
|
transition: 'background 120ms ease',
|
|
@@ -228,16 +228,16 @@ function WalkthroughFlow({
|
|
|
228
228
|
type="button"
|
|
229
229
|
onClick={() => {
|
|
230
230
|
if (collapsed) {
|
|
231
|
-
onToggleCollapsed(
|
|
232
|
-
onFocusFlow(
|
|
231
|
+
onToggleCollapsed(trail.id);
|
|
232
|
+
onFocusFlow(trail);
|
|
233
233
|
} else if (active !== null && active.stepIndex === null) {
|
|
234
234
|
// Whole flow already selected → collapse + clear.
|
|
235
|
-
onToggleCollapsed(
|
|
235
|
+
onToggleCollapsed(trail.id);
|
|
236
236
|
onClearFocus();
|
|
237
237
|
} else {
|
|
238
238
|
// Expanded with nothing (or a step) selected → select the whole
|
|
239
239
|
// flow, which deselects any focused step without collapsing.
|
|
240
|
-
onFocusFlow(
|
|
240
|
+
onFocusFlow(trail);
|
|
241
241
|
}
|
|
242
242
|
}}
|
|
243
243
|
style={{
|
|
@@ -263,14 +263,14 @@ function WalkthroughFlow({
|
|
|
263
263
|
color: touchesProposed ? PROPOSED_COLOR : theme.colors.text,
|
|
264
264
|
}}
|
|
265
265
|
>
|
|
266
|
-
{
|
|
266
|
+
{trail.title}
|
|
267
267
|
</span>
|
|
268
268
|
</button>
|
|
269
269
|
{!collapsed && (
|
|
270
270
|
<>
|
|
271
271
|
<button
|
|
272
272
|
type="button"
|
|
273
|
-
aria-label={playing ? `Pause ${
|
|
273
|
+
aria-label={playing ? `Pause ${trail.title} autoplay` : `Play ${trail.title}`}
|
|
274
274
|
title={playing ? 'Pause' : 'Play through steps'}
|
|
275
275
|
onMouseEnter={() => setPlayHover(true)}
|
|
276
276
|
onMouseLeave={() => setPlayHover(false)}
|
|
@@ -284,7 +284,7 @@ function WalkthroughFlow({
|
|
|
284
284
|
justifyContent: 'center',
|
|
285
285
|
flexShrink: 0,
|
|
286
286
|
alignSelf: 'stretch',
|
|
287
|
-
width:
|
|
287
|
+
width: TRAIL_CONTROL_SIZE,
|
|
288
288
|
padding: 0,
|
|
289
289
|
border: 'none',
|
|
290
290
|
borderRadius: 0,
|
|
@@ -298,13 +298,13 @@ function WalkthroughFlow({
|
|
|
298
298
|
</button>
|
|
299
299
|
<button
|
|
300
300
|
type="button"
|
|
301
|
-
aria-label={`Collapse ${
|
|
301
|
+
aria-label={`Collapse ${trail.title}`}
|
|
302
302
|
title="Collapse"
|
|
303
303
|
onMouseEnter={() => setCollapseHover(true)}
|
|
304
304
|
onMouseLeave={() => setCollapseHover(false)}
|
|
305
305
|
onClick={(e) => {
|
|
306
306
|
e.stopPropagation();
|
|
307
|
-
onToggleCollapsed(
|
|
307
|
+
onToggleCollapsed(trail.id);
|
|
308
308
|
if (active !== null) onClearFocus();
|
|
309
309
|
}}
|
|
310
310
|
style={{
|
|
@@ -313,7 +313,7 @@ function WalkthroughFlow({
|
|
|
313
313
|
justifyContent: 'center',
|
|
314
314
|
flexShrink: 0,
|
|
315
315
|
alignSelf: 'stretch',
|
|
316
|
-
width:
|
|
316
|
+
width: TRAIL_CONTROL_SIZE,
|
|
317
317
|
padding: 0,
|
|
318
318
|
border: 'none',
|
|
319
319
|
borderRadius: 0,
|
|
@@ -332,7 +332,7 @@ function WalkthroughFlow({
|
|
|
332
332
|
role="button"
|
|
333
333
|
tabIndex={-1}
|
|
334
334
|
draggable
|
|
335
|
-
aria-label={`Reorder ${
|
|
335
|
+
aria-label={`Reorder ${trail.title}`}
|
|
336
336
|
title="Drag to reorder"
|
|
337
337
|
onMouseEnter={() => {
|
|
338
338
|
if (!isHoverSuppressed?.()) setGripHover(true);
|
|
@@ -364,7 +364,7 @@ function WalkthroughFlow({
|
|
|
364
364
|
onLeaveStep();
|
|
365
365
|
}}
|
|
366
366
|
>
|
|
367
|
-
{
|
|
367
|
+
{trail.steps.map((step, i) => {
|
|
368
368
|
const stepActive = active !== null && active.stepIndex === i;
|
|
369
369
|
const proposed = stepProposed(step.from, step.to);
|
|
370
370
|
const revealed =
|
|
@@ -373,7 +373,7 @@ function WalkthroughFlow({
|
|
|
373
373
|
const copyHovered = copyHoverStep === i;
|
|
374
374
|
return (
|
|
375
375
|
<div
|
|
376
|
-
key={`${
|
|
376
|
+
key={`${trailStepGraphEdgeId(step)}-${i}`}
|
|
377
377
|
style={{ position: 'relative' }}
|
|
378
378
|
onFocus={() => setFocusedStep(i)}
|
|
379
379
|
onBlur={(e) => {
|
|
@@ -390,9 +390,9 @@ function WalkthroughFlow({
|
|
|
390
390
|
title={proposed ? 'Step touches a proposed component' : undefined}
|
|
391
391
|
onMouseEnter={() => {
|
|
392
392
|
setHoveredStep(i);
|
|
393
|
-
onHoverStep(
|
|
393
|
+
onHoverStep(trail, i);
|
|
394
394
|
}}
|
|
395
|
-
onClick={() => onFocusStep(
|
|
395
|
+
onClick={() => onFocusStep(trail, i)}
|
|
396
396
|
style={{
|
|
397
397
|
display: 'flex',
|
|
398
398
|
alignItems: 'center',
|
|
@@ -443,7 +443,7 @@ function WalkthroughFlow({
|
|
|
443
443
|
{revealed && (
|
|
444
444
|
<button
|
|
445
445
|
type="button"
|
|
446
|
-
aria-label={`Copy step ${i + 1} of ${
|
|
446
|
+
aria-label={`Copy step ${i + 1} of ${trail.title} for an agent`}
|
|
447
447
|
title={copied ? 'Copied' : 'Copy this step for an agent'}
|
|
448
448
|
onMouseDown={(e) => e.preventDefault()}
|
|
449
449
|
onMouseEnter={() => setCopyHoverStep(i)}
|
|
@@ -490,30 +490,30 @@ function WalkthroughFlow({
|
|
|
490
490
|
);
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
-
export interface
|
|
494
|
-
/** Ordered
|
|
495
|
-
|
|
493
|
+
export interface TrailsPanelProps {
|
|
494
|
+
/** Ordered trails — the list renders them in array order. */
|
|
495
|
+
trails: SubsystemTrail[];
|
|
496
496
|
/** Ids of the rows whose step lists are expanded. */
|
|
497
|
-
|
|
498
|
-
|
|
497
|
+
expandedTrails: Set<string>;
|
|
498
|
+
focusedTrailId: string | null;
|
|
499
499
|
focusedStepIndex: number | null;
|
|
500
|
-
|
|
501
|
-
|
|
500
|
+
hoveredTrailStep: {
|
|
501
|
+
trailId: string;
|
|
502
502
|
stepIndex: number | null;
|
|
503
503
|
} | null;
|
|
504
504
|
onToggleCollapsed: (tlId: string) => void;
|
|
505
|
-
onFocusFlow: (tl:
|
|
505
|
+
onFocusFlow: (tl: SubsystemTrail) => void;
|
|
506
506
|
onClearFocus: () => void;
|
|
507
|
-
onFocusStep: (tl:
|
|
508
|
-
onHoverStep: (tl:
|
|
509
|
-
onHoverFlow: (tl:
|
|
507
|
+
onFocusStep: (tl: SubsystemTrail, stepIndex: number) => void;
|
|
508
|
+
onHoverStep: (tl: SubsystemTrail, stepIndex: number) => void;
|
|
509
|
+
onHoverFlow: (tl: SubsystemTrail) => void;
|
|
510
510
|
onLeaveStep: () => void;
|
|
511
511
|
/**
|
|
512
512
|
* When set, rows grow a drag grip (and become drop targets) so a drop emits
|
|
513
513
|
* the reordered array. Grips show only while every row is collapsed. Omit
|
|
514
514
|
* for a read-only panel.
|
|
515
515
|
*/
|
|
516
|
-
onReorder?: (next:
|
|
516
|
+
onReorder?: (next: SubsystemTrail[]) => void;
|
|
517
517
|
/**
|
|
518
518
|
* Aliases of components marked `proposed`. A row whose steps touch one gets
|
|
519
519
|
* its title tinted, and each such step (index and title) is tinted too
|
|
@@ -523,16 +523,16 @@ export interface WalkthroughsPanelProps {
|
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
/**
|
|
526
|
-
* The flows panel: a scroll container of `
|
|
526
|
+
* The flows panel: a scroll container of `TrailFlow` rows, optionally
|
|
527
527
|
* drag-reorderable. The host owns the array; a drop calls `onReorder` with the
|
|
528
528
|
* next order and the host re-renders with it.
|
|
529
529
|
*/
|
|
530
|
-
export function
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
530
|
+
export function TrailsPanel({
|
|
531
|
+
trails,
|
|
532
|
+
expandedTrails,
|
|
533
|
+
focusedTrailId,
|
|
534
534
|
focusedStepIndex,
|
|
535
|
-
|
|
535
|
+
hoveredTrailStep,
|
|
536
536
|
onToggleCollapsed,
|
|
537
537
|
onFocusFlow,
|
|
538
538
|
onClearFocus,
|
|
@@ -542,12 +542,12 @@ export function WalkthroughsPanel({
|
|
|
542
542
|
onLeaveStep,
|
|
543
543
|
onReorder,
|
|
544
544
|
proposedAliases,
|
|
545
|
-
}:
|
|
545
|
+
}: TrailsPanelProps) {
|
|
546
546
|
const { theme } = useTheme();
|
|
547
547
|
// Reordering is offered only while every row is collapsed: the compact list
|
|
548
548
|
// is what you drag, and expanded step lists would make drop targets tall and
|
|
549
549
|
// the landing boundary ambiguous.
|
|
550
|
-
const allCollapsed =
|
|
550
|
+
const allCollapsed = trails.every((w) => !expandedTrails.has(w.id));
|
|
551
551
|
const reorderable = onReorder != null && allCollapsed;
|
|
552
552
|
// Row being dragged, and the gap the pointer is over (boundaries 0..n
|
|
553
553
|
// between rows). The boundary is where the dragged row will be inserted.
|
|
@@ -621,9 +621,9 @@ export function WalkthroughsPanel({
|
|
|
621
621
|
// Removing the dragged row shifts every boundary after it down one.
|
|
622
622
|
const target = reorderTargetIndex(boundary, from);
|
|
623
623
|
if (target === from) return;
|
|
624
|
-
onReorder(
|
|
624
|
+
onReorder(reorderTrails(trails, from, target));
|
|
625
625
|
},
|
|
626
|
-
[dragIndex, dropBoundary, onReorder, resetDrag,
|
|
626
|
+
[dragIndex, dropBoundary, onReorder, resetDrag, trails],
|
|
627
627
|
);
|
|
628
628
|
|
|
629
629
|
const accent = theme.colors.accent ?? theme.colors.primary ?? theme.colors.text;
|
|
@@ -639,19 +639,19 @@ export function WalkthroughsPanel({
|
|
|
639
639
|
}}
|
|
640
640
|
onDragEnd={reorderable ? resetDrag : undefined}
|
|
641
641
|
>
|
|
642
|
-
{
|
|
642
|
+
{trails.map((tl, i) => {
|
|
643
643
|
const isDragging = dragIndex === i;
|
|
644
644
|
// One indicator per boundary: a row's top edge for boundaries above it,
|
|
645
645
|
// the last row's bottom edge for the boundary at the very end.
|
|
646
646
|
const showTop = reorderable && dropBoundary === i;
|
|
647
647
|
const showBottom =
|
|
648
648
|
reorderable &&
|
|
649
|
-
i ===
|
|
650
|
-
dropBoundary ===
|
|
649
|
+
i === trails.length - 1 &&
|
|
650
|
+
dropBoundary === trails.length;
|
|
651
651
|
return (
|
|
652
652
|
<div
|
|
653
653
|
key={tl.id}
|
|
654
|
-
data-
|
|
654
|
+
data-trail-row={tl.id}
|
|
655
655
|
data-reorder-index={i}
|
|
656
656
|
onDragOver={reorderable ? (e) => handleDragOver(e, i) : undefined}
|
|
657
657
|
onDrop={reorderable ? handleDrop : undefined}
|
|
@@ -692,14 +692,14 @@ export function WalkthroughsPanel({
|
|
|
692
692
|
}}
|
|
693
693
|
/>
|
|
694
694
|
)}
|
|
695
|
-
<
|
|
696
|
-
|
|
697
|
-
collapsed={!
|
|
695
|
+
<TrailFlow
|
|
696
|
+
trail={tl}
|
|
697
|
+
collapsed={!expandedTrails.has(tl.id)}
|
|
698
698
|
active={
|
|
699
|
-
|
|
699
|
+
focusedTrailId === tl.id
|
|
700
700
|
? { stepIndex: focusedStepIndex }
|
|
701
|
-
:
|
|
702
|
-
? { stepIndex:
|
|
701
|
+
: hoveredTrailStep?.trailId === tl.id
|
|
702
|
+
? { stepIndex: hoveredTrailStep.stepIndex }
|
|
703
703
|
: null
|
|
704
704
|
}
|
|
705
705
|
onToggleCollapsed={onToggleCollapsed}
|
|
@@ -53,7 +53,7 @@ export function extractDeclarationLine(content: string, lineNumber: number): str
|
|
|
53
53
|
|
|
54
54
|
/** Options when opening a file in the subsystem graph drawer. */
|
|
55
55
|
export interface SubsystemOpenFileOptions {
|
|
56
|
-
/** Scroll/highlight this 1-based line (declaration start or
|
|
56
|
+
/** Scroll/highlight this 1-based line (declaration start or trail site). */
|
|
57
57
|
startLine?: number;
|
|
58
58
|
/**
|
|
59
59
|
* When true with `startLine`, show the whole file scrolled to that line
|
|
@@ -192,29 +192,29 @@ describe('generateDeclarationString — signature augmentation', () => {
|
|
|
192
192
|
expect(
|
|
193
193
|
generateDeclarationString(
|
|
194
194
|
base({
|
|
195
|
-
name: '
|
|
196
|
-
symbol: '
|
|
195
|
+
name: 'TrailsPanel',
|
|
196
|
+
symbol: 'TrailsPanel',
|
|
197
197
|
signatureAugmentation: {
|
|
198
|
-
parameters: [{ type: '
|
|
198
|
+
parameters: [{ type: 'TrailsPanelProps' }],
|
|
199
199
|
returnType: 'JSX.Element',
|
|
200
200
|
},
|
|
201
201
|
}),
|
|
202
202
|
),
|
|
203
|
-
).toBe('function
|
|
203
|
+
).toBe('function TrailsPanel(arg0: TrailsPanelProps): JSX.Element;');
|
|
204
204
|
});
|
|
205
205
|
|
|
206
206
|
test('resolveComponentDeclaration returns the augmentation when there is no own declaration', () => {
|
|
207
207
|
const d = resolveComponentDeclaration(
|
|
208
208
|
base({
|
|
209
209
|
signatureAugmentation: {
|
|
210
|
-
parameters: [{ type: '
|
|
210
|
+
parameters: [{ type: 'TrailsPanelProps' }],
|
|
211
211
|
returnType: 'JSX.Element',
|
|
212
212
|
},
|
|
213
213
|
}),
|
|
214
214
|
);
|
|
215
215
|
expect(d?.kind).toBe('function');
|
|
216
216
|
if (d?.kind === 'function') {
|
|
217
|
-
expect(d.parameters).toEqual([{ type: '
|
|
217
|
+
expect(d.parameters).toEqual([{ type: 'TrailsPanelProps' }]);
|
|
218
218
|
expect(d.returnType).toBe('JSX.Element');
|
|
219
219
|
}
|
|
220
220
|
});
|
|
@@ -40,10 +40,10 @@ import {
|
|
|
40
40
|
packageColor,
|
|
41
41
|
subsystemGraphLayoutKey,
|
|
42
42
|
describeConstructBreakdown,
|
|
43
|
-
|
|
43
|
+
reorderTrails,
|
|
44
44
|
reorderTargetIndex,
|
|
45
45
|
} from './model';
|
|
46
|
-
import type { SubsystemComponent, SubsystemComponentEdge,
|
|
46
|
+
import type { SubsystemComponent, SubsystemComponentEdge, SubsystemTrail } from './model';
|
|
47
47
|
|
|
48
48
|
const comps: SubsystemComponent[] = [
|
|
49
49
|
{ alias: 'reader', name: 'SessionReader', construct: 'class', file: 'SessionReader.ts', purl: 'pkg:github/principal-ai/agent-monitoring' },
|
|
@@ -51,7 +51,7 @@ const comps: SubsystemComponent[] = [
|
|
|
51
51
|
];
|
|
52
52
|
|
|
53
53
|
// 'host' is NOT a component — this is the cross-package external case.
|
|
54
|
-
const
|
|
54
|
+
const trails: SubsystemTrail[] = [
|
|
55
55
|
{
|
|
56
56
|
id: 'wt',
|
|
57
57
|
title: 'flow',
|
|
@@ -78,7 +78,7 @@ const walkthroughs: SubsystemWalkthrough[] = [
|
|
|
78
78
|
},
|
|
79
79
|
];
|
|
80
80
|
|
|
81
|
-
const doc = { components: comps,
|
|
81
|
+
const doc = { components: comps, trails };
|
|
82
82
|
|
|
83
83
|
describe('subsystem graph model', () => {
|
|
84
84
|
test('converts all components to flat component nodes', () => {
|
|
@@ -109,7 +109,7 @@ describe('subsystem graph model', () => {
|
|
|
109
109
|
];
|
|
110
110
|
const { nodes } = await buildSubsystemGraph({
|
|
111
111
|
components: withExternal,
|
|
112
|
-
|
|
112
|
+
trails: [{
|
|
113
113
|
id: 'w1',
|
|
114
114
|
title: 'feed',
|
|
115
115
|
steps: [{ from: 'reader', to: 'proposed-watcher', mechanism: 'feeds', file: 'x.ts', line: 1 }],
|
|
@@ -452,7 +452,7 @@ describe('subsystem graph model', () => {
|
|
|
452
452
|
{ alias: 'b', name: 'b', construct: 'function', file: 'b.ts', purl: 'pkg:github/acme/app', process: 'app/host' },
|
|
453
453
|
{ alias: 'solo', name: 'solo', construct: 'function', file: 's.ts', purl: 'pkg:github/acme/app', process: 'app/lonely' },
|
|
454
454
|
],
|
|
455
|
-
|
|
455
|
+
trails: [{
|
|
456
456
|
id: 'w1',
|
|
457
457
|
title: 'call',
|
|
458
458
|
steps: [{ from: 'a', to: 'b', mechanism: 'calls', file: 'a.ts', line: 1 }],
|
|
@@ -808,7 +808,7 @@ describe('subsystem graph model', () => {
|
|
|
808
808
|
}
|
|
809
809
|
: c,
|
|
810
810
|
),
|
|
811
|
-
|
|
811
|
+
trails,
|
|
812
812
|
};
|
|
813
813
|
expect(subsystemGraphLayoutKey(base)).toBe(subsystemGraphLayoutKey(withRef));
|
|
814
814
|
});
|
|
@@ -816,7 +816,7 @@ describe('subsystem graph model', () => {
|
|
|
816
816
|
|
|
817
817
|
describe('isConstructsOnlyModel', () => {
|
|
818
818
|
test('true when components exist and there are no edges', () => {
|
|
819
|
-
expect(isConstructsOnlyModel({ components: comps,
|
|
819
|
+
expect(isConstructsOnlyModel({ components: comps, trails: [] })).toBe(true);
|
|
820
820
|
expect(isConstructsOnlyModel({ components: comps })).toBe(true);
|
|
821
821
|
});
|
|
822
822
|
|
|
@@ -829,13 +829,13 @@ describe('isConstructsOnlyModel', () => {
|
|
|
829
829
|
).toBe(false);
|
|
830
830
|
});
|
|
831
831
|
|
|
832
|
-
test('false when empty, or when
|
|
832
|
+
test('false when empty, or when trail steps exist', () => {
|
|
833
833
|
expect(isConstructsOnlyModel({ components: [] })).toBe(false);
|
|
834
|
-
expect(isConstructsOnlyModel({ components: comps,
|
|
834
|
+
expect(isConstructsOnlyModel({ components: comps, trails })).toBe(false);
|
|
835
835
|
expect(
|
|
836
836
|
isConstructsOnlyModel({
|
|
837
837
|
components: comps,
|
|
838
|
-
|
|
838
|
+
trails: [
|
|
839
839
|
{
|
|
840
840
|
id: 'wt',
|
|
841
841
|
title: 'flow',
|
|
@@ -1079,41 +1079,41 @@ describe('boundary frame min width (process / package badges)', () => {
|
|
|
1079
1079
|
});
|
|
1080
1080
|
});
|
|
1081
1081
|
|
|
1082
|
-
describe('
|
|
1083
|
-
const wts:
|
|
1082
|
+
describe('reorderTrails', () => {
|
|
1083
|
+
const wts: SubsystemTrail[] = [
|
|
1084
1084
|
{ id: 'a', title: 'A', steps: [] },
|
|
1085
1085
|
{ id: 'b', title: 'B', steps: [] },
|
|
1086
1086
|
{ id: 'c', title: 'C', steps: [] },
|
|
1087
1087
|
];
|
|
1088
|
-
const ids = (list:
|
|
1088
|
+
const ids = (list: SubsystemTrail[]) => list.map((w) => w.id);
|
|
1089
1089
|
|
|
1090
1090
|
test('moves an item forward to the target index', () => {
|
|
1091
|
-
expect(ids(
|
|
1091
|
+
expect(ids(reorderTrails(wts, 0, 2))).toEqual(['b', 'c', 'a']);
|
|
1092
1092
|
});
|
|
1093
1093
|
|
|
1094
1094
|
test('moves an item backward to the target index', () => {
|
|
1095
|
-
expect(ids(
|
|
1095
|
+
expect(ids(reorderTrails(wts, 2, 0))).toEqual(['c', 'a', 'b']);
|
|
1096
1096
|
});
|
|
1097
1097
|
|
|
1098
1098
|
test('returns a new array and leaves the input untouched', () => {
|
|
1099
|
-
const next =
|
|
1099
|
+
const next = reorderTrails(wts, 1, 2);
|
|
1100
1100
|
expect(next).not.toBe(wts);
|
|
1101
1101
|
expect(ids(wts)).toEqual(['a', 'b', 'c']);
|
|
1102
1102
|
expect(ids(next)).toEqual(['a', 'c', 'b']);
|
|
1103
1103
|
});
|
|
1104
1104
|
|
|
1105
1105
|
test('no-op when source and target match', () => {
|
|
1106
|
-
expect(ids(
|
|
1106
|
+
expect(ids(reorderTrails(wts, 1, 1))).toEqual(['a', 'b', 'c']);
|
|
1107
1107
|
});
|
|
1108
1108
|
|
|
1109
1109
|
test('out-of-range source returns a shallow copy unchanged', () => {
|
|
1110
|
-
const next =
|
|
1110
|
+
const next = reorderTrails(wts, 5, 0);
|
|
1111
1111
|
expect(next).not.toBe(wts);
|
|
1112
1112
|
expect(ids(next)).toEqual(['a', 'b', 'c']);
|
|
1113
1113
|
});
|
|
1114
1114
|
|
|
1115
1115
|
test('clamps a target beyond the end to the last slot', () => {
|
|
1116
|
-
expect(ids(
|
|
1116
|
+
expect(ids(reorderTrails(wts, 0, 99))).toEqual(['b', 'c', 'a']);
|
|
1117
1117
|
});
|
|
1118
1118
|
});
|
|
1119
1119
|
|
|
@@ -1140,15 +1140,15 @@ describe('reorderTargetIndex', () => {
|
|
|
1140
1140
|
expect(reorderTargetIndex(0, 0)).toBe(0);
|
|
1141
1141
|
});
|
|
1142
1142
|
|
|
1143
|
-
test('composes with
|
|
1144
|
-
const wts:
|
|
1143
|
+
test('composes with reorderTrails to match the indicator', () => {
|
|
1144
|
+
const wts: SubsystemTrail[] = [
|
|
1145
1145
|
{ id: 'a', title: 'A', steps: [] },
|
|
1146
1146
|
{ id: 'b', title: 'B', steps: [] },
|
|
1147
1147
|
{ id: 'c', title: 'C', steps: [] },
|
|
1148
1148
|
];
|
|
1149
1149
|
// Drag A onto the gap below B (boundary 2) → A lands between B and C.
|
|
1150
1150
|
const target = reorderTargetIndex(2, 0);
|
|
1151
|
-
expect(
|
|
1151
|
+
expect(reorderTrails(wts, 0, target).map((w) => w.id)).toEqual(['b', 'a', 'c']);
|
|
1152
1152
|
});
|
|
1153
1153
|
});
|
|
1154
1154
|
|
|
@@ -1167,9 +1167,9 @@ describe('graphify-native edges', () => {
|
|
|
1167
1167
|
expect(e.mechanism).toBe('imports');
|
|
1168
1168
|
});
|
|
1169
1169
|
|
|
1170
|
-
test('
|
|
1170
|
+
test('trail edges keep no graphify provenance', () => {
|
|
1171
1171
|
const [e] = deriveGraphEdges({
|
|
1172
|
-
|
|
1172
|
+
trails: [trails[0]!],
|
|
1173
1173
|
});
|
|
1174
1174
|
expect(e.provenance).toBeUndefined();
|
|
1175
1175
|
expect(e.mechanism).toBe('calls');
|