@principal-ai/principal-view-react 0.16.34 → 0.16.35

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.
Files changed (31) hide show
  1. package/dist/subsystem/ComponentDetail.d.ts +12 -0
  2. package/dist/subsystem/ComponentDetail.d.ts.map +1 -0
  3. package/dist/subsystem/ComponentDetail.js +95 -0
  4. package/dist/subsystem/ComponentDetail.js.map +1 -0
  5. package/dist/subsystem/EdgeLegendModal.d.ts +18 -0
  6. package/dist/subsystem/EdgeLegendModal.d.ts.map +1 -0
  7. package/dist/subsystem/EdgeLegendModal.js +98 -0
  8. package/dist/subsystem/EdgeLegendModal.js.map +1 -0
  9. package/dist/subsystem/FileDrawer.d.ts +16 -0
  10. package/dist/subsystem/FileDrawer.d.ts.map +1 -0
  11. package/dist/subsystem/FileDrawer.js +72 -0
  12. package/dist/subsystem/FileDrawer.js.map +1 -0
  13. package/dist/subsystem/SubsystemComponentGraph.d.ts +0 -3
  14. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  15. package/dist/subsystem/SubsystemComponentGraph.js +28 -190
  16. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  17. package/dist/subsystem/model.d.ts +0 -3
  18. package/dist/subsystem/model.d.ts.map +1 -1
  19. package/dist/subsystem/model.js.map +1 -1
  20. package/dist/subsystem/nodes.d.ts +2 -2
  21. package/dist/subsystem/nodes.d.ts.map +1 -1
  22. package/dist/subsystem/nodes.js +3 -21
  23. package/dist/subsystem/nodes.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/stories/SubsystemComponentGraph.stories.tsx +10 -10
  26. package/src/subsystem/ComponentDetail.tsx +187 -0
  27. package/src/subsystem/EdgeLegendModal.tsx +146 -0
  28. package/src/subsystem/FileDrawer.tsx +105 -0
  29. package/src/subsystem/SubsystemComponentGraph.tsx +42 -327
  30. package/src/subsystem/model.ts +0 -3
  31. package/src/subsystem/nodes.tsx +2 -29
@@ -32,40 +32,21 @@ import {
32
32
  applyNodeChanges,
33
33
  } from '@xyflow/react';
34
34
  import { useTheme } from '@principal-ade/industry-theme';
35
- import { X } from 'lucide-react';
35
+ import { Map as MapIcon } from 'lucide-react';
36
36
  import { IndustryMarkdownSlide } from 'themed-markdown';
37
37
  import {
38
38
  buildSubsystemGraph,
39
- KIND_COLOR,
40
39
  MECHANISM_COLOR,
41
- deriveNameFromSymbol,
42
40
  type SubsystemComponentEdge,
43
41
  type SubsystemComponent,
44
42
  type SubsystemEdgeMechanism,
45
43
  } from './model';
46
- import type { GraphifyComponentDetail } from '../graphify';
47
44
  import { SubsystemComponentNode, SubsystemEdge, SUBSYSTEM_CALLBACKS } from './nodes';
48
45
  import { SubsystemFileTree } from './SubsystemFileTree';
49
46
  import { GraphLayoutCover } from './GraphLayoutCover';
50
-
51
- const MECHANISM_DESCRIPTIONS: [SubsystemEdgeMechanism, string, boolean][] = [
52
- ['imports', 'import statement (code-level dependency)', true],
53
- ['imports_from', 'imported by (reverse dependency)', true],
54
- ['re_exports', 're-exports symbols from', true],
55
- ['defines', 'defines / declares symbol', true],
56
- ['calls', 'function/method call (call graph edge)', true],
57
- ['extends', 'class inheritance', true],
58
- ['inherits', 'class inheritance', true],
59
- ['implements', 'implements interface / protocol', true],
60
- ['mixes_in', 'applies mixin', true],
61
- ['uses', 'general dependency (import, call, or reference)', false],
62
- ['method', 'structural: has method / member', true],
63
- ['references', 'type / symbol reference (not a call)', true],
64
- ['contains', 'structural: contains / encapsulates', true],
65
- ['feeds', 'data flow: output feeds into input', false],
66
- ['produces', 'data flow: produces / outputs', false],
67
- ['registers-into', 'registration pattern', false],
68
- ];
47
+ import { ComponentDetail } from './ComponentDetail';
48
+ import { FileDrawer } from './FileDrawer';
49
+ import { EdgeLegendModal, MECHANISM_DESCRIPTIONS } from './EdgeLegendModal';
69
50
 
70
51
  export interface SubsystemComponentGraphProps {
71
52
  components: SubsystemComponent[];
@@ -78,9 +59,6 @@ export interface SubsystemComponentGraphProps {
78
59
  maxNodeWidth?: number;
79
60
  /** Show edge labels (mechanism names) on the graph. @default true */
80
61
  showEdgeLabels?: boolean;
81
- /** Show the click-to-open file chip under each component name.
82
- * @default true */
83
- showFileBadges?: boolean;
84
62
  /** Subsystem title displayed in the sidebar. */
85
63
  title?: string;
86
64
  /** Markdown description rendered in the sidebar. */
@@ -123,7 +101,7 @@ interface InnerProps extends SubsystemComponentGraphProps {
123
101
  measured: { w: number; h: number } | null;
124
102
  }
125
103
 
126
- function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, showFileBadges, title, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, renderFileView, renderFileViewer, onFileSelect }: InnerProps) {
104
+ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured, maxNodeWidth, showEdgeLabels, title, description, canvasOverlay, sidebarExtra, sidebarAfterDescription, renderFileView, renderFileViewer, onFileSelect }: InnerProps) {
127
105
  const { theme } = useTheme();
128
106
  const { fitView } = useReactFlow();
129
107
  const viewport = useViewport();
@@ -135,6 +113,8 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
135
113
  const [selected, setSelected] = useState<SubsystemComponent | null>(null);
136
114
  // File currently shown in the bottom drawer (repo-root-relative path).
137
115
  const [openFile, setOpenFile] = useState<string | null>(null);
116
+ // Edge-legend modal visibility (opened from the canvas's top-left button).
117
+ const [legendOpen, setLegendOpen] = useState(false);
138
118
  // Component the pointer is over (null on leave) → transient tree highlight.
139
119
  const [hoveredComponentId, setHoveredComponentId] = useState<string | null>(null);
140
120
  // Ref mirror of `selected` so the SUBSYSTEM_CALLBACKS click handler (a
@@ -248,19 +228,15 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
248
228
  // component lives in that file — the node renderer spotlights matches and
249
229
  // dims non-matches (mirrors the edge-dimming behavior on selection).
250
230
  const dispNodes = useMemo(() => {
251
- let ns = xyflowNodesBase.map((n) => ({
252
- ...n,
253
- data: { ...(n.data as object), showFileBadges },
254
- }));
255
- if (!openFile) return ns;
256
- return ns.map((n) => {
231
+ if (!openFile) return xyflowNodesBase;
232
+ return xyflowNodesBase.map((n) => {
257
233
  const comp = (n.data as { component?: SubsystemComponent } | undefined)?.component;
258
234
  return {
259
235
  ...n,
260
236
  data: { ...(n.data as object), fileMatch: comp?.file === openFile },
261
237
  };
262
238
  });
263
- }, [xyflowNodesBase, openFile, showFileBadges]);
239
+ }, [xyflowNodesBase, openFile]);
264
240
 
265
241
  const baseNodesKey = useMemo(() => nodes.map((n) => n.id).sort().join(','), [nodes]);
266
242
  const baseEdgesKey = useMemo(
@@ -404,8 +380,6 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
404
380
  return new Set(edgeLabels.map((l) => l.mechanism));
405
381
  }, [edgeLabels]);
406
382
 
407
- const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
408
-
409
383
  // Unique source files across components → sidebar file tree.
410
384
  const files = useMemo(
411
385
  () => Array.from(new Set(components.map((c) => c.file).filter(Boolean))).sort(),
@@ -436,8 +410,8 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
436
410
 
437
411
  return (
438
412
  <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'row' }}>
439
- {/* Sidebar: scrollable title/description/legend on top, file tree pinned to the bottom half */}
440
- {(title || description || usedMechanisms.size > 0 || sidebarExtra || sidebarAfterDescription || files.length > 0) && (
413
+ {/* Sidebar: scrollable title/description on top, file tree pinned to the bottom half */}
414
+ {(title || description || sidebarExtra || sidebarAfterDescription || files.length > 0) && (
441
415
  <div
442
416
  style={{
443
417
  width: 340,
@@ -490,29 +464,6 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
490
464
  </div>
491
465
  )}
492
466
  {sidebarAfterDescription}
493
- {usedMechanisms.size > 0 && (
494
- <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
495
- <span style={{ fontSize: theme.fontSizes[0] * 0.8, fontFamily: theme.fonts.monospace, textTransform: 'uppercase', color: muted, fontWeight: 600 }}>
496
- Edge Legend
497
- </span>
498
- {MECHANISM_DESCRIPTIONS.filter(([m]) => usedMechanisms.has(m)).map(([mechanism, desc, verifiable]) => (
499
- <div key={mechanism} style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: theme.fontSizes[0] }}>
500
- <span
501
- style={{
502
- width: 8,
503
- height: 8,
504
- borderRadius: verifiable ? '50%' : '30% 70% 70% 30% / 30% 30% 70% 70%',
505
- background: MECHANISM_COLOR[mechanism],
506
- border: verifiable ? 'none' : `1px dashed ${MECHANISM_COLOR[mechanism]}`,
507
- flexShrink: 0,
508
- }}
509
- />
510
- <span style={{ fontFamily: theme.fonts.monospace, color: MECHANISM_COLOR[mechanism], fontWeight: 500 }}>{mechanism}</span>
511
- <span style={{ color: muted }}>{desc}</span>
512
- </div>
513
- ))}
514
- </div>
515
- )}
516
467
  </div>
517
468
  {files.length > 0 && (
518
469
  <SubsystemFileTree
@@ -612,287 +563,51 @@ function Inner({ components, edges, onSelect, onEdgeSelect, measured: _measured,
612
563
  <Background variant={BackgroundVariant.Dots} gap={16} size={1} />
613
564
  <Controls showZoom showFitView showInteractive />
614
565
  </ReactFlow>
615
- {selected && <ComponentDetail component={selected} />}
616
- <FileDrawer file={openFile} onClose={() => setOpenFile(null)}>
617
- {fileViewer && openFile ? fileViewer(openFile) : null}
618
- </FileDrawer>
619
- {/* Startup cover — hides measurement, layout swap, and camera settle. */}
620
- <GraphLayoutCover revealed={layoutReady} />
621
- {canvasOverlay}
622
- </div>
623
- </div>
624
- );
625
- }
626
-
627
- /** Detail panel for the selected component — the verifiable identity + sources
628
- * moved off the canvas so nodes stay minimal. File content lives in the
629
- * bottom FileDrawer, not here. */
630
- function ComponentDetail({ component }: { component: SubsystemComponent }) {
631
- const { theme } = useTheme();
632
- const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
633
- const color = KIND_COLOR[component.kind] ?? '#888';
634
- const displayName = deriveNameFromSymbol(component.symbol, component.kind, component.name, component.file);
635
- const rows: Array<[string, string]> = [];
636
- if (component.symbol) rows.push(['Symbol', component.symbol]);
637
- if (component.file) rows.push(['File', component.file]);
638
- if (component.purpose) rows.push(['Purpose', component.purpose]);
639
- rows.push(['PURL', component.purl]);
640
-
641
- return (
642
- <div
643
- style={{
644
- borderTop: `1px solid ${theme.colors.border}`,
645
- background: theme.colors.background,
646
- padding: '10px 12px',
647
- fontFamily: theme.fonts.body,
648
- }}
649
- >
650
- <div
651
- style={{
652
- display: 'flex',
653
- alignItems: 'center',
654
- gap: 8,
655
- fontSize: theme.fontSizes[1],
656
- fontWeight: 600,
657
- marginBottom: 6,
658
- }}
659
- >
660
- <span style={{ color }}>{displayName}</span>
661
- <span
662
- style={{
663
- fontSize: theme.fontSizes[0] * 0.8,
664
- fontFamily: theme.fonts.monospace,
665
- textTransform: 'uppercase',
666
- color,
667
- }}
668
- >
669
- {component.kind}
670
- </span>
671
- </div>
672
- {rows.map(([k, v]) => (
673
- <div
674
- key={k}
675
- style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0], lineHeight: 1.5 }}
676
- >
677
- <span
678
- style={{
679
- width: 64,
680
- flexShrink: 0,
681
- color: muted,
682
- fontFamily: theme.fonts.monospace,
683
- textTransform: 'uppercase',
684
- fontSize: theme.fontSizes[0] * 0.8,
685
- }}
686
- >
687
- {k}
688
- </span>
689
- <span style={{ color: theme.colors.text, fontFamily: theme.fonts.monospace }}>
690
- {v}
691
- </span>
692
- </div>
693
- ))}
694
- {component.detail && <GraphifyDetailSections detail={component.detail} />}
695
- </div>
696
- );
697
- }
698
-
699
- /** Bottom panel that slides up from the bottom of the graph area to show a
700
- * file's contents — opened by node clicks and sidebar file-tree clicks
701
- * alike. Sits in normal flow (canvas shrinks while open, nothing covered)
702
- * and animates via height; stays mounted so open/close animates. */
703
- function FileDrawer({
704
- file,
705
- onClose,
706
- children,
707
- }: {
708
- file: string | null;
709
- onClose: () => void;
710
- children?: ReactNode;
711
- }) {
712
- const { theme } = useTheme();
713
- const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
714
- const open = file !== null;
715
-
716
- useEffect(() => {
717
- if (!open) return;
718
- const onKey = (e: KeyboardEvent) => {
719
- if (e.key === 'Escape') onClose();
720
- };
721
- window.addEventListener('keydown', onKey);
722
- return () => window.removeEventListener('keydown', onKey);
723
- }, [open, onClose]);
724
-
725
- return (
726
- <div
727
- style={{
728
- position: 'relative',
729
- // Above the absolute edge-label overlay (zIndex 5), which spans the
730
- // whole graph-area container including this panel's slice.
731
- zIndex: 6,
732
- flexShrink: 0,
733
- height: open ? '45%' : 0,
734
- minHeight: 0,
735
- overflow: 'hidden',
736
- display: 'flex',
737
- flexDirection: 'column',
738
- background: theme.colors.background,
739
- borderTop: open ? `1px solid ${theme.colors.border}` : 'none',
740
- transition: 'height 200ms ease',
741
- }}
742
- >
743
- <div
744
- style={{
745
- display: 'flex',
746
- alignItems: 'center',
747
- gap: 8,
748
- padding: '6px 10px',
749
- borderBottom: `1px solid ${theme.colors.border}`,
750
- flexShrink: 0,
751
- }}
752
- >
753
- <span
754
- title={file ?? undefined}
755
- style={{
756
- flex: 1,
757
- minWidth: 0,
758
- overflow: 'hidden',
759
- textOverflow: 'ellipsis',
760
- whiteSpace: 'nowrap',
761
- fontFamily: theme.fonts.monospace,
762
- fontSize: theme.fontSizes[0],
763
- color: muted,
764
- }}
765
- >
766
- {file}
767
- </span>
566
+ {/* Legend button top-left overlay on the canvas; opens the modal. */}
567
+ {usedMechanisms.size > 0 && (
768
568
  <button
769
569
  type="button"
770
- onClick={onClose}
771
- aria-label="Close file"
570
+ onClick={() => setLegendOpen(true)}
772
571
  style={{
572
+ position: 'absolute',
573
+ top: 10,
574
+ left: 10,
575
+ zIndex: 7,
773
576
  display: 'inline-flex',
774
577
  alignItems: 'center',
775
- justifyContent: 'center',
776
- width: 22,
777
- height: 22,
778
- padding: 0,
779
- border: 'none',
780
- borderRadius: 4,
781
- background: 'transparent',
578
+ gap: 6,
579
+ padding: '4px 10px',
580
+ fontSize: theme.fontSizes[0],
581
+ fontFamily: theme.fonts.body,
782
582
  color: theme.colors.text,
583
+ background: theme.colors.backgroundSecondary ?? theme.colors.background,
584
+ border: `1px solid ${theme.colors.border}`,
585
+ borderRadius: 6,
783
586
  cursor: 'pointer',
587
+ boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
784
588
  }}
785
589
  >
786
- <X size={14} />
590
+ <MapIcon size={13} />
591
+ Legend
787
592
  </button>
593
+ )}
594
+ <EdgeLegendModal
595
+ open={legendOpen}
596
+ mechanisms={usedMechanisms}
597
+ onClose={() => setLegendOpen(false)}
598
+ />
599
+ {selected && <ComponentDetail component={selected} />}
600
+ <FileDrawer file={openFile} onClose={() => setOpenFile(null)}>
601
+ {fileViewer && openFile ? fileViewer(openFile) : null}
602
+ </FileDrawer>
603
+ {/* Startup cover — hides measurement, layout swap, and camera settle. */}
604
+ <GraphLayoutCover revealed={layoutReady} />
605
+ {canvasOverlay}
788
606
  </div>
789
- <div style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>{children}</div>
790
607
  </div>
791
608
  );
792
609
  }
793
610
 
794
- /** Renders the graphify drill-down payload for a component. */
795
- function GraphifyDetailSections({ detail }: { detail: GraphifyComponentDetail }) {
796
- const { theme } = useTheme();
797
- const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
798
-
799
- const label = (k: string) => (
800
- <span
801
- style={{
802
- width: 64,
803
- flexShrink: 0,
804
- color: muted,
805
- fontFamily: theme.fonts.monospace,
806
- textTransform: 'uppercase',
807
- fontSize: theme.fontSizes[0] * 0.8,
808
- }}
809
- >
810
- {k}
811
- </span>
812
- );
813
- const chip = (name: string, meta?: string, key?: string | number) => (
814
- <span
815
- key={key}
816
- style={{
817
- fontFamily: theme.fonts.monospace,
818
- fontSize: theme.fontSizes[0],
819
- color: theme.colors.text,
820
- border: `1px solid ${theme.colors.border}`,
821
- borderRadius: 4,
822
- padding: '1px 6px',
823
- marginRight: 6,
824
- marginBottom: 4,
825
- display: 'inline-block',
826
- }}
827
- >
828
- {name}
829
- {meta ? <span style={{ color: muted }}> {meta}</span> : ''}
830
- </span>
831
- );
832
- const row = (k: string, children: ReactNode) => (
833
- <div
834
- style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0], lineHeight: 1.5, marginBottom: 4 }}
835
- >
836
- {label(k)}
837
- <div style={{ minWidth: 0 }}>{children}</div>
838
- </div>
839
- );
840
-
841
- switch (detail.kind) {
842
- case 'class':
843
- return (
844
- <>
845
- {detail.methods.length > 0 &&
846
- row('methods', detail.methods.map((m, i) => chip(m.name, m.returnType, i)))}
847
- {detail.properties.length > 0 &&
848
- row('props', detail.properties.map((p, i) => chip(p.name, p.type, i)))}
849
- {detail.extends.length > 0 && row('extends', detail.extends.map((e, i) => chip(e, undefined, i)))}
850
- {detail.implements.length > 0 && row('impl', detail.implements.map((e, i) => chip(e, undefined, i)))}
851
- {detail.instantiations.length > 0 &&
852
- row('insts', detail.instantiations.map((i, idx) => chip(i.name, undefined, idx)))}
853
- {detail.references.length > 0 &&
854
- row('refs', detail.references.map((r, idx) => chip(r.name, undefined, idx)))}
855
- </>
856
- );
857
- case 'function':
858
- return (
859
- <>
860
- {detail.parameters.length > 0 &&
861
- row('params', detail.parameters.map((p, i) => chip(p.type, undefined, i)))}
862
- {detail.returnType && row('return', <span>{detail.returnType}</span>)}
863
- {detail.callers.length > 0 &&
864
- row('callers', detail.callers.map((c, i) => chip(c.name, undefined, i)))}
865
- {detail.callees.length > 0 &&
866
- row('callees', detail.callees.map((c, i) => chip(c.name, undefined, i)))}
867
- </>
868
- );
869
- case 'type':
870
- return (
871
- <>
872
- {detail.properties.length > 0 &&
873
- row('props', detail.properties.map((p, i) => chip(p.name, p.type, i)))}
874
- {detail.usedBy.length > 0 &&
875
- row('used by', detail.usedBy.map((u, i) => chip(u.name, undefined, i)))}
876
- {detail.implementors.length > 0 &&
877
- row('impl', detail.implementors.map((e, i) => chip(e, undefined, i)))}
878
- </>
879
- );
880
- case 'module':
881
- return (
882
- <>
883
- {detail.exports.length > 0 &&
884
- row('exports', detail.exports.map((e, i) => chip(e, undefined, i)))}
885
- {detail.imports.length > 0 &&
886
- row('imports', detail.imports.map((i, idx) => chip(i.name, undefined, idx)))}
887
- {detail.symbols.length > 0 &&
888
- row('symbols', detail.symbols.map((s, i) => chip(s, undefined, i)))}
889
- </>
890
- );
891
- case 'external':
892
- return row('source', <span>{detail.label}</span>);
893
- }
894
- }
895
-
896
611
  export function SubsystemComponentGraph(props: SubsystemComponentGraphProps) {
897
612
  const wrapRef = useRef<HTMLDivElement>(null);
898
613
  const [size, setSize] = useState<{ w: number; h: number } | null>(null);
@@ -136,9 +136,6 @@ export interface SubsystemGraphNodeData extends Record<string, unknown> {
136
136
  * lives in that file (spotlighted), false otherwise (dimmed). Absent when
137
137
  * no file is open — render neutrally. */
138
138
  fileMatch?: boolean;
139
- /** False hides the click-to-open file chip under the component name.
140
- * Absent/true renders it (default). */
141
- showFileBadges?: boolean;
142
139
  }
143
140
 
144
141
  export type SubsystemGraphNode = Node<SubsystemGraphNodeData, SubsystemGraphNodeType>;
@@ -2,8 +2,8 @@
2
2
  * Subsystem component/group node + edge renderers.
3
3
  *
4
4
  * Lightweight, purpose-built for the subsystem component graph: a component
5
- * renders its name (kind-tagged, colored by package) plus its symbol/purpose
6
- * and a click-to-open file chip. Groups render as package containers. Clicking
5
+ * renders its name (kind-tagged, colored by package) plus its symbol/purpose.
6
+ * Groups render as package containers. Clicking
7
7
  * a component calls `onSelect` (to open the entry point / file).
8
8
  */
9
9
 
@@ -72,7 +72,6 @@ export function SubsystemComponentNode(props: NodeProps<SubsystemGraphNode>) {
72
72
  // Set while a file is open in the drawer: true → spotlight, false → dim,
73
73
  // absent (no file open) → neutral.
74
74
  const fileMatch = data.fileMatch as boolean | undefined;
75
- const showFileBadges = data.showFileBadges !== false;
76
75
 
77
76
  return (
78
77
  <div
@@ -204,32 +203,6 @@ export function SubsystemComponentNode(props: NodeProps<SubsystemGraphNode>) {
204
203
  </div>
205
204
  )}
206
205
 
207
- {c.file && showFileBadges && (
208
- <div
209
- onClick={(e) => {
210
- e.stopPropagation();
211
- SUBSYSTEM_CALLBACKS.onSelect?.(c.id);
212
- }}
213
- style={{
214
- alignSelf: 'center',
215
- marginTop: 3,
216
- fontSize: theme.fontSizes[0] * 0.78,
217
- fontFamily: theme.fonts.monospace,
218
- color: theme.colors.primary,
219
- border: `1px solid ${theme.colors.border}`,
220
- borderRadius: 4,
221
- padding: '1px 5px',
222
- cursor: 'pointer',
223
- maxWidth: '100%',
224
- overflow: 'hidden',
225
- textOverflow: 'ellipsis',
226
- whiteSpace: 'nowrap',
227
- }}
228
- >
229
- {c.file.split('/').pop()}
230
- </div>
231
- )}
232
-
233
206
  <Handle type="target" position={Position.Left} style={{ opacity: 0 }} />
234
207
  <Handle type="source" position={Position.Right} style={{ opacity: 0 }} />
235
208
  </div>