@anlyx/ui 0.1.3 → 0.1.6-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/capture/capture-runtime.d.ts +14 -0
- package/dist/capture/capture-runtime.js +300 -0
- package/dist/components/CaptureStatusEmptyState.js +2 -2
- package/dist/components/EndpointMapCanvas.js +1 -1
- package/dist/components/InspectorPanel.js +27 -1
- package/dist/components/StatusBadge.d.ts +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/overlay/MainFlowCanvas.js +1 -1
- package/dist/overlay/overlay-ui.js +1 -1
- package/dist/readme-demo/ReadmeDemoApp.d.ts +12 -1
- package/dist/readme-demo/ReadmeDemoApp.js +74 -16
- package/dist/styles.css +17 -4
- package/dist/viewer/ViewerApp.js +35 -15
- package/dist/viewer/styles.css +2639 -0
- package/dist/viewer/viewer-entry.d.ts +1 -0
- package/dist/viewer/viewer-entry.js +1 -0
- package/dist/viewer/workspace/anlyx-logo-transparent.png +0 -0
- package/dist/viewer/workspace/workspace.css +11938 -0
- package/dist/workspace/ScanTreeMap.d.ts +6 -0
- package/dist/workspace/ScanTreeMap.js +838 -0
- package/dist/workspace/WorkspaceApp.d.ts +9 -0
- package/dist/workspace/WorkspaceApp.js +3016 -0
- package/dist/workspace/project-view-model.d.ts +63 -0
- package/dist/workspace/project-view-model.js +170 -0
- package/dist/workspace/workspace.css +11938 -0
- package/package.json +10 -2
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ProjectData, ProjectEvidence, ProjectFeature, ProjectFlow, ProjectFlowLayer, ProjectPage, ProjectRequest } from "@anlyx/core";
|
|
2
|
+
export type ProjectPageIndexItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
path: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
featureCount: number;
|
|
8
|
+
confidence?: string;
|
|
9
|
+
};
|
|
10
|
+
export type ProjectPageIndexGroup = {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
pages: ProjectPageIndexItem[];
|
|
14
|
+
};
|
|
15
|
+
export type ProjectRequestView = ProjectRequest & {
|
|
16
|
+
source: "feature" | "project";
|
|
17
|
+
};
|
|
18
|
+
export type ProjectFeatureView = ProjectFeature & {
|
|
19
|
+
requests: ProjectRequestView[];
|
|
20
|
+
};
|
|
21
|
+
export type ProjectFlowView = ProjectFlow & {
|
|
22
|
+
request?: ProjectRequestView;
|
|
23
|
+
layers: ProjectFlowLayer[];
|
|
24
|
+
};
|
|
25
|
+
export type ProjectEvidenceSummary = {
|
|
26
|
+
observed: number;
|
|
27
|
+
measured: number;
|
|
28
|
+
sourceMatched: number;
|
|
29
|
+
agentInferred: number;
|
|
30
|
+
manual: number;
|
|
31
|
+
notProven: number;
|
|
32
|
+
unknown: number;
|
|
33
|
+
total: number;
|
|
34
|
+
};
|
|
35
|
+
export type ProjectSelectedPageView = {
|
|
36
|
+
page: ProjectPage;
|
|
37
|
+
areaName: string;
|
|
38
|
+
features: ProjectFeatureView[];
|
|
39
|
+
requests: ProjectRequestView[];
|
|
40
|
+
flows: ProjectFlowView[];
|
|
41
|
+
evidence: ProjectEvidence[];
|
|
42
|
+
evidenceSummary: ProjectEvidenceSummary;
|
|
43
|
+
hasMeasurements: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type ProjectWorkspaceViewModel = {
|
|
46
|
+
dictionary: ProjectData["dictionary"];
|
|
47
|
+
project: ProjectData["project"];
|
|
48
|
+
schemaVersion: ProjectData["schemaVersion"];
|
|
49
|
+
pageGroups: ProjectPageIndexGroup[];
|
|
50
|
+
selectedPage: ProjectSelectedPageView | undefined;
|
|
51
|
+
totals: {
|
|
52
|
+
areas: number;
|
|
53
|
+
pages: number;
|
|
54
|
+
features: number;
|
|
55
|
+
requests: number;
|
|
56
|
+
flows: number;
|
|
57
|
+
evidence: number;
|
|
58
|
+
measurements: number;
|
|
59
|
+
architectureNodes: number;
|
|
60
|
+
architectureEdges: number;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export declare function buildProjectWorkspaceViewModel(data: ProjectData, selectedPageId?: string): ProjectWorkspaceViewModel;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export function buildProjectWorkspaceViewModel(data, selectedPageId) {
|
|
2
|
+
const areaById = new Map(data.areas.map((area) => [area.id, area]));
|
|
3
|
+
const requestById = new Map(data.requests.map((request) => [request.id, request]));
|
|
4
|
+
const pageId = selectedPageId ?? data.pages[0]?.id;
|
|
5
|
+
const selectedPage = data.pages.find((page) => page.id === pageId) ?? data.pages[0];
|
|
6
|
+
return {
|
|
7
|
+
dictionary: data.dictionary,
|
|
8
|
+
project: data.project,
|
|
9
|
+
schemaVersion: data.schemaVersion,
|
|
10
|
+
pageGroups: groupPagesByArea(data.pages, data.areas, data.features),
|
|
11
|
+
selectedPage: selectedPage
|
|
12
|
+
? buildSelectedPageView(data, selectedPage, areaById, requestById)
|
|
13
|
+
: undefined,
|
|
14
|
+
totals: {
|
|
15
|
+
areas: data.areas.length,
|
|
16
|
+
pages: data.pages.length,
|
|
17
|
+
features: data.features.length,
|
|
18
|
+
requests: data.requests.length,
|
|
19
|
+
flows: data.flows.length,
|
|
20
|
+
evidence: data.evidence.length,
|
|
21
|
+
measurements: data.measurements.length,
|
|
22
|
+
architectureNodes: data.architecture.nodes.length,
|
|
23
|
+
architectureEdges: data.architecture.edges.length
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function groupPagesByArea(pages, areas, features) {
|
|
28
|
+
const orderByArea = new Map(areas.map((area, index) => [area.id, area.order ?? index]));
|
|
29
|
+
const featureCountByPageId = new Map();
|
|
30
|
+
const groups = new Map();
|
|
31
|
+
for (const feature of features) {
|
|
32
|
+
featureCountByPageId.set(feature.pageId, (featureCountByPageId.get(feature.pageId) ?? 0) + 1);
|
|
33
|
+
}
|
|
34
|
+
for (const area of [...areas].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))) {
|
|
35
|
+
groups.set(area.id, { id: area.id, name: area.name, pages: [] });
|
|
36
|
+
}
|
|
37
|
+
groups.set("uncategorized", { id: "uncategorized", name: "Uncategorized", pages: [] });
|
|
38
|
+
for (const page of pages) {
|
|
39
|
+
const group = page.areaId ? groups.get(page.areaId) : undefined;
|
|
40
|
+
const targetGroup = group ?? groups.get("uncategorized");
|
|
41
|
+
targetGroup.pages.push({
|
|
42
|
+
id: page.id,
|
|
43
|
+
title: page.title,
|
|
44
|
+
path: page.path,
|
|
45
|
+
...(page.description ? { description: page.description } : {}),
|
|
46
|
+
featureCount: Math.max(page.featureIds.length, featureCountByPageId.get(page.id) ?? 0),
|
|
47
|
+
...(page.confidence ? { confidence: page.confidence } : {})
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return [...groups.values()]
|
|
51
|
+
.filter((group) => group.pages.length > 0)
|
|
52
|
+
.sort((a, b) => {
|
|
53
|
+
if (a.id === "uncategorized")
|
|
54
|
+
return 1;
|
|
55
|
+
if (b.id === "uncategorized")
|
|
56
|
+
return -1;
|
|
57
|
+
return (orderByArea.get(a.id) ?? 0) - (orderByArea.get(b.id) ?? 0);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function buildSelectedPageView(data, page, areaById, requestById) {
|
|
61
|
+
const pageFeatures = data.features.filter((feature) => feature.pageId === page.id || page.featureIds.includes(feature.id));
|
|
62
|
+
const requestMap = new Map();
|
|
63
|
+
const features = pageFeatures.map((feature) => {
|
|
64
|
+
const requests = collectFeatureRequests(feature, requestById);
|
|
65
|
+
for (const request of requests) {
|
|
66
|
+
requestMap.set(request.id, request);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
...feature,
|
|
70
|
+
requests
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
for (const request of data.requests) {
|
|
74
|
+
if (isPageScopedRequest(request, page.id)) {
|
|
75
|
+
requestMap.set(request.id, { ...request, source: "project" });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const requests = [...requestMap.values()];
|
|
79
|
+
const requestIds = new Set(requests.map((request) => request.id));
|
|
80
|
+
const flows = data.flows
|
|
81
|
+
.filter((flow) => (flow.requestId ? requestIds.has(flow.requestId) : false))
|
|
82
|
+
.map((flow) => {
|
|
83
|
+
const request = flow.requestId ? requestMap.get(flow.requestId) : undefined;
|
|
84
|
+
return request
|
|
85
|
+
? {
|
|
86
|
+
...flow,
|
|
87
|
+
request,
|
|
88
|
+
layers: flow.layers
|
|
89
|
+
}
|
|
90
|
+
: {
|
|
91
|
+
...flow,
|
|
92
|
+
layers: flow.layers
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
const evidenceIds = new Set([
|
|
96
|
+
...page.evidenceIds,
|
|
97
|
+
...features.flatMap((feature) => feature.evidenceIds),
|
|
98
|
+
...requests.flatMap((request) => request.evidenceIds),
|
|
99
|
+
...flows.flatMap((flow) => [
|
|
100
|
+
...flow.evidenceIds,
|
|
101
|
+
...flow.layers.flatMap((layer) => layer.evidenceIds)
|
|
102
|
+
])
|
|
103
|
+
]);
|
|
104
|
+
const targetIds = new Set([
|
|
105
|
+
page.id,
|
|
106
|
+
...features.map((feature) => feature.id),
|
|
107
|
+
...requests.map((request) => request.id),
|
|
108
|
+
...flows.flatMap((flow) => [flow.id, ...flow.layers.map((layer) => layer.id)])
|
|
109
|
+
]);
|
|
110
|
+
const evidence = data.evidence.filter((item) => evidenceIds.has(item.id) ||
|
|
111
|
+
(item.targetIds.length > 0
|
|
112
|
+
? item.targetIds.some((targetId) => targetIds.has(targetId))
|
|
113
|
+
: targetIds.has(item.id)));
|
|
114
|
+
return {
|
|
115
|
+
page,
|
|
116
|
+
areaName: page.areaId ? (areaById.get(page.areaId)?.name ?? "Uncategorized") : "Uncategorized",
|
|
117
|
+
features,
|
|
118
|
+
requests,
|
|
119
|
+
flows,
|
|
120
|
+
evidence,
|
|
121
|
+
evidenceSummary: summarizeEvidence(evidence),
|
|
122
|
+
hasMeasurements: data.measurements.some((measurement) => targetIds.has(measurement.targetId))
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function collectFeatureRequests(feature, requestById) {
|
|
126
|
+
const collected = new Map();
|
|
127
|
+
for (const request of feature.requests) {
|
|
128
|
+
collected.set(request.id, { ...request, source: "feature" });
|
|
129
|
+
}
|
|
130
|
+
for (const requestId of feature.requestIds) {
|
|
131
|
+
const request = requestById.get(requestId);
|
|
132
|
+
if (request) {
|
|
133
|
+
collected.set(request.id, { ...request, source: "project" });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return [...collected.values()];
|
|
137
|
+
}
|
|
138
|
+
function isPageScopedRequest(request, pageId) {
|
|
139
|
+
const metadataPageId = request.metadata?.["pageId"];
|
|
140
|
+
return typeof metadataPageId === "string" && metadataPageId === pageId;
|
|
141
|
+
}
|
|
142
|
+
function summarizeEvidence(evidence) {
|
|
143
|
+
const summary = {
|
|
144
|
+
observed: 0,
|
|
145
|
+
measured: 0,
|
|
146
|
+
sourceMatched: 0,
|
|
147
|
+
agentInferred: 0,
|
|
148
|
+
manual: 0,
|
|
149
|
+
notProven: 0,
|
|
150
|
+
unknown: 0,
|
|
151
|
+
total: evidence.length
|
|
152
|
+
};
|
|
153
|
+
for (const item of evidence) {
|
|
154
|
+
if (item.status === "observed")
|
|
155
|
+
summary.observed += 1;
|
|
156
|
+
else if (item.status === "measured")
|
|
157
|
+
summary.measured += 1;
|
|
158
|
+
else if (item.status === "source-matched")
|
|
159
|
+
summary.sourceMatched += 1;
|
|
160
|
+
else if (item.status === "agent-inferred")
|
|
161
|
+
summary.agentInferred += 1;
|
|
162
|
+
else if (item.status === "manual")
|
|
163
|
+
summary.manual += 1;
|
|
164
|
+
else if (item.status === "not-proven")
|
|
165
|
+
summary.notProven += 1;
|
|
166
|
+
else
|
|
167
|
+
summary.unknown += 1;
|
|
168
|
+
}
|
|
169
|
+
return summary;
|
|
170
|
+
}
|