@principal-ai/subsystems-react 0.50.0 → 0.51.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/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts +95 -0
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts.map +1 -0
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js +340 -0
- package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js.map +1 -0
- package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts +4 -0
- package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts.map +1 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js +7334 -1
- package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +1 -1
- package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts +2 -0
- package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts.map +1 -0
- package/dist/stories/Subsystem/C4Graph/generateFixture.js +145 -0
- package/dist/stories/Subsystem/C4Graph/generateFixture.js.map +1 -0
- package/dist/subsystem/C4Graph.d.ts.map +1 -1
- package/dist/subsystem/C4Graph.js +16 -60
- package/dist/subsystem/C4Graph.js.map +1 -1
- package/dist/subsystem/C4NodeCard.d.ts +84 -0
- package/dist/subsystem/C4NodeCard.d.ts.map +1 -0
- package/dist/subsystem/C4NodeCard.js +229 -0
- package/dist/subsystem/C4NodeCard.js.map +1 -0
- package/dist/subsystem/DiagnosticToggle.d.ts +8 -1
- package/dist/subsystem/DiagnosticToggle.d.ts.map +1 -1
- package/dist/subsystem/DiagnosticToggle.js +40 -6
- package/dist/subsystem/DiagnosticToggle.js.map +1 -1
- package/dist/subsystem/c4Associations.d.ts +186 -0
- package/dist/subsystem/c4Associations.d.ts.map +1 -0
- package/dist/subsystem/c4Associations.js +284 -0
- package/dist/subsystem/c4Associations.js.map +1 -0
- package/dist/subsystem/model.d.ts +25 -1
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +15 -0
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/nodes.d.ts.map +1 -1
- package/dist/subsystem/nodes.js +78 -7
- package/dist/subsystem/nodes.js.map +1 -1
- package/dist/subsystem/toC4.d.ts +119 -0
- package/dist/subsystem/toC4.d.ts.map +1 -1
- package/dist/subsystem/toC4.js +95 -5
- package/dist/subsystem/toC4.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +39 -0
- package/src/stories/Subsystem/C4Graph/C4Associations.stories.tsx +273 -0
- package/src/stories/Subsystem/C4Graph/C4NodeGallery.stories.tsx +325 -0
- package/src/stories/Subsystem/C4Graph/c4Associations.fixture.ts +344 -0
- package/src/stories/Subsystem/C4Graph/c4Fixture.ts +7337 -4
- package/src/stories/Subsystem/C4Graph/generateFixture.ts +161 -0
- package/src/stories/Subsystem/ComponentGraph/Deprecated.stories.tsx +358 -0
- package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +27 -2
- package/src/stories/Subsystem/ComponentGraph/{Flows.stories.tsx → Trails.stories.tsx} +4 -4
- package/src/subsystem/C4Graph.tsx +51 -92
- package/src/subsystem/C4NodeCard.test.ts +196 -0
- package/src/subsystem/C4NodeCard.tsx +307 -0
- package/src/subsystem/DiagnosticToggle.tsx +58 -4
- package/src/subsystem/c4Associations.test.ts +484 -0
- package/src/subsystem/c4Associations.ts +398 -0
- package/src/subsystem/model.ts +34 -1
- package/src/subsystem/nodes.tsx +124 -5
- package/src/subsystem/toC4.ts +210 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toC4.d.ts","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAE1E,4DAA4D;AAC5D,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjF,+EAA+E;AAC/E,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/C,mDAAmD;AACnD,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qEAAqE;IACrE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,+DAA+D;AAC/D,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"toC4.d.ts","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"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"}
|
package/dist/subsystem/toC4.js
CHANGED
|
@@ -25,6 +25,40 @@ const UNASSIGNED = '(unassigned)';
|
|
|
25
25
|
export function isGroundedComponent(c) {
|
|
26
26
|
return c.construct !== 'external' && c.construct !== 'custom_entity';
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Index confirmed associations by the derived keys they claim.
|
|
30
|
+
*
|
|
31
|
+
* First writer wins on a contested key so the result does not depend on array
|
|
32
|
+
* order, and the loser is reported so the conflict is visible rather than
|
|
33
|
+
* silently dropped.
|
|
34
|
+
*/
|
|
35
|
+
export function indexAssociations(associations) {
|
|
36
|
+
const byKey = new Map();
|
|
37
|
+
const contested = [];
|
|
38
|
+
if (!associations)
|
|
39
|
+
return { byKey, contested };
|
|
40
|
+
// Stable order: accepted before proposed, so a confirmed decision outranks a
|
|
41
|
+
// speculative one for the same key.
|
|
42
|
+
const ordered = [...associations].sort((a, b) => {
|
|
43
|
+
const rank = (s) => (s === 'accepted' ? 0 : s === 'proposed' ? 1 : 2);
|
|
44
|
+
return rank(a.state) - rank(b.state) || a.id.localeCompare(b.id);
|
|
45
|
+
});
|
|
46
|
+
for (const a of ordered) {
|
|
47
|
+
for (const key of a.sourceKeys) {
|
|
48
|
+
const existing = byKey.get(key);
|
|
49
|
+
if (existing && existing.id !== a.id) {
|
|
50
|
+
contested.push({ key, kept: existing.id, dropped: a.id });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
byKey.set(key, a);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { byKey, contested };
|
|
57
|
+
}
|
|
58
|
+
/** True when a resolved association means this box should not be drawn. */
|
|
59
|
+
function isSuppressed(a) {
|
|
60
|
+
return a?.state === 'rejected';
|
|
61
|
+
}
|
|
28
62
|
/** `owner/name` from a purl, trimmed of scheme and fragment. */
|
|
29
63
|
export function labelFromPurl(purl) {
|
|
30
64
|
const base = purl.replace(/^external:/, '').split('#')[0]?.trim() ?? '';
|
|
@@ -60,6 +94,12 @@ export function toC4(doc, options = {}) {
|
|
|
60
94
|
const view = options.view ?? 'container';
|
|
61
95
|
const repoKey = options.repoKey ?? deriveRepoKey(doc) ?? 'system';
|
|
62
96
|
const systemId = `system:${repoKey}`;
|
|
97
|
+
const { byKey: assocByKey } = indexAssociations(options.associations);
|
|
98
|
+
// Id -> association, so a container frame can be labelled from its
|
|
99
|
+
// association even when no node exists for it (component view).
|
|
100
|
+
const assocById = new Map();
|
|
101
|
+
for (const a of options.associations ?? [])
|
|
102
|
+
assocById.set(a.id, a);
|
|
63
103
|
const system = {
|
|
64
104
|
id: systemId,
|
|
65
105
|
kind: 'system',
|
|
@@ -73,12 +113,32 @@ export function toC4(doc, options = {}) {
|
|
|
73
113
|
const ownerOf = new Map();
|
|
74
114
|
const containerNodeId = (key) => `container:${key}`;
|
|
75
115
|
const componentNodeId = (alias) => `component:${alias}`;
|
|
116
|
+
/**
|
|
117
|
+
* Resolve one derived container key into the box that should carry it.
|
|
118
|
+
*
|
|
119
|
+
* An accepted association wins: its id becomes the node id, so every key it
|
|
120
|
+
* claims rolls into one node (that is the dedup), and its label / type /
|
|
121
|
+
* technology / description become the node's presentation. A rejected one
|
|
122
|
+
* means the box is not drawn at all. Unclaimed keys keep the raw derived
|
|
123
|
+
* behaviour, so the projection is still useful with zero associations.
|
|
124
|
+
*/
|
|
125
|
+
const resolveContainer = (key) => {
|
|
126
|
+
const assoc = assocByKey.get(key);
|
|
127
|
+
if (assoc && assoc.level === 'container') {
|
|
128
|
+
return { id: assoc.id, label: assoc.label, assoc };
|
|
129
|
+
}
|
|
130
|
+
if (view === 'component') {
|
|
131
|
+
return { id: containerNodeId(key), label: key === UNASSIGNED ? 'Unassigned' : key, assoc: undefined };
|
|
132
|
+
}
|
|
133
|
+
return { id: containerNodeId(key), label: key === UNASSIGNED ? 'Unassigned' : key, assoc: undefined };
|
|
134
|
+
};
|
|
76
135
|
for (const c of doc.components) {
|
|
77
136
|
let id;
|
|
78
137
|
let kind;
|
|
79
138
|
let label;
|
|
80
139
|
let parentId;
|
|
81
140
|
let key;
|
|
141
|
+
let assoc;
|
|
82
142
|
if (c.construct === 'external') {
|
|
83
143
|
key = externalKey(c);
|
|
84
144
|
id = `external:${key}`;
|
|
@@ -93,17 +153,25 @@ export function toC4(doc, options = {}) {
|
|
|
93
153
|
}
|
|
94
154
|
else if (view === 'component') {
|
|
95
155
|
key = containerKey(c);
|
|
156
|
+
const resolved = resolveContainer(key);
|
|
157
|
+
if (isSuppressed(resolved.assoc))
|
|
158
|
+
continue;
|
|
96
159
|
id = componentNodeId(c.alias);
|
|
97
160
|
kind = 'component';
|
|
98
161
|
label = c.name;
|
|
99
|
-
parentId =
|
|
162
|
+
parentId = resolved.id;
|
|
163
|
+
assoc = undefined; // the component itself has no association
|
|
100
164
|
}
|
|
101
165
|
else {
|
|
102
166
|
key = containerKey(c);
|
|
103
|
-
|
|
167
|
+
const resolved = resolveContainer(key);
|
|
168
|
+
if (isSuppressed(resolved.assoc))
|
|
169
|
+
continue;
|
|
170
|
+
id = resolved.id;
|
|
104
171
|
kind = 'container';
|
|
105
|
-
label =
|
|
172
|
+
label = resolved.label;
|
|
106
173
|
parentId = systemId;
|
|
174
|
+
assoc = resolved.assoc;
|
|
107
175
|
}
|
|
108
176
|
ownerOf.set(c.alias, id);
|
|
109
177
|
let node = nodes.get(id);
|
|
@@ -117,7 +185,12 @@ export function toC4(doc, options = {}) {
|
|
|
117
185
|
members: [],
|
|
118
186
|
constructs: [],
|
|
119
187
|
isStore: false,
|
|
188
|
+
// A merged box is built from several derived keys. Track them as a
|
|
189
|
+
// set so the confirm UI can show what was folded together — without
|
|
190
|
+
// this, the accumulation would run once per member, not per key.
|
|
191
|
+
...(assoc && assoc.sourceKeys.length > 1 ? { sourceKeys: [...assoc.sourceKeys] } : {}),
|
|
120
192
|
...(kind === 'component' ? { component: c } : {}),
|
|
193
|
+
...(assoc ? { decoration: toDecoration(assoc) } : {}),
|
|
121
194
|
};
|
|
122
195
|
nodes.set(id, node);
|
|
123
196
|
}
|
|
@@ -133,6 +206,9 @@ export function toC4(doc, options = {}) {
|
|
|
133
206
|
}
|
|
134
207
|
// --- Groups (compound frames) ------------------------------------------
|
|
135
208
|
const groups = [];
|
|
209
|
+
const labelForContainerId = (id) => nodes.get(id)?.label ??
|
|
210
|
+
assocById.get(id)?.label ??
|
|
211
|
+
(id.startsWith('container:') ? id.slice('container:'.length) : id);
|
|
136
212
|
if (view === 'container') {
|
|
137
213
|
const containerIds = [...nodes.values()].filter((n) => n.kind === 'container').map((n) => n.id);
|
|
138
214
|
if (containerIds.length > 0) {
|
|
@@ -150,8 +226,7 @@ export function toC4(doc, options = {}) {
|
|
|
150
226
|
}
|
|
151
227
|
const containerIds = [];
|
|
152
228
|
for (const [id, memberIds] of byContainer) {
|
|
153
|
-
|
|
154
|
-
groups.push({ id, kind: 'container', label: label === UNASSIGNED ? 'Unassigned' : label, parentId: systemId, memberIds });
|
|
229
|
+
groups.push({ id, kind: 'container', label: labelForContainerId(id), parentId: systemId, memberIds });
|
|
155
230
|
containerIds.push(id);
|
|
156
231
|
}
|
|
157
232
|
if (containerIds.length > 0) {
|
|
@@ -163,6 +238,10 @@ export function toC4(doc, options = {}) {
|
|
|
163
238
|
const addEdge = (bucket, source, target, kind, mechanism) => {
|
|
164
239
|
if (!source || !target || source === target)
|
|
165
240
|
return;
|
|
241
|
+
// An endpoint whose box was rejected has no owner; the edge cannot be
|
|
242
|
+
// drawn, so drop it rather than inventing a dangling arrow.
|
|
243
|
+
if (!nodes.has(source) || !nodes.has(target))
|
|
244
|
+
return;
|
|
166
245
|
const key = `${source}\0${target}`;
|
|
167
246
|
let edge = bucket.get(key);
|
|
168
247
|
if (!edge) {
|
|
@@ -189,4 +268,15 @@ export function toC4(doc, options = {}) {
|
|
|
189
268
|
edges,
|
|
190
269
|
};
|
|
191
270
|
}
|
|
271
|
+
/** Project an association down to the attributes a node carries. */
|
|
272
|
+
function toDecoration(a) {
|
|
273
|
+
return {
|
|
274
|
+
id: a.id,
|
|
275
|
+
label: a.label,
|
|
276
|
+
type: a.type,
|
|
277
|
+
technology: a.technology,
|
|
278
|
+
description: a.description,
|
|
279
|
+
state: a.state,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
192
282
|
//# sourceMappingURL=toC4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toC4.js","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"toC4.js","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/subsystems-react",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "React UI for Subsystem Models
|
|
3
|
+
"version": "0.51.0",
|
|
4
|
+
"description": "React UI for Subsystem Models \u2014 graph, Pierre code views, and session-event feeds",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
package/src/index.ts
CHANGED
|
@@ -239,6 +239,45 @@ export type {
|
|
|
239
239
|
SubsystemSignatureClaim,
|
|
240
240
|
SubsystemSignatureParameter,
|
|
241
241
|
} from './subsystem/model';
|
|
242
|
+
// --- C4 projection + the confirmed association layer ------------------
|
|
243
|
+
export { C4Graph } from './subsystem/C4Graph';
|
|
244
|
+
export type { C4GraphProps } from './subsystem/C4Graph';
|
|
245
|
+
export { C4NodeCard, nodeStyle, nodeSubtitle, nodeTag, nodeMissing, NODE_W, NODE_H } from './subsystem/C4NodeCard';
|
|
246
|
+
export type { C4NodeCardProps, NodeStyle } from './subsystem/C4NodeCard';
|
|
247
|
+
export {
|
|
248
|
+
toC4,
|
|
249
|
+
isGroundedComponent,
|
|
250
|
+
labelFromPurl,
|
|
251
|
+
deriveRepoKey,
|
|
252
|
+
indexAssociations,
|
|
253
|
+
} from './subsystem/toC4';
|
|
254
|
+
export type {
|
|
255
|
+
C4Kind,
|
|
256
|
+
C4View,
|
|
257
|
+
C4Node,
|
|
258
|
+
C4Group,
|
|
259
|
+
C4Edge,
|
|
260
|
+
C4Model,
|
|
261
|
+
C4Decoration,
|
|
262
|
+
C4ElementType,
|
|
263
|
+
C4Association,
|
|
264
|
+
C4AssociationState,
|
|
265
|
+
ToC4Options,
|
|
266
|
+
} from './subsystem/toC4';
|
|
267
|
+
export {
|
|
268
|
+
deriveConcerns,
|
|
269
|
+
suggestMerges,
|
|
270
|
+
buildAssociations,
|
|
271
|
+
mergeAssociations,
|
|
272
|
+
associationWeight,
|
|
273
|
+
summarizeAssociations,
|
|
274
|
+
} from './subsystem/c4Associations';
|
|
275
|
+
export type {
|
|
276
|
+
C4AssociationSet,
|
|
277
|
+
C4AssociationReason,
|
|
278
|
+
C4ConcernKind,
|
|
279
|
+
C4MemberView,
|
|
280
|
+
} from './subsystem/c4Associations';
|
|
242
281
|
export {
|
|
243
282
|
constructBadgeLabel,
|
|
244
283
|
constructBadgeColor,
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import '@xyflow/react/dist/style.css';
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
4
|
+
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
5
|
+
import { C4Graph } from '../../../subsystem/C4Graph';
|
|
6
|
+
import { toC4, type C4View } from '../../../subsystem/toC4';
|
|
7
|
+
import type { C4Association } from '../../../subsystem/toC4';
|
|
8
|
+
import { summarizeAssociations, mergeAssociations } from '../../../subsystem/c4Associations';
|
|
9
|
+
import { c4FixtureModel, c4MemberCounts } from './c4Fixture';
|
|
10
|
+
import { c4Associations, C4_MERGE_CANDIDATES, C4_CONCERNS } from './c4Associations.fixture';
|
|
11
|
+
|
|
12
|
+
const MEMBER_COUNTS = new Map(Object.entries(c4MemberCounts));
|
|
13
|
+
|
|
14
|
+
const meta = {
|
|
15
|
+
title: 'Subsystem/C4Graph/C4Associations',
|
|
16
|
+
component: C4Graph,
|
|
17
|
+
parameters: { layout: 'fullscreen' },
|
|
18
|
+
tags: ['autodocs'],
|
|
19
|
+
decorators: [
|
|
20
|
+
(Story) => (
|
|
21
|
+
<ThemeProvider theme={defaultEditorTheme}>
|
|
22
|
+
<Story />
|
|
23
|
+
</ThemeProvider>
|
|
24
|
+
),
|
|
25
|
+
],
|
|
26
|
+
} satisfies Meta<typeof C4Graph>;
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof meta>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* C4 associations — the confirmed layer over a raw derivation.
|
|
33
|
+
*
|
|
34
|
+
* `toC4()` alone rolls components up into boxes keyed by `process`. That
|
|
35
|
+
* derivation is a guess: two keys may be the same deployable, a library may be
|
|
36
|
+
* pretending to be a container, and a store may not be a C4 data store at all.
|
|
37
|
+
*
|
|
38
|
+
* This story starts from a real composite of 40 stored models and lets you act
|
|
39
|
+
* on the 13 proposed associations:
|
|
40
|
+
*
|
|
41
|
+
* accept the box goes solid — it is part of the architecture
|
|
42
|
+
* reject the box disappears, and so do the edges into it
|
|
43
|
+
* merge two keys collapse into one box
|
|
44
|
+
*
|
|
45
|
+
* Try `merge host` first: it takes `subsystems-studio/host` (113 components)
|
|
46
|
+
* and `principal-studio/host` (1 component) and folds them into one container.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
function Demo({ initialAccepted = [] as string[] }: { initialAccepted?: string[] }) {
|
|
50
|
+
const [view, setView] = useState<C4View>('container');
|
|
51
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
52
|
+
const [state, setState] = useState<Record<string, C4Association['state']>>(() =>
|
|
53
|
+
Object.fromEntries(initialAccepted.map((id) => [id, 'accepted' as const])),
|
|
54
|
+
);
|
|
55
|
+
/** Roles the user has merged. Folds the candidates into one association each. */
|
|
56
|
+
const [mergedRoles, setMergedRoles] = useState<string[]>([]);
|
|
57
|
+
|
|
58
|
+
const associations = useMemo<C4Association[]>(() => {
|
|
59
|
+
let set: C4Association[] = c4Associations;
|
|
60
|
+
for (const role of mergedRoles) {
|
|
61
|
+
const candidate = C4_MERGE_CANDIDATES.find((c) => c.role === role);
|
|
62
|
+
if (!candidate) continue;
|
|
63
|
+
// The evidence-heavy side survives automatically — see mergeAssociations.
|
|
64
|
+
set = mergeAssociations(set, candidate.keys, undefined, MEMBER_COUNTS);
|
|
65
|
+
}
|
|
66
|
+
// Apply the user's accept/reject last, over the merged set.
|
|
67
|
+
return set.map((a) => ({ ...a, state: state[a.id] ?? a.state }));
|
|
68
|
+
}, [state, mergedRoles]);
|
|
69
|
+
|
|
70
|
+
const model = useMemo(
|
|
71
|
+
() => toC4(c4FixtureModel, { view, systemLabel: 'Subsystem Modeling', associations }),
|
|
72
|
+
[view, associations],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const stats = useMemo(() => summarizeAssociations(model, associations), [model, associations]);
|
|
76
|
+
|
|
77
|
+
const concernsFor = (id: string) => {
|
|
78
|
+
const a = associations.find((x) => x.id === id);
|
|
79
|
+
if (!a) return [];
|
|
80
|
+
return C4_CONCERNS.filter((c) => a.sourceKeys.includes(c.target));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const decide = (id: string, next: C4Association['state']) =>
|
|
84
|
+
setState((prev) => ({ ...prev, [id]: next }));
|
|
85
|
+
|
|
86
|
+
const reset = () => {
|
|
87
|
+
setState({});
|
|
88
|
+
setMergedRoles([]);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const button = (label: string, value: C4View) => (
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
onClick={() => setView(value)}
|
|
95
|
+
style={{
|
|
96
|
+
fontFamily: 'monospace',
|
|
97
|
+
fontSize: 12,
|
|
98
|
+
padding: '2px 10px',
|
|
99
|
+
borderRadius: 4,
|
|
100
|
+
cursor: 'pointer',
|
|
101
|
+
border: '1px solid #555',
|
|
102
|
+
background: view === value ? '#1D9E75' : 'transparent',
|
|
103
|
+
color: view === value ? '#020B12' : '#ddd',
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
{label}
|
|
107
|
+
</button>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const act = (label: string, onClick: () => void) => (
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
onClick={onClick}
|
|
114
|
+
style={{
|
|
115
|
+
fontFamily: 'monospace',
|
|
116
|
+
fontSize: 11,
|
|
117
|
+
padding: '2px 8px',
|
|
118
|
+
borderRadius: 4,
|
|
119
|
+
cursor: 'pointer',
|
|
120
|
+
border: '1px solid #555',
|
|
121
|
+
background: 'transparent',
|
|
122
|
+
color: '#ddd',
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
{label}
|
|
126
|
+
</button>
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column', background: '#12141a' }}>
|
|
131
|
+
<div style={{ flex: 1, minHeight: 0, position: 'relative' }}>
|
|
132
|
+
<C4Graph model={model} title="Subsystem Modeling" onSelectNode={setSelected} />
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div
|
|
136
|
+
style={{
|
|
137
|
+
maxHeight: 280,
|
|
138
|
+
overflowY: 'auto',
|
|
139
|
+
padding: '8px 12px',
|
|
140
|
+
display: 'flex',
|
|
141
|
+
gap: 18,
|
|
142
|
+
fontFamily: 'monospace',
|
|
143
|
+
fontSize: 12,
|
|
144
|
+
color: '#aaa',
|
|
145
|
+
borderTop: '1px solid #333',
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
<div style={{ minWidth: 210 }}>
|
|
149
|
+
<div style={{ display: 'flex', gap: 6, marginBottom: 8 }}>
|
|
150
|
+
{button('container', 'container')}
|
|
151
|
+
{button('component', 'component')}
|
|
152
|
+
</div>
|
|
153
|
+
<div>
|
|
154
|
+
{stats.confirmed} confirmed · {stats.proposed} proposed
|
|
155
|
+
</div>
|
|
156
|
+
<div>{stats.rejected} rejected · {stats.mergedAway} keys merged away</div>
|
|
157
|
+
<div style={{ color: stats.missingTechnology > 0 ? '#e8a33a' : '#5a5' }}>
|
|
158
|
+
{stats.missingTechnology} containers missing technology
|
|
159
|
+
</div>
|
|
160
|
+
<div>{stats.needsDecision} still need a decision</div>
|
|
161
|
+
<div style={{ marginTop: 8 }}>{act('reset', reset)}</div>
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
{/* The merge question, with one click to try it. */}
|
|
165
|
+
<div style={{ minWidth: 300, maxWidth: 340 }}>
|
|
166
|
+
<div style={{ color: '#ddd', marginBottom: 4 }}>MERGE CANDIDATES</div>
|
|
167
|
+
{C4_MERGE_CANDIDATES.map((c) => {
|
|
168
|
+
const done = mergedRoles.includes(c.role);
|
|
169
|
+
// Show which side the evidence will keep, before you click.
|
|
170
|
+
const heaviest = c.keys.reduce((a, b) =>
|
|
171
|
+
(c4MemberCounts[b] ?? 0) > (c4MemberCounts[a] ?? 0) ? b : a,
|
|
172
|
+
);
|
|
173
|
+
return (
|
|
174
|
+
<div key={c.role} style={{ marginBottom: 8 }}>
|
|
175
|
+
{c.keys.map((k) => (
|
|
176
|
+
<div
|
|
177
|
+
key={k}
|
|
178
|
+
style={{
|
|
179
|
+
color: done && k === heaviest ? '#5a5' : '#888',
|
|
180
|
+
lineHeight: 1.35,
|
|
181
|
+
fontWeight: done && k === heaviest ? 600 : 400,
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
{k} · {c4MemberCounts[k] ?? 0}
|
|
185
|
+
</div>
|
|
186
|
+
))}
|
|
187
|
+
<div style={{ display: 'flex', gap: 6, alignItems: 'center', marginTop: 3 }}>
|
|
188
|
+
{done ? (
|
|
189
|
+
<>
|
|
190
|
+
<span style={{ color: '#5a5' }}>merged — kept {heaviest.split('/').pop()}</span>
|
|
191
|
+
{act('undo', () => setMergedRoles((prev) => prev.filter((r) => r !== c.role)))}
|
|
192
|
+
</>
|
|
193
|
+
) : (
|
|
194
|
+
act(`merge ${c.role}`, () => setMergedRoles((prev) => [...prev, c.role]))
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
})}
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
{/* Per-association review. This is the surface a real confirm UI would use. */}
|
|
203
|
+
<div style={{ flex: 1, minWidth: 380 }}>
|
|
204
|
+
<div style={{ color: '#ddd', marginBottom: 4 }}>
|
|
205
|
+
ASSOCIATIONS · {associations.length}
|
|
206
|
+
</div>
|
|
207
|
+
{associations.map((a) => {
|
|
208
|
+
const s = state[a.id] ?? a.state;
|
|
209
|
+
const concerns = concernsFor(a.id);
|
|
210
|
+
const missing: string[] = [];
|
|
211
|
+
if (!a.technology) missing.push('technology');
|
|
212
|
+
if (!a.description) missing.push('description');
|
|
213
|
+
return (
|
|
214
|
+
<div
|
|
215
|
+
key={a.id}
|
|
216
|
+
style={{
|
|
217
|
+
display: 'flex',
|
|
218
|
+
gap: 10,
|
|
219
|
+
alignItems: 'flex-start',
|
|
220
|
+
padding: '4px 0',
|
|
221
|
+
borderBottom: '1px solid #222',
|
|
222
|
+
opacity: s === 'rejected' ? 0.45 : 1,
|
|
223
|
+
}}
|
|
224
|
+
>
|
|
225
|
+
<div style={{ flex: 1, minWidth: 0 }}>
|
|
226
|
+
<div style={{ color: '#ddd' }}>
|
|
227
|
+
{a.label}
|
|
228
|
+
<span style={{ color: s === 'accepted' ? '#5a5' : s === 'proposed' ? '#e8a33a' : '#888' }}>
|
|
229
|
+
{' '}
|
|
230
|
+
· {s} · {a.type}
|
|
231
|
+
</span>
|
|
232
|
+
</div>
|
|
233
|
+
<div style={{ color: '#777', fontSize: 11 }}>
|
|
234
|
+
keys: {a.sourceKeys.join(', ')}
|
|
235
|
+
{a.technology ? ` · tech: ${a.technology}` : ''}
|
|
236
|
+
{missing.length > 0 ? ` · needs ${missing.join(' + ')}` : ''}
|
|
237
|
+
</div>
|
|
238
|
+
{concerns.length > 0 && (
|
|
239
|
+
<div style={{ color: '#c96', fontSize: 11, lineHeight: 1.35 }}>
|
|
240
|
+
{concerns.map((c) => (
|
|
241
|
+
<div key={c.kind + c.target}>⚠ {c.message}</div>
|
|
242
|
+
))}
|
|
243
|
+
</div>
|
|
244
|
+
)}
|
|
245
|
+
</div>
|
|
246
|
+
<div style={{ display: 'flex', gap: 4 }}>
|
|
247
|
+
{act('accept', () => decide(a.id, 'accepted'))}
|
|
248
|
+
{act('reject', () => decide(a.id, 'rejected'))}
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
})}
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<div style={{ minWidth: 130, fontSize: 11, color: '#777' }}>
|
|
256
|
+
<div>selected: {selected ?? '(none)'}</div>
|
|
257
|
+
<div style={{ marginTop: 6 }}>solid = confirmed</div>
|
|
258
|
+
<div>dashed = proposed</div>
|
|
259
|
+
<div>muted = unconfirmed</div>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export const Associations: Story = {
|
|
267
|
+
render: () => <Demo />,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/** Start from a half-confirmed state so the visual difference is obvious. */
|
|
271
|
+
export const PartiallyConfirmed: Story = {
|
|
272
|
+
render: () => <Demo initialAccepted={['container:subsystems-studio/host', 'container:subsystems-studio/renderer']} />,
|
|
273
|
+
};
|