@principal-ai/subsystems-react 0.51.0 → 0.51.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.
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- 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/pierre/PierreTrailCodeView.js +44 -21
- package/dist/pierre/PierreTrailCodeView.js.map +1 -1
- package/dist/stories/Subsystem/C4Graph/c4ProposedElements.fixture.d.ts +493 -0
- package/dist/stories/Subsystem/C4Graph/c4ProposedElements.fixture.d.ts.map +1 -0
- package/dist/stories/Subsystem/C4Graph/c4ProposedElements.fixture.js +329 -0
- package/dist/stories/Subsystem/C4Graph/c4ProposedElements.fixture.js.map +1 -0
- package/dist/subsystem/C4Graph.d.ts +2 -2
- package/dist/subsystem/C4Graph.d.ts.map +1 -1
- package/dist/subsystem/C4Graph.js +25 -16
- package/dist/subsystem/C4Graph.js.map +1 -1
- package/dist/subsystem/C4NodeCard.d.ts +71 -36
- package/dist/subsystem/C4NodeCard.d.ts.map +1 -1
- package/dist/subsystem/C4NodeCard.js +88 -94
- package/dist/subsystem/C4NodeCard.js.map +1 -1
- package/dist/subsystem/FileDrawer.d.ts.map +1 -1
- package/dist/subsystem/FileDrawer.js +20 -21
- package/dist/subsystem/FileDrawer.js.map +1 -1
- package/dist/subsystem/IssueList.js +1 -1
- package/dist/subsystem/IssueList.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +13 -4
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/c4.d.ts +272 -0
- package/dist/subsystem/c4.d.ts.map +1 -0
- package/dist/subsystem/c4.js +322 -0
- package/dist/subsystem/c4.js.map +1 -0
- package/dist/subsystem/c4Evidence.d.ts +143 -0
- package/dist/subsystem/c4Evidence.d.ts.map +1 -0
- package/dist/subsystem/c4Evidence.js +240 -0
- package/dist/subsystem/c4Evidence.js.map +1 -0
- package/dist/subsystem/model.d.ts +2 -6
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +26 -28
- package/src/pierre/PierreTrailCodeView.tsx +49 -21
- package/src/stories/Subsystem/C4Graph/C4NodeGallery.stories.tsx +167 -79
- package/src/stories/Subsystem/C4Graph/ProposedElements.stories.tsx +293 -0
- package/src/stories/Subsystem/C4Graph/c4ProposedElements.fixture.ts +366 -0
- package/src/stories/Subsystem/ComponentGraph/IssueOverlay.stories.tsx +1 -1
- package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +1 -1
- package/src/subsystem/C4Graph.tsx +39 -24
- package/src/subsystem/C4NodeCard.test.ts +169 -64
- package/src/subsystem/C4NodeCard.tsx +102 -108
- package/src/subsystem/FileDrawer.tsx +32 -34
- package/src/subsystem/IssueList.tsx +1 -1
- package/src/subsystem/SubsystemComponentGraph.tsx +13 -5
- package/src/subsystem/c4.test.ts +573 -0
- package/src/subsystem/c4.ts +558 -0
- package/src/subsystem/c4Evidence.test.ts +386 -0
- package/src/subsystem/c4Evidence.ts +329 -0
- package/src/subsystem/model.ts +2 -6
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts +0 -95
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts.map +0 -1
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js +0 -340
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js.map +0 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts +0 -7
- package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts.map +0 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js +0 -7335
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +0 -1
- package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts +0 -2
- package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts.map +0 -1
- package/dist/stories/Subsystem/C4Graph/generateFixture.js +0 -145
- package/dist/stories/Subsystem/C4Graph/generateFixture.js.map +0 -1
- package/dist/subsystem/c4Associations.d.ts +0 -186
- package/dist/subsystem/c4Associations.d.ts.map +0 -1
- package/dist/subsystem/c4Associations.js +0 -284
- package/dist/subsystem/c4Associations.js.map +0 -1
- package/dist/subsystem/toC4.d.ts +0 -214
- package/dist/subsystem/toC4.d.ts.map +0 -1
- package/dist/subsystem/toC4.js +0 -282
- package/dist/subsystem/toC4.js.map +0 -1
- package/src/stories/Subsystem/C4Graph/C4Associations.stories.tsx +0 -273
- package/src/stories/Subsystem/C4Graph/C4Container.stories.tsx +0 -101
- package/src/stories/Subsystem/C4Graph/c4Associations.fixture.ts +0 -344
- package/src/stories/Subsystem/C4Graph/c4Fixture.ts +0 -7339
- package/src/stories/Subsystem/C4Graph/generateFixture.ts +0 -161
- package/src/subsystem/c4Associations.test.ts +0 -484
- package/src/subsystem/c4Associations.ts +0 -398
- package/src/subsystem/toC4.test.ts +0 -114
- package/src/subsystem/toC4.ts +0 -478
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A proposed C4 element set — what an agent's output looks like.
|
|
3
|
+
*
|
|
4
|
+
* Hand-authored on purpose. The previous fixture was *generated* from live
|
|
5
|
+
* store data by converting each `process` value into a container, which is the
|
|
6
|
+
* thing we no longer believe: `process` says where code runs, not which runs
|
|
7
|
+
* of code are one deployable unit.
|
|
8
|
+
*
|
|
9
|
+
* Everything below is a claim, and each carries a `rationale` saying why. All
|
|
10
|
+
* of it is `proposed` — accepting is a human's decision.
|
|
11
|
+
*
|
|
12
|
+
* Three of these are deliberately wrong, and `c4OpenQuestions` surfaces them:
|
|
13
|
+
* `container:shared-ui` is a library pretending to be a deployable unit,
|
|
14
|
+
* `container:in-memory-state` is process-lifetime state pretending to be a
|
|
15
|
+
* container, and `external:opencode-db` is a boundary two models disagree on.
|
|
16
|
+
*/
|
|
17
|
+
import type { C4Element } from '../../../subsystem/c4';
|
|
18
|
+
|
|
19
|
+
const author = 'c4-proposer';
|
|
20
|
+
|
|
21
|
+
export const c4ProposedElements: C4Element[] = [
|
|
22
|
+
// --- deployable units ----------------------------------------------------
|
|
23
|
+
{
|
|
24
|
+
id: 'container:studio-host',
|
|
25
|
+
kind: 'container',
|
|
26
|
+
label: 'Subsystem Studio — host',
|
|
27
|
+
derivedFrom: ['subsystems-studio/host'],
|
|
28
|
+
// Only the aliases with no component of their own. The store I/O and the
|
|
29
|
+
// audit runner name their own members below, and `buildC4Model` rolls
|
|
30
|
+
// those up into this container rather than counting them twice.
|
|
31
|
+
members: [
|
|
32
|
+
'resolve-root', 'http-put', 'http-propose', 'tab-registry',
|
|
33
|
+
'live-feed-store', 'maintain-probe-registry', 'run-store',
|
|
34
|
+
'graphify-store', 'proposal-create', 'proposal-accept',
|
|
35
|
+
'maintain-orchestrator', 'run-maintain-agent', 'ensure-graphify',
|
|
36
|
+
'close-tab', 'open-tab',
|
|
37
|
+
],
|
|
38
|
+
containerKind: 'application',
|
|
39
|
+
technology: 'Bun + Electrobun host',
|
|
40
|
+
description:
|
|
41
|
+
'Owns the model store on disk, runs graphify-backed verification, and serves the renderer over RPC.',
|
|
42
|
+
state: 'proposed',
|
|
43
|
+
rationale: 'The Electron main process, holding 113 components in the live corpus.',
|
|
44
|
+
author,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'container:legacy-host',
|
|
48
|
+
kind: 'container',
|
|
49
|
+
label: 'Principal Studio — host',
|
|
50
|
+
// The other half of the merge question. `subsystems-studio/host` (113
|
|
51
|
+
// components) and `principal-studio/host` (1) are either one process or
|
|
52
|
+
// two, and no amount of reading the keys decides it — `mergeElements`
|
|
53
|
+
// exists for exactly this, and the story shows the button.
|
|
54
|
+
derivedFrom: ['principal-studio/host'],
|
|
55
|
+
members: ['register-roots'],
|
|
56
|
+
containerKind: 'application',
|
|
57
|
+
technology: 'Electrobun host',
|
|
58
|
+
description: "The same Electron main process under the app's former name.",
|
|
59
|
+
state: 'proposed',
|
|
60
|
+
rationale:
|
|
61
|
+
'One member, and the same process as container:studio-host. Merged or kept separate, one deployable unit under two app names or two units?',
|
|
62
|
+
author,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'container:studio-renderer',
|
|
66
|
+
kind: 'container',
|
|
67
|
+
label: 'Subsystem Studio — renderer',
|
|
68
|
+
// `file-panel` is not repeated here: component:file-viewer owns it, and
|
|
69
|
+
// the build rolls it up. An alias belongs to exactly one element.
|
|
70
|
+
derivedFrom: ['subsystems-studio/renderer'],
|
|
71
|
+
members: [
|
|
72
|
+
'subsystems-view', 'model-view', 'regular-audit-view', 'list-view',
|
|
73
|
+
'rpc-bridge', 'reload-subs', 'regular-audit-subscribers',
|
|
74
|
+
'tab-strip', 'graph-view', 'detail-graph', 'is-model-viewed',
|
|
75
|
+
'preloadHighlighter', 'SharedHighlighter', 'CodeView',
|
|
76
|
+
],
|
|
77
|
+
containerKind: 'application',
|
|
78
|
+
technology: 'React 19 in an Electron renderer',
|
|
79
|
+
description: 'Renders subsystem models and talks to the host over the Electrobun RPC bridge.',
|
|
80
|
+
state: 'proposed',
|
|
81
|
+
rationale: 'The Electron renderer process, holding 41 components in the live corpus.',
|
|
82
|
+
author,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'container:legacy-renderer',
|
|
86
|
+
kind: 'container',
|
|
87
|
+
label: 'Principal Studio — renderer',
|
|
88
|
+
// The other half of the renderer merge question, mirroring legacy-host.
|
|
89
|
+
derivedFrom: ['principal-studio/renderer'],
|
|
90
|
+
members: ['app-shell'],
|
|
91
|
+
containerKind: 'application',
|
|
92
|
+
technology: 'React 19',
|
|
93
|
+
description: "The same React bundle under the app's former name.",
|
|
94
|
+
state: 'proposed',
|
|
95
|
+
rationale:
|
|
96
|
+
'One member, and the same process as container:studio-renderer. One deployable unit under two app names or two units?',
|
|
97
|
+
author,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'container:cli',
|
|
101
|
+
kind: 'container',
|
|
102
|
+
label: 'Subsystem Modeling CLI',
|
|
103
|
+
derivedFrom: ['principal-studio-cli'],
|
|
104
|
+
members: ['cli-create'],
|
|
105
|
+
containerKind: 'application',
|
|
106
|
+
technology: 'Node',
|
|
107
|
+
description: 'Creates and updates models from the terminal.',
|
|
108
|
+
state: 'proposed',
|
|
109
|
+
rationale: 'A standalone binary is a deployable unit even with one command.',
|
|
110
|
+
author,
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
// --- the shape questions -------------------------------------------------
|
|
114
|
+
{
|
|
115
|
+
id: 'container:shared-ui',
|
|
116
|
+
kind: 'container',
|
|
117
|
+
label: 'subsystems-react (proposed container?)',
|
|
118
|
+
members: ['measured-dims'],
|
|
119
|
+
containerKind: 'application',
|
|
120
|
+
technology: 'React',
|
|
121
|
+
description: 'Shared graph UI, published as an npm package.',
|
|
122
|
+
state: 'proposed',
|
|
123
|
+
// Proposed as a container so the question is visible. There is no `library`
|
|
124
|
+
// kind to fall back on: c4model says a JAR/assembly/module "typically" is
|
|
125
|
+
// not an element at all, so a published package has to earn its box or be
|
|
126
|
+
// demoted into the containers that import it.
|
|
127
|
+
rationale:
|
|
128
|
+
'MEMBER OF THE COMPANION LIBRARY, not a runtime unit — no process of its own, imported by both renderers. Expected to be rejected or demoted.',
|
|
129
|
+
author,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'container:model-store',
|
|
133
|
+
kind: 'container',
|
|
134
|
+
label: 'Subsystem model store',
|
|
135
|
+
members: ['model-disk-store', 'proposals-store'],
|
|
136
|
+
containerKind: 'data-store',
|
|
137
|
+
technology: 'JSON files under ~/.principal',
|
|
138
|
+
description: 'Every stored model and the correction queue, on local disk.',
|
|
139
|
+
state: 'proposed',
|
|
140
|
+
// The open Q2 decision: is this one C4 data-store container, or internals
|
|
141
|
+
// of the host that owns them?
|
|
142
|
+
rationale:
|
|
143
|
+
'Disk-backed and shared across the host and the CLI, which reads it. Whether C4 wants one data-store container or internals of the host is unresolved.',
|
|
144
|
+
author,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'container:in-memory-state',
|
|
148
|
+
kind: 'container',
|
|
149
|
+
label: 'In-memory renderer state (proposed container?)',
|
|
150
|
+
// Two aliases nothing else claims. Rejecting this element is what makes
|
|
151
|
+
// them reappear in `unmapped` — which is the point: rejecting an element
|
|
152
|
+
// orphans whatever was in it, and the build says so out loud.
|
|
153
|
+
members: ['renderer-probe-cache', 'tab-order-cache'],
|
|
154
|
+
containerKind: 'application',
|
|
155
|
+
// Required by the type on every container, and empty on purpose: this is
|
|
156
|
+
// the shape the C4 notation forbids (process-lifetime state has no
|
|
157
|
+
// technology), and `summarizeElements` reports exactly this gap.
|
|
158
|
+
technology: '',
|
|
159
|
+
description: 'Module-level Sets and Maps that do not outlive the process.',
|
|
160
|
+
state: 'proposed',
|
|
161
|
+
rationale:
|
|
162
|
+
'Process-lifetime state, not durable storage. Belongs inside the renderer container as components, not beside it as its own container. Expected to be rejected.',
|
|
163
|
+
author,
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// --- outside the boundary ----------------------------------------------
|
|
167
|
+
{
|
|
168
|
+
id: 'external:opencode2',
|
|
169
|
+
kind: 'external-system',
|
|
170
|
+
label: 'OpenCode v2 service',
|
|
171
|
+
members: ['opencode-v2-service'],
|
|
172
|
+
technology: 'HTTP',
|
|
173
|
+
description: 'Runs the maintain agent sessions this model is edited by.',
|
|
174
|
+
state: 'proposed',
|
|
175
|
+
rationale: 'Another system we call out to — a C4 software system, not one of our containers.',
|
|
176
|
+
author,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: 'external:gists',
|
|
180
|
+
kind: 'external-system',
|
|
181
|
+
label: 'GitHub Gists API',
|
|
182
|
+
members: ['github-gists-api'],
|
|
183
|
+
technology: 'REST',
|
|
184
|
+
description: 'Publishes the portable model JSON as a gist.',
|
|
185
|
+
state: 'proposed',
|
|
186
|
+
author,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: 'external:opencode-db',
|
|
190
|
+
kind: 'external-system',
|
|
191
|
+
label: 'opencode.db',
|
|
192
|
+
members: ['session-v2', 'event', 'session-message'],
|
|
193
|
+
// No technology field at all: C4 makes technology optional for an
|
|
194
|
+
// external system, and for a SQLite file the honest answer is "on disk".
|
|
195
|
+
description: 'Agent session transcripts, read by the host to build the timeline.',
|
|
196
|
+
state: 'proposed',
|
|
197
|
+
// Two models disagree about this: one claims these tables inside our
|
|
198
|
+
// system, another marks them external. Flagged rather than resolved.
|
|
199
|
+
rationale:
|
|
200
|
+
'CONFLICT — one stored model claims these tables inside the system, another marks the same tables external. Needs the user.',
|
|
201
|
+
author,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'person:maintainer',
|
|
205
|
+
kind: 'person',
|
|
206
|
+
label: 'Maintain operator',
|
|
207
|
+
members: ['maintain-agent'],
|
|
208
|
+
description: 'Reviews and accepts the correction proposals this subsystem model accumulates.',
|
|
209
|
+
state: 'proposed',
|
|
210
|
+
rationale:
|
|
211
|
+
'C4 Person — no technology, by the notation. The only actor in the corpus; entityKind was never set on the underlying custom_entity.',
|
|
212
|
+
author,
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
// --- component level ----------------------------------------------------
|
|
216
|
+
{
|
|
217
|
+
id: 'component:boundary-layout',
|
|
218
|
+
kind: 'component',
|
|
219
|
+
label: 'Boundary layout builder',
|
|
220
|
+
members: ['build-boundary-layout', 'nest-groups'],
|
|
221
|
+
// Naming `container:shared-ui` as the parent is itself part of the open
|
|
222
|
+
// question: if that container is rejected, this component has no home and
|
|
223
|
+
// `buildC4Model` reports `unknown_container`.
|
|
224
|
+
container: 'container:shared-ui',
|
|
225
|
+
technology: 'React + ELK',
|
|
226
|
+
description: 'Turns module and process claims into nested compound frames.',
|
|
227
|
+
state: 'proposed',
|
|
228
|
+
author,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: 'component:file-viewer',
|
|
232
|
+
kind: 'component',
|
|
233
|
+
label: 'Pierre file viewer',
|
|
234
|
+
members: ['file-panel'],
|
|
235
|
+
container: 'container:studio-renderer',
|
|
236
|
+
technology: 'React',
|
|
237
|
+
description: 'Opens the source slice a trail step points at.',
|
|
238
|
+
state: 'proposed',
|
|
239
|
+
author,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'component:model-store-io',
|
|
243
|
+
kind: 'component',
|
|
244
|
+
label: 'Model store I/O',
|
|
245
|
+
members: ['store-create', 'store-list', 'read-file', 'store-file'],
|
|
246
|
+
container: 'container:studio-host',
|
|
247
|
+
technology: 'Bun fs',
|
|
248
|
+
description: 'Reads and writes model JSON under ~/.principal.',
|
|
249
|
+
state: 'proposed',
|
|
250
|
+
author,
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: 'component:audit-runner',
|
|
254
|
+
kind: 'component',
|
|
255
|
+
label: 'Audit runner',
|
|
256
|
+
members: ['audit-model', 'verify-files'],
|
|
257
|
+
// Deliberately dangling: points at a container that is not in this set, so
|
|
258
|
+
// the story shows what `unknown_container` looks like.
|
|
259
|
+
container: 'container:verifier',
|
|
260
|
+
technology: 'Bun',
|
|
261
|
+
description: 'Verifies every component claim in a model.',
|
|
262
|
+
state: 'proposed',
|
|
263
|
+
rationale: 'Named a container that does not exist yet — shows the build problem report.',
|
|
264
|
+
author,
|
|
265
|
+
},
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* A small document the elements above can be drawn against: the member aliases
|
|
270
|
+
* resolved, plus one trail so there is a line to draw.
|
|
271
|
+
*
|
|
272
|
+
* Only members named by an element appear. A component nobody claimed is
|
|
273
|
+
* deliberately absent — `buildC4Model` reports those as `unmapped` instead of
|
|
274
|
+
* inventing a home for them.
|
|
275
|
+
*/
|
|
276
|
+
export const c4FixtureDocument = {
|
|
277
|
+
components: [
|
|
278
|
+
{ alias: 'store-create', name: 'createSubsystemModel', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-store.ts' },
|
|
279
|
+
{ alias: 'store-list', name: 'listSubsystemModels', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-store.ts' },
|
|
280
|
+
{ alias: 'verify-files', name: 'verifyModelFiles', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-store.ts' },
|
|
281
|
+
{ alias: 'resolve-root', name: 'resolveRepoRootForComponent', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-store.ts' },
|
|
282
|
+
{ alias: 'audit-model', name: 'auditSubsystemModel', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/verify-subsystem-component.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/verify-subsystem-component.ts' },
|
|
283
|
+
{ alias: 'http-put', name: 'handleSubsystemModelRequest', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/http-server.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/http-server.ts' },
|
|
284
|
+
{ alias: 'http-propose', name: 'postSubsystemModelProposal', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/proposal-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/proposal-store.ts' },
|
|
285
|
+
{ alias: 'register-roots', name: 'registerRepoRoots', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/alexandria.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/alexandria.ts' },
|
|
286
|
+
{ alias: 'tab-registry', name: 'tabs', construct: 'store' as const, file: 'packages/subsystems-studio/src/bun/index.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/index.ts', declaration: { kind: 'store' as const, storage: 'memory' as const, properties: [] } },
|
|
287
|
+
{ alias: 'live-feed-store', name: 'OpencodeLiveFeedState', construct: 'store' as const, file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/opencode-v2-live.ts', declaration: { kind: 'store' as const, storage: 'memory' as const, properties: [] } },
|
|
288
|
+
{ alias: 'maintain-probe-registry', name: 'MaintainerProbeRegistry', construct: 'store' as const, file: 'packages/subsystems-studio/src/bun/maintainer-probe.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintainer-probe.ts', declaration: { kind: 'store' as const, storage: 'memory' as const, properties: [] } },
|
|
289
|
+
{ alias: 'run-store', name: 'SubsystemModelRunStore', construct: 'store' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-runs.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-runs.ts', declaration: { kind: 'store' as const, storage: 'disk' as const, properties: [] } },
|
|
290
|
+
{ alias: 'graphify-store', name: 'ensureCaches', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/graphify-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/graphify-store.ts' },
|
|
291
|
+
{ alias: 'proposal-create', name: 'createSubsystemModelProposal', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/proposal-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/proposal-store.ts' },
|
|
292
|
+
{ alias: 'proposal-accept', name: 'acceptSubsystemModelProposal', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/proposal-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/proposal-store.ts' },
|
|
293
|
+
{ alias: 'maintain-orchestrator', name: 'maintainSubsystemModel', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintain-model.ts' },
|
|
294
|
+
{ alias: 'run-maintain-agent', name: 'runMaintainAgent', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintain-model.ts' },
|
|
295
|
+
{ alias: 'ensure-graphify', name: 'ensureCaches', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/graphify-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/graphify-store.ts' },
|
|
296
|
+
{ alias: 'store-file', name: 'writeFile', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/subsystem-model-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/subsystem-model-store.ts' },
|
|
297
|
+
{ alias: 'read-file', name: 'readSubsystemFile', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/index.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/index.ts' },
|
|
298
|
+
{ alias: 'close-tab', name: 'closeTabById', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/index.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/index.ts' },
|
|
299
|
+
{ alias: 'open-tab', name: 'openSubsystemModelTab', construct: 'function' as const, file: 'packages/subsystems-studio/src/bun/index.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/index.ts' },
|
|
300
|
+
|
|
301
|
+
{ alias: 'subsystems-view', name: 'SubsystemsModelsView', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx' },
|
|
302
|
+
{ alias: 'model-view', name: 'SubsystemModelView', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx' },
|
|
303
|
+
{ alias: 'regular-audit-view', name: 'RegularAuditView', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx' },
|
|
304
|
+
{ alias: 'list-view', name: 'listView', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx' },
|
|
305
|
+
{ alias: 'file-panel', name: 'FilePanel', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx' },
|
|
306
|
+
{ alias: 'rpc-bridge', name: 'electrobun', construct: 'store' as const, file: 'packages/subsystems-studio/src/mainview/rpc.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/rpc.ts', declaration: { kind: 'store' as const, properties: [] } },
|
|
307
|
+
{ alias: 'reload-subs', name: 'reloadSubscribers', construct: 'store' as const, file: 'packages/subsystems-studio/src/mainview/rpc.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/rpc.ts', declaration: { kind: 'store' as const, properties: [] } },
|
|
308
|
+
{ alias: 'regular-audit-subscribers', name: 'regularAuditChangeSubscribers', construct: 'store' as const, file: 'packages/subsystems-studio/src/mainview/rpc.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/rpc.ts', declaration: { kind: 'store' as const, properties: [] } },
|
|
309
|
+
{ alias: 'app-shell', name: 'App', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/App.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/App.tsx' },
|
|
310
|
+
{ alias: 'tab-strip', name: 'TabStrip', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/components/TabStrip.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/components/TabStrip.tsx' },
|
|
311
|
+
{ alias: 'graph-view', name: 'SubsystemComponentGraph', construct: 'function' as const, file: 'packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx' },
|
|
312
|
+
{ alias: 'detail-graph', name: 'DetailGraph', construct: 'function' as const, file: 'packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx' },
|
|
313
|
+
{ alias: 'is-model-viewed', name: 'isModelViewed', construct: 'function' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx' },
|
|
314
|
+
{ alias: 'preloadHighlighter', name: 'preloadHighlighter', construct: 'external' as const, file: '', purl: 'pkg:npm/@pierre/diffs' },
|
|
315
|
+
{ alias: 'SharedHighlighter', name: 'SharedHighlighter', construct: 'external' as const, file: '', purl: 'pkg:npm/@pierre/diffs' },
|
|
316
|
+
{ alias: 'CodeView', name: 'CodeView', construct: 'external' as const, file: '', purl: 'pkg:npm/@pierre/diffs' },
|
|
317
|
+
|
|
318
|
+
{ alias: 'cli-create', name: 'create', construct: 'function' as const, file: 'packages/principal-studio-cli/src/commands/subsystem-model.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/principal-studio-cli/src/commands/subsystem-model.ts' },
|
|
319
|
+
|
|
320
|
+
{ alias: 'nest-groups', name: 'nestCompoundGroups', construct: 'function' as const, file: 'packages/subsystems-react/src/utils/elkLayout.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-react/src/utils/elkLayout.ts' },
|
|
321
|
+
{ alias: 'build-boundary-layout', name: 'buildBoundaryLayoutGroups', construct: 'function' as const, file: 'packages/subsystems-react/src/subsystem/model.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-react/src/subsystem/model.ts' },
|
|
322
|
+
{ alias: 'measured-dims', name: 'measuredDimsRef', construct: 'store' as const, file: 'packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-react/src/subsystem/SubsystemComponentGraph.tsx', declaration: { kind: 'store' as const, properties: [] } },
|
|
323
|
+
|
|
324
|
+
{ alias: 'model-disk-store', name: '~/.principal/subsystem-models', construct: 'store' as const, file: '', purl: 'external:file:~/.principal/subsystem-models', declaration: { kind: 'store' as const, storage: 'disk' as const, properties: [] } },
|
|
325
|
+
{ alias: 'proposals-store', name: 'SubsystemModelProposalStore', construct: 'store' as const, file: 'packages/subsystems-studio/src/bun/proposal-store.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/proposal-store.ts', declaration: { kind: 'store' as const, storage: 'disk' as const, properties: [] } },
|
|
326
|
+
|
|
327
|
+
{ alias: 'opencode-v2-service', name: 'OpenCode v2 service', construct: 'external' as const, file: '', purl: 'external:opencode/v2-service' },
|
|
328
|
+
{ alias: 'github-gists-api', name: 'GitHub Gists API', construct: 'external' as const, file: '', purl: 'external:api.github.com/gists' },
|
|
329
|
+
{ alias: 'session-v2', name: 'session_v2', construct: 'external' as const, file: '', purl: 'external:opencode.db/session-v2' },
|
|
330
|
+
{ alias: 'event', name: 'event', construct: 'external' as const, file: '', purl: 'external:opencode.db/event' },
|
|
331
|
+
{ alias: 'session-message', name: 'session_message', construct: 'external' as const, file: '', purl: 'external:opencode.db/session-message' },
|
|
332
|
+
{ alias: 'renderer-probe-cache', name: 'rendererProbeCache', construct: 'store' as const, file: 'packages/subsystems-studio/src/mainview/rpc.ts', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/rpc.ts', declaration: { kind: 'store' as const, storage: 'memory' as const, properties: [] } },
|
|
333
|
+
{ alias: 'tab-order-cache', name: 'tabOrderCache', construct: 'store' as const, file: 'packages/subsystems-studio/src/mainview/components/TabStrip.tsx', purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/components/TabStrip.tsx', declaration: { kind: 'store' as const, storage: 'memory' as const, properties: [] } },
|
|
334
|
+
|
|
335
|
+
{ alias: 'maintain-agent', name: 'Maintenance agent (OpenCode) session', construct: 'custom_entity' as const, file: '', purl: 'external' },
|
|
336
|
+
],
|
|
337
|
+
trails: [
|
|
338
|
+
{
|
|
339
|
+
id: 'tl-audit',
|
|
340
|
+
title: 'Run a dry-run audit from the Audit button',
|
|
341
|
+
steps: [
|
|
342
|
+
{ from: 'model-view', to: 'audit-model', mechanism: 'calls' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx', line: 443, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelView.tsx', symbol: 'SubsystemModelView' },
|
|
343
|
+
{ from: 'audit-model', to: 'model-disk-store', mechanism: 'writes' as const, file: 'packages/subsystems-studio/src/bun/verify-subsystem-component.ts', line: 950, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/verify-subsystem-component.ts', symbol: 'auditSubsystemModel' },
|
|
344
|
+
{ from: 'subsystems-view', to: 'model-view', mechanism: 'feeds' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', line: 1152, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', symbol: 'openSubsystemModel' },
|
|
345
|
+
{ from: 'subsystems-view', to: 'file-panel', mechanism: 'uses' as const, file: 'packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', line: 958, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/mainview/views/SubsystemModelsView.tsx', symbol: 'onShowAuditReport' },
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
id: 'tl-maintain',
|
|
350
|
+
title: 'Maintain run posts a correction proposal',
|
|
351
|
+
steps: [
|
|
352
|
+
{ from: 'maintain-orchestrator', to: 'run-maintain-agent', mechanism: 'calls' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', line: 854, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintain-model.ts', symbol: 'maintainSubsystemModel' },
|
|
353
|
+
{ from: 'run-maintain-agent', to: 'opencode-v2-service', mechanism: 'calls' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', line: 651, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintain-model.ts', symbol: 'runMaintainAgent' },
|
|
354
|
+
{ from: 'opencode-v2-service', to: 'maintain-agent', mechanism: 'feeds' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', line: 650, purl: 'external:opencode/v2-service#packages/subsystems-studio/src/bun/maintain-model.ts', symbol: 'runMaintainAgent' },
|
|
355
|
+
{ from: 'http-propose', to: 'proposal-create', mechanism: 'calls' as const, file: 'packages/subsystems-studio/src/bun/http-server.ts', line: 404, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/http-server.ts', symbol: 'handleSubsystemModelRequest' },
|
|
356
|
+
{ from: 'proposal-create', to: 'proposals-store', mechanism: 'writes' as const, file: 'packages/subsystems-studio/src/bun/proposal-store.ts', line: 554, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/proposal-store.ts', symbol: 'createSubsystemModelProposal' },
|
|
357
|
+
{ from: 'maintain-orchestrator', to: 'run-store', mechanism: 'writes' as const, file: 'packages/subsystems-studio/src/bun/maintain-model.ts', line: 892, purl: 'pkg:github/acme/subsystem-modeling#packages/subsystems-studio/src/bun/maintain-model.ts', symbol: 'noteSubsystemModelRunStart' },
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
} as const;
|
|
362
|
+
|
|
363
|
+
/** Elements the author is asking a question about, surfaced in the story. */
|
|
364
|
+
export const c4OpenQuestions = c4ProposedElements
|
|
365
|
+
.filter((a) => a.rationale && /(CONFLICT|not a|Expected to be|whether|Needs|one deployable unit)/.test(a.rationale))
|
|
366
|
+
.map((a) => ({ id: a.id, label: a.label, rationale: a.rationale! }));
|
|
@@ -469,7 +469,7 @@ const MAINTAIN_ISSUES: SubsystemIssue[] = [
|
|
|
469
469
|
},
|
|
470
470
|
{
|
|
471
471
|
id: 'mr-symbol-unmatched',
|
|
472
|
-
severity: '
|
|
472
|
+
severity: 'error',
|
|
473
473
|
kind: 'symbol_unmatched',
|
|
474
474
|
message:
|
|
475
475
|
'No graphify node matches symbol readSse in packages/subsystems-studio/src/bun/opencode-v2-live.ts',
|
|
@@ -84,7 +84,7 @@ const ISSUES: SubsystemIssue[] = [
|
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
id: 'i18',
|
|
87
|
-
severity: '
|
|
87
|
+
severity: 'error',
|
|
88
88
|
kind: 'symbol_unmatched',
|
|
89
89
|
message: 'No Graphify node matches symbol persistSession in src/session/SessionStore.ts',
|
|
90
90
|
target: { kind: 'component', id: 'session-store', label: 'SessionStore' },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* C4Graph — a C4 projection of a (composed) subsystem model on React Flow.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Feed it a `C4Model` from `buildC4Model()` and it draws the
|
|
5
5
|
* system as a compound frame, its containers (or components) as boxes, and
|
|
6
6
|
* externals/actors outside the system. `trail` steps render as flow
|
|
7
7
|
* edges. Click a box to list the source components it rolled up.
|
|
@@ -26,9 +26,9 @@ import {
|
|
|
26
26
|
import { useTheme } from '@principal-ade/industry-theme';
|
|
27
27
|
import { computeElkLayout } from '../utils/elkLayout';
|
|
28
28
|
import { MECHANISM_COLOR } from './model';
|
|
29
|
-
import { C4NodeCard, NODE_H, NODE_W, nodeStyle } from './C4NodeCard';
|
|
29
|
+
import { C4NodeCard, NODE_H, NODE_W, nodeSize, nodeStyle } from './C4NodeCard';
|
|
30
30
|
import { GRAPH_CANVAS_CLASS, GRAPH_NAV_PROPS, GraphChrome, GraphLayerStyle } from './graphChrome';
|
|
31
|
-
import type { C4Model, C4Node } from './
|
|
31
|
+
import type { C4Model, C4Node } from './c4';
|
|
32
32
|
|
|
33
33
|
export interface C4GraphProps {
|
|
34
34
|
model: C4Model;
|
|
@@ -130,15 +130,24 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
130
130
|
setReady(false);
|
|
131
131
|
setSelectedId(null);
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
// Per-node size, so a square component is laid out as a square. Feeding the
|
|
134
|
+
// container dimensions for everything would make ELK reserve 210x138 of
|
|
135
|
+
// space around a 132x132 box and space the component view twice as far
|
|
136
|
+
// apart as it needs.
|
|
137
|
+
const rfNodes: Node[] = model.nodes.map((n, i) => {
|
|
138
|
+
const size = nodeSize(n);
|
|
139
|
+
return {
|
|
140
|
+
id: n.id,
|
|
141
|
+
type: 'c4-node',
|
|
142
|
+
// Fallback grid pitch uses the container box — the largest, so the
|
|
143
|
+
// pre-layout positions never overlap. ELK replaces them on success.
|
|
144
|
+
position: { x: (i % 5) * (NODE_W + 44), y: Math.floor(i / 5) * (NODE_H + 44) },
|
|
145
|
+
width: size.width,
|
|
146
|
+
height: size.height,
|
|
147
|
+
...(n.parentId ? { parentId: n.parentId } : {}),
|
|
148
|
+
data: { node: n, selected: false },
|
|
149
|
+
};
|
|
150
|
+
});
|
|
142
151
|
|
|
143
152
|
const groups = model.groups.map((g) => ({
|
|
144
153
|
id: g.id,
|
|
@@ -147,8 +156,8 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
147
156
|
}));
|
|
148
157
|
|
|
149
158
|
const rfEdges: Edge[] = model.edges.map((e) => {
|
|
150
|
-
|
|
151
|
-
const color =
|
|
159
|
+
// Every edge here came from a trail step, so the mechanism colours apply.
|
|
160
|
+
const color = edgeColor(e.mechanisms[0], muted);
|
|
152
161
|
return {
|
|
153
162
|
id: e.id,
|
|
154
163
|
source: e.source,
|
|
@@ -159,7 +168,7 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
159
168
|
style: {
|
|
160
169
|
stroke: color,
|
|
161
170
|
strokeWidth: 1 + Math.min(e.count, 6) * 0.4,
|
|
162
|
-
|
|
171
|
+
strokeDasharray: '6 4',
|
|
163
172
|
},
|
|
164
173
|
markerEnd: { type: MarkerType.ArrowClosed, color, width: 18, height: 18 },
|
|
165
174
|
data: { edge: e },
|
|
@@ -241,7 +250,10 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
241
250
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
242
251
|
}, [layoutKey]);
|
|
243
252
|
|
|
244
|
-
const selected = useMemo(
|
|
253
|
+
const selected = useMemo(
|
|
254
|
+
() => model.nodes.find((n) => n.id === selectedId) ?? null,
|
|
255
|
+
[model, selectedId],
|
|
256
|
+
);
|
|
245
257
|
|
|
246
258
|
const displayNodes = useMemo(
|
|
247
259
|
() =>
|
|
@@ -254,7 +266,9 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
254
266
|
);
|
|
255
267
|
|
|
256
268
|
const runtime = model.nodes.filter((n) => n.kind === 'container' || n.kind === 'component').length;
|
|
257
|
-
const outside = model.nodes.filter(
|
|
269
|
+
const outside = model.nodes.filter(
|
|
270
|
+
(n) => n.kind === 'external-system' || n.kind === 'person',
|
|
271
|
+
).length;
|
|
258
272
|
|
|
259
273
|
return (
|
|
260
274
|
<div style={{ position: 'relative', width: '100%', height: '100%', background: theme.colors.background }}>
|
|
@@ -369,22 +383,23 @@ function Inner({ model, title, onSelectNode }: C4GraphProps) {
|
|
|
369
383
|
}}
|
|
370
384
|
>
|
|
371
385
|
<span style={{ color: nodeStyle(selected, theme).color }}>
|
|
372
|
-
{selected.
|
|
386
|
+
{selected.state}
|
|
387
|
+
{selected.containerKind ? ` · ${selected.containerKind}` : ` · ${selected.kind}`}
|
|
373
388
|
</span>
|
|
374
|
-
{selected.
|
|
375
|
-
<span>technology: {selected.
|
|
389
|
+
{selected.technology ? (
|
|
390
|
+
<span>technology: {selected.technology}</span>
|
|
376
391
|
) : (
|
|
377
392
|
<span style={{ color: theme.colors.warning ?? '#e8a33a' }}>technology: not stated</span>
|
|
378
393
|
)}
|
|
379
|
-
{selected.
|
|
380
|
-
<span style={{ whiteSpace: 'normal', lineHeight: 1.4 }}>{selected.
|
|
394
|
+
{selected.description ? (
|
|
395
|
+
<span style={{ whiteSpace: 'normal', lineHeight: 1.4 }}>{selected.description}</span>
|
|
381
396
|
) : (
|
|
382
397
|
<span style={{ color: theme.colors.warning ?? '#e8a33a' }}>description: not stated</span>
|
|
383
398
|
)}
|
|
384
399
|
{/* A merge hides its inputs, so always show what it absorbed. */}
|
|
385
|
-
{selected.
|
|
400
|
+
{selected.derivedFrom && selected.derivedFrom.length > 1 && (
|
|
386
401
|
<span style={{ whiteSpace: 'normal', lineHeight: 1.4 }}>
|
|
387
|
-
|
|
402
|
+
consolidated from: {selected.derivedFrom.join(', ')}
|
|
388
403
|
</span>
|
|
389
404
|
)}
|
|
390
405
|
</div>
|