@principal-ai/subsystems-react 0.24.0 → 0.24.1

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 (40) hide show
  1. package/dist/index.d.ts +7 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/subsystem/ComponentDeclaration.d.ts +3 -1
  6. package/dist/subsystem/ComponentDeclaration.d.ts.map +1 -1
  7. package/dist/subsystem/ComponentDeclaration.js +2 -2
  8. package/dist/subsystem/ComponentDeclaration.js.map +1 -1
  9. package/dist/subsystem/ConstructsCatalog.d.ts +30 -0
  10. package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -0
  11. package/dist/subsystem/ConstructsCatalog.js +349 -0
  12. package/dist/subsystem/ConstructsCatalog.js.map +1 -0
  13. package/dist/subsystem/DiagnosticToggle.d.ts +46 -0
  14. package/dist/subsystem/DiagnosticToggle.d.ts.map +1 -0
  15. package/dist/subsystem/DiagnosticToggle.js +95 -0
  16. package/dist/subsystem/DiagnosticToggle.js.map +1 -0
  17. package/dist/subsystem/IssueList.d.ts +102 -0
  18. package/dist/subsystem/IssueList.d.ts.map +1 -0
  19. package/dist/subsystem/IssueList.js +282 -0
  20. package/dist/subsystem/IssueList.js.map +1 -0
  21. package/dist/subsystem/SubsystemComponentGraph.d.ts +28 -0
  22. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  23. package/dist/subsystem/SubsystemComponentGraph.js +80 -57
  24. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  25. package/dist/subsystem/model.d.ts +13 -2
  26. package/dist/subsystem/model.d.ts.map +1 -1
  27. package/dist/subsystem/model.js +12 -0
  28. package/dist/subsystem/model.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/index.ts +37 -0
  31. package/src/stories/Subsystem/ComponentGraph/Constructs.stories.tsx +287 -0
  32. package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +138 -0
  33. package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +130 -0
  34. package/src/subsystem/ComponentDeclaration.tsx +4 -1
  35. package/src/subsystem/ConstructsCatalog.tsx +644 -0
  36. package/src/subsystem/DiagnosticToggle.tsx +160 -0
  37. package/src/subsystem/IssueList.tsx +488 -0
  38. package/src/subsystem/SubsystemComponentGraph.tsx +118 -36
  39. package/src/subsystem/model.test.ts +34 -0
  40. package/src/subsystem/model.ts +18 -2
@@ -0,0 +1,138 @@
1
+ import '@xyflow/react/dist/style.css';
2
+ import React from 'react';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
+ import {
7
+ SubsystemDiagnosticToggle,
8
+ type SubsystemDiagnosticStatus,
9
+ } from '../../../subsystem/DiagnosticToggle';
10
+ import { components, graphSpecFromEdges } from './fixtures';
11
+
12
+ const meta = {
13
+ title: 'Subsystem/ComponentGraph/Diagnostics',
14
+ component: SubsystemComponentGraph,
15
+ parameters: {
16
+ layout: 'fullscreen',
17
+ },
18
+ decorators: [
19
+ (Story) => (
20
+ <ThemeProvider theme={defaultEditorTheme}>
21
+ <Story />
22
+ </ThemeProvider>
23
+ ),
24
+ ],
25
+ } satisfies Meta<typeof SubsystemComponentGraph>;
26
+
27
+ export default meta;
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ const graphComponents = components([
31
+ ['entry', 'checkoutApi', 'function', 'src/checkout/api.ts', 'pkg:github/you/your-app', 'Handles cart requests.', 'checkoutApi'],
32
+ ['store', 'cartStore', 'store', 'src/checkout/cartStore.ts', 'pkg:github/you/your-app', 'Retained cart state.', 'cartStore'],
33
+ ['stripe', 'Stripe', 'external', '', 'external', undefined, undefined],
34
+ ['caller', 'Web client', 'external', '', 'external', undefined, undefined],
35
+ ]);
36
+
37
+ const graphEdges = graphSpecFromEdges([
38
+ ['caller', 'entry', 'calls'],
39
+ ['entry', 'store', 'writes'],
40
+ ['entry', 'stripe', 'calls'],
41
+ ]);
42
+
43
+ const GRAPH_DESCRIPTION =
44
+ 'A small e-commerce checkout subsystem: an HTTP entry point that writes to retained cart state and calls out to Stripe.';
45
+
46
+ /** Every chip state side by side, for quick visual review. */
47
+ export const States: Story = {
48
+ render: () => {
49
+ const rows: Array<{ label: string; status: SubsystemDiagnosticStatus; issueCount?: number; stale?: boolean; busy?: boolean }> = [
50
+ { label: 'ok', status: 'ok' },
51
+ { label: 'ok (stale)', status: 'ok', stale: true },
52
+ { label: 'issues · 3', status: 'issues', issueCount: 3 },
53
+ { label: 'gaps · 2', status: 'gaps', issueCount: 2 },
54
+ { label: 'unknown (never checked)', status: 'unknown' },
55
+ { label: 'issues (busy)', status: 'issues', issueCount: 3, busy: true },
56
+ ];
57
+ return (
58
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18, padding: 32 }}>
59
+ {rows.map((row) => (
60
+ <div key={row.label} style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
61
+ <span style={{ width: 200, fontFamily: 'monospace', fontSize: 12, opacity: 0.7 }}>
62
+ {row.label}
63
+ </span>
64
+ <SubsystemDiagnosticToggle
65
+ status={row.status}
66
+ issueCount={row.issueCount}
67
+ stale={row.stale}
68
+ busy={row.busy}
69
+ onOpen={() => {}}
70
+ />
71
+ </div>
72
+ ))}
73
+ </div>
74
+ );
75
+ },
76
+ };
77
+
78
+ /** The chip in its real home: the sidebar title row, beside the description toggle. */
79
+ export const GraphClean: Story = {
80
+ render: () => (
81
+ <div style={{ width: '100%', height: '100vh' }}>
82
+ <SubsystemComponentGraph
83
+ components={graphComponents}
84
+ relations={graphEdges.relations}
85
+ walkthroughs={graphEdges.walkthroughs}
86
+ title="Checkout"
87
+ description={GRAPH_DESCRIPTION}
88
+ diagnostic={{ status: 'ok', onOpen: () => {} }}
89
+ />
90
+ </div>
91
+ ),
92
+ };
93
+
94
+ export const GraphWithIssues: Story = {
95
+ render: () => (
96
+ <div style={{ width: '100%', height: '100vh' }}>
97
+ <SubsystemComponentGraph
98
+ components={graphComponents}
99
+ relations={graphEdges.relations}
100
+ walkthroughs={graphEdges.walkthroughs}
101
+ title="Checkout"
102
+ description={GRAPH_DESCRIPTION}
103
+ diagnostic={{ status: 'issues', issueCount: 3, onOpen: () => {} }}
104
+ />
105
+ </div>
106
+ ),
107
+ };
108
+
109
+ /** Stale report: the color stays, a hollow ring marks that inputs changed. */
110
+ export const GraphStale: Story = {
111
+ render: () => (
112
+ <div style={{ width: '100%', height: '100vh' }}>
113
+ <SubsystemComponentGraph
114
+ components={graphComponents}
115
+ relations={graphEdges.relations}
116
+ walkthroughs={graphEdges.walkthroughs}
117
+ title="Checkout"
118
+ description={GRAPH_DESCRIPTION}
119
+ diagnostic={{ status: 'issues', issueCount: 3, stale: true, onOpen: () => {} }}
120
+ />
121
+ </div>
122
+ ),
123
+ };
124
+
125
+ /** No title/description — the chip still anchors the title row at the right. */
126
+ export const GraphChipOnly: Story = {
127
+ render: () => (
128
+ <div style={{ width: '100%', height: '100vh' }}>
129
+ <SubsystemComponentGraph
130
+ components={graphComponents}
131
+ relations={graphEdges.relations}
132
+ walkthroughs={graphEdges.walkthroughs}
133
+ title="Checkout"
134
+ diagnostic={{ status: 'gaps', issueCount: 2, onOpen: () => {} }}
135
+ />
136
+ </div>
137
+ ),
138
+ };
@@ -0,0 +1,130 @@
1
+ import '@xyflow/react/dist/style.css';
2
+ import React from 'react';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
+ import { SubsystemIssueList, type SubsystemIssue } from '../../../subsystem/IssueList';
7
+ import { components, graphSpecFromEdges } from './fixtures';
8
+
9
+ const meta = {
10
+ title: 'Subsystem/ComponentGraph/Issues',
11
+ component: SubsystemComponentGraph,
12
+ parameters: {
13
+ layout: 'fullscreen',
14
+ },
15
+ decorators: [
16
+ (Story) => (
17
+ <ThemeProvider theme={defaultEditorTheme}>
18
+ <Story />
19
+ </ThemeProvider>
20
+ ),
21
+ ],
22
+ } satisfies Meta<typeof SubsystemComponentGraph>;
23
+
24
+ export default meta;
25
+ type Story = StoryObj<typeof meta>;
26
+
27
+ const ISSUES: SubsystemIssue[] = [
28
+ {
29
+ id: 'i1',
30
+ severity: 'error',
31
+ kind: 'missing_file',
32
+ message: 'File src/checkout/cartStore.ts is not present on disk (repo pkg:github/you/your-app).',
33
+ target: { kind: 'component', id: 'store', label: 'cartStore' },
34
+ fix: { label: 'Use graphify file' },
35
+ },
36
+ {
37
+ id: 'i2',
38
+ severity: 'error',
39
+ kind: 'construct_mismatch',
40
+ message: 'Claimed function but graphify infers class.',
41
+ target: { kind: 'component', id: 'entry', label: 'checkoutApi' },
42
+ },
43
+ {
44
+ id: 'i3',
45
+ severity: 'info',
46
+ kind: 'signature_unconfirmed',
47
+ message: 'Named parameter types are not present in the graphify cache.',
48
+ target: { kind: 'component', id: 'entry', label: 'checkoutApi' },
49
+ },
50
+ {
51
+ id: 'i4',
52
+ severity: 'error',
53
+ kind: 'topology_broken_endpoint',
54
+ message: 'Relation endpoint "store" does not resolve to a component.',
55
+ target: { kind: 'relation', id: 'r1', label: 'checkoutApi → cartStore', detail: 'writes' },
56
+ },
57
+ {
58
+ id: 'i5',
59
+ severity: 'warn',
60
+ kind: 'boundary_module_file_mismatch',
61
+ message: 'Module "src/checkout" contains a file outside its declared root.',
62
+ target: { kind: 'module', id: 'src/checkout', label: 'src/checkout' },
63
+ },
64
+ {
65
+ id: 'i6',
66
+ severity: 'info',
67
+ kind: 'walkthrough',
68
+ message: 'Step 2 references a line that moved (was :42).',
69
+ target: { kind: 'walkthrough', id: 'flow-1', label: 'Checkout', detail: 'step 2' },
70
+ },
71
+ {
72
+ id: 'i7',
73
+ severity: 'warn',
74
+ kind: 'boundary_process_nest_disagree',
75
+ message: 'Component is nested in process "api" but Graphify places it outside.',
76
+ target: { kind: 'module', id: 'api', label: 'api' },
77
+ },
78
+ ];
79
+
80
+ const graphComponents = components([
81
+ ['entry', 'checkoutApi', 'function', 'src/checkout/api.ts', 'pkg:github/you/your-app', 'Handles cart requests.', 'checkoutApi'],
82
+ ['store', 'cartStore', 'store', 'src/checkout/cartStore.ts', 'pkg:github/you/your-app', 'Retained cart state.', 'cartStore'],
83
+ ['stripe', 'Stripe', 'external', '', 'external', undefined, undefined],
84
+ ]);
85
+
86
+ const graphEdges = graphSpecFromEdges([
87
+ ['entry', 'store', 'writes'],
88
+ ['entry', 'stripe', 'calls'],
89
+ ]);
90
+
91
+ /** The catalogue, grouped by verification layer. */
92
+ export const List: Story = {
93
+ render: () => (
94
+ <div style={{ display: 'flex', flexDirection: 'column', width: 380, height: '100vh', borderRight: '1px solid #333' }}>
95
+ <SubsystemIssueList
96
+ issues={ISSUES}
97
+ onSelectIssue={() => {}}
98
+ onApplyFix={() => {}}
99
+ />
100
+ </div>
101
+ ),
102
+ };
103
+
104
+ /** All four layers clean — the happy state. */
105
+ export const AllGood: Story = {
106
+ render: () => (
107
+ <div style={{ display: 'flex', flexDirection: 'column', width: 380, height: '100vh', borderRight: '1px solid #333' }}>
108
+ <SubsystemIssueList issues={[]} />
109
+ </div>
110
+ ),
111
+ };
112
+
113
+ /** In place: diagnostics active, so the sidebar bottom panel is the issue list. */
114
+ export const GraphWithIssues: Story = {
115
+ render: () => (
116
+ <div style={{ width: '100%', height: '100vh' }}>
117
+ <SubsystemComponentGraph
118
+ components={graphComponents}
119
+ relations={graphEdges.relations}
120
+ walkthroughs={graphEdges.walkthroughs}
121
+ title="Checkout"
122
+ description="A small e-commerce checkout subsystem."
123
+ diagnostic={{ status: 'issues', issueCount: 5, onOpen: () => {} }}
124
+ issues={ISSUES}
125
+ onSelectIssue={() => {}}
126
+ onApplyIssueFix={() => {}}
127
+ />
128
+ </div>
129
+ ),
130
+ };
@@ -118,6 +118,8 @@ export interface ComponentDeclarationProps {
118
118
  onVerify?: (componentId: string) => void;
119
119
  /** Live verification status for the selected component. */
120
120
  verification?: ComponentVerificationState | null;
121
+ /** Start with the file path row visible (catalog / source-first views). */
122
+ defaultShowFile?: boolean;
121
123
  }
122
124
 
123
125
  function verificationSummary(
@@ -256,11 +258,12 @@ export function ComponentDeclaration({
256
258
  maxWidth,
257
259
  onVerify,
258
260
  verification,
261
+ defaultShowFile = false,
259
262
  }: ComponentDeclarationProps) {
260
263
  const { theme, mode } = useTheme();
261
264
  const pierreSyntaxTheme = resolvePierreSyntaxThemeName(mode);
262
265
  const [fileHovered, setFileHovered] = useState(false);
263
- const [showFile, setShowFile] = useState(false);
266
+ const [showFile, setShowFile] = useState(defaultShowFile);
264
267
  const [showPurpose, setShowPurpose] = useState(false);
265
268
  const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
266
269
  const color = componentColor(component, pierreSyntaxTheme);