Skip to content

Commit dee647e

Browse files
authored
Merge pull request #1265 from oliviajanejohns/hackday
Visualizer Not Displaying Interfaces #1090
2 parents 0dddfe1 + 4b55c0f commit dee647e

File tree

8 files changed

+281
-163
lines changed

8 files changed

+281
-163
lines changed

calm-hub-ui/src/visualizer/components/cytoscape-renderer/CytoscapeRenderer.tsx

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ import nodeEdgeHtmlLabel from 'cytoscape-node-edge-html-label';
55
import expandCollapse from 'cytoscape-expand-collapse';
66
import { Sidebar } from '../sidebar/Sidebar.js';
77
import { ZoomContext } from '../zoom-context.provider.js';
8+
import {
9+
CalmInterfaceTypeSchema,
10+
CalmHostPortInterfaceSchema,
11+
CalmHostnameInterfaceSchema,
12+
CalmPathInterfaceSchema,
13+
CalmOAuth2AudienceInterfaceSchema,
14+
CalmURLInterfaceSchema,
15+
CalmRateLimitInterfaceSchema,
16+
CalmContainerImageInterfaceSchema,
17+
CalmPortInterfaceSchema,
18+
} from '../../../../../shared/src/types/interface-types.js';
19+
import { CalmControlsSchema } from '../../../../../shared/src/types/control-types.js';
820

921
// Initialize Cytoscape plugins
1022
nodeEdgeHtmlLabel(cytoscape);
@@ -23,7 +35,7 @@ const breadthFirstLayout = {
2335
};
2436

2537
// Types for nodes and edges
26-
export type Node = {
38+
export type CalmNode = {
2739
classes?: string;
2840
data: {
2941
description: string;
@@ -32,7 +44,19 @@ export type Node = {
3244
id: string;
3345
_displayPlaceholderWithDesc: string;
3446
_displayPlaceholderWithoutDesc: string;
35-
[idx: string]: string;
47+
parent?: string;
48+
interfaces?: (
49+
| CalmInterfaceTypeSchema
50+
| CalmHostPortInterfaceSchema
51+
| CalmHostnameInterfaceSchema
52+
| CalmPathInterfaceSchema
53+
| CalmOAuth2AudienceInterfaceSchema
54+
| CalmURLInterfaceSchema
55+
| CalmRateLimitInterfaceSchema
56+
| CalmContainerImageInterfaceSchema
57+
| CalmPortInterfaceSchema
58+
)[];
59+
controls?: CalmControlsSchema;
3660
};
3761
};
3862

@@ -50,7 +74,7 @@ interface Props {
5074
title?: string;
5175
isNodeDescActive: boolean;
5276
isConDescActive: boolean;
53-
nodes: Node[];
77+
nodes: CalmNode[];
5478
edges: Edge[];
5579
}
5680

@@ -64,13 +88,12 @@ export const CytoscapeRenderer = ({
6488
const cyRef = useRef<HTMLDivElement>(null);
6589
const [cy, setCy] = useState<Core | null>(null);
6690
const { zoomLevel, updateZoom } = useContext(ZoomContext);
67-
const [selectedNode, setSelectedNode] = useState<Node['data'] | null>(null);
68-
const [selectedEdge, setSelectedEdge] = useState<Edge['data'] | null>(null);
91+
const [selectedItem, setSelectedItem] = useState<CalmNode['data'] | Edge['data'] | null>(null);
6992

7093
// Generate node label templates
7194
const getNodeLabelTemplateGenerator =
7295
(selected = false) =>
73-
(data: Node['data']) => `
96+
(data: CalmNode['data']) => `
7497
<div class="node element ${selected ? 'selected-node' : ''}">
7598
<p class="title">${data.label}</p>
7699
<p class="type">${data.type}</p>
@@ -108,12 +131,14 @@ export const CytoscapeRenderer = ({
108131
{
109132
selector: 'node',
110133
style: {
111-
label: isNodeDescActive ? 'data(_displayPlaceholderWithDesc)' : 'data(_displayPlaceholderWithoutDesc)',
134+
label: isNodeDescActive
135+
? 'data(_displayPlaceholderWithDesc)'
136+
: 'data(_displayPlaceholderWithoutDesc)',
112137
'text-valign': 'center',
113138
'text-halign': 'center',
114139
'text-wrap': 'wrap',
115140
'text-max-width': '180px',
116-
"font-family": 'Arial',
141+
'font-family': 'Arial',
117142
width: '200px',
118143
height: 'label',
119144
shape: 'rectangle',
@@ -139,14 +164,12 @@ export const CytoscapeRenderer = ({
139164
// Add event listeners
140165
updatedCy.on('tap', 'node', (e) => {
141166
const node = e.target as NodeSingular;
142-
setSelectedEdge(null);
143-
setSelectedNode(node?.data());
167+
setSelectedItem(node?.data());
144168
});
145169

146170
updatedCy.on('tap', 'edge', (e) => {
147171
const edge = e.target as EdgeSingular;
148-
setSelectedNode(null);
149-
setSelectedEdge(edge?.data());
172+
setSelectedItem(edge?.data());
150173
});
151174

152175
updatedCy.on('zoom', () => updateZoom(updatedCy.zoom()));
@@ -192,11 +215,8 @@ export const CytoscapeRenderer = ({
192215
</div>
193216
)}
194217
<div ref={cyRef} className="flex-1 bg-white visualizer" style={{ height: '100vh' }} />
195-
{selectedNode && (
196-
<Sidebar selectedData={selectedNode} closeSidebar={() => setSelectedNode(null)} />
197-
)}
198-
{selectedEdge && (
199-
<Sidebar selectedData={selectedEdge} closeSidebar={() => setSelectedEdge(null)} />
218+
{selectedItem && (
219+
<Sidebar selectedData={selectedItem} closeSidebar={() => setSelectedItem(null)} />
200220
)}
201221
</div>
202222
);

calm-hub-ui/src/visualizer/components/drawer/Drawer.tsx

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,80 @@
11
import { Sidebar } from '../sidebar/Sidebar.js';
22
import { useState } from 'react';
3-
import { CytoscapeRenderer, Node, Edge } from '../cytoscape-renderer/CytoscapeRenderer.js';
3+
import { CytoscapeRenderer, CalmNode, Edge } from '../cytoscape-renderer/CytoscapeRenderer.js';
44
import {
5+
CalmArchitectureSchema,
6+
CalmRelationshipSchema,
7+
} from '../../../../../shared/src/types/core-types.js';
8+
import {
9+
CALMDeployedInRelationship,
510
CALMComposedOfRelationship,
611
CALMConnectsRelationship,
7-
CALMDeployedInRelationship,
812
CALMInteractsRelationship,
9-
CALMRelationship,
10-
CALMArchitecture,
1113
} from '../../../../../shared/src/types.js';
1214

1315
interface DrawerProps {
14-
calmInstance?: CALMArchitecture;
16+
calmInstance?: CalmArchitectureSchema;
1517
title?: string;
1618
isNodeDescActive: boolean;
1719
isConDescActive: boolean;
1820
}
1921

20-
function isComposedOf(relationship: CALMRelationship): relationship is CALMComposedOfRelationship {
22+
function isComposedOf(
23+
relationship: CalmRelationshipSchema
24+
): relationship is CALMComposedOfRelationship {
2125
return 'composed-of' in relationship['relationship-type'];
2226
}
2327

24-
function isDeployedIn(relationship: CALMRelationship): relationship is CALMDeployedInRelationship {
28+
function isDeployedIn(
29+
relationship: CalmRelationshipSchema
30+
): relationship is CALMDeployedInRelationship {
2531
return 'deployed-in' in relationship['relationship-type'];
2632
}
2733

28-
function isInteracts(relationship: CALMRelationship): relationship is CALMInteractsRelationship {
34+
function isInteracts(
35+
relationship: CalmRelationshipSchema
36+
): relationship is CALMInteractsRelationship {
2937
return 'interacts' in relationship['relationship-type'];
3038
}
3139

32-
function isConnects(relationship: CALMRelationship): relationship is CALMConnectsRelationship {
40+
function isConnects(
41+
relationship: CalmRelationshipSchema
42+
): relationship is CALMConnectsRelationship {
3343
return 'connects' in relationship['relationship-type'];
3444
}
3545

36-
function getComposedOfRelationships(calmInstance: CALMArchitecture) {
46+
function getComposedOfRelationships(calmInstance: CalmArchitectureSchema) {
3747
const composedOfRelationships: {
3848
[idx: string]: {
3949
type: 'parent' | 'child';
4050
parent?: string;
4151
};
4252
} = {};
4353

44-
calmInstance.relationships.forEach((relationship) => {
54+
calmInstance.relationships?.forEach((relationship) => {
4555
if (isComposedOf(relationship)) {
4656
const rel = relationship['relationship-type']['composed-of'];
47-
composedOfRelationships[rel['container']] = { type: 'parent' };
48-
rel['nodes'].forEach((node) => {
57+
composedOfRelationships[rel!['container']] = { type: 'parent' };
58+
rel!['nodes'].forEach((node) => {
4959
composedOfRelationships[node] = {
5060
type: 'child',
51-
parent: rel['container'],
61+
parent: rel!['container'],
5262
};
5363
});
5464
}
5565
});
5666

5767
return composedOfRelationships;
5868
}
59-
function getDeployedInRelationships(calmInstance: CALMArchitecture) {
69+
70+
function getDeployedInRelationships(calmInstance: CalmArchitectureSchema) {
6071
const deployedInRelationships: {
6172
[idx: string]: {
6273
type: 'parent' | 'child';
6374
parent?: string;
6475
};
6576
} = {};
66-
calmInstance.relationships.forEach((relationship) => {
77+
calmInstance.relationships?.forEach((relationship) => {
6778
if (isDeployedIn(relationship)) {
6879
const rel = relationship['relationship-type']['deployed-in'];
6980
deployedInRelationships[rel['container']] = { type: 'parent' };
@@ -80,63 +91,60 @@ function getDeployedInRelationships(calmInstance: CALMArchitecture) {
8091
}
8192

8293
export function Drawer({ calmInstance, title, isConDescActive, isNodeDescActive }: DrawerProps) {
83-
const [selectedNode, setSelectedNode] = useState(null);
94+
const [selectedNode, setSelectedNode] = useState<CalmNode | null>(null);
8495

8596
function closeSidebar() {
8697
setSelectedNode(null);
8798
}
8899

89-
function getNodes(): Node[] {
100+
function getNodes(): CalmNode[] {
90101
if (!calmInstance || !calmInstance.relationships) return [];
91102

92103
const composedOfRelationships = getComposedOfRelationships(calmInstance);
93104
const deployedInRelationships = getDeployedInRelationships(calmInstance);
94-
const nodes = calmInstance.nodes.map((node) => {
95-
const newData: Node = {
105+
106+
return (calmInstance.nodes ?? []).map((node) => {
107+
const newData: CalmNode = {
96108
classes: 'node',
97109
data: {
98110
label: node.name,
99111
description: node.description,
100112
type: node['node-type'],
101113
id: node['unique-id'],
102-
//Used to make the size of the node scale dynamically
103114
_displayPlaceholderWithDesc: `${node.name}\n\n\n${node['node-type']}\n\n\n${node.description}\n`,
104115
_displayPlaceholderWithoutDesc: `${node.name}\n\n\n${node['node-type']}`,
105116
},
106117
};
107118

108-
if (composedOfRelationships[node['unique-id']]?.type === 'parent') {
109-
newData.classes = 'group';
119+
if (node.interfaces) {
120+
newData.data.interfaces = node.interfaces;
110121
}
111122

112-
if (
113-
composedOfRelationships[node['unique-id']]?.type === 'child' &&
114-
composedOfRelationships[node['unique-id']]['parent']
115-
) {
116-
newData.data.parent = composedOfRelationships[node['unique-id']].parent!;
117-
}
123+
const composedOfRel = composedOfRelationships[node['unique-id']];
124+
const deployedInRel = deployedInRelationships[node['unique-id']];
118125

119-
if (deployedInRelationships[node['unique-id']]?.type === 'parent') {
126+
if (composedOfRel?.type === 'parent' || deployedInRel?.type === 'parent') {
120127
newData.classes = 'group';
121128
}
122129

123-
if (
124-
deployedInRelationships[node['unique-id']]?.type === 'child' &&
125-
deployedInRelationships[node['unique-id']]['parent'] &&
126-
!newData.data.parent
127-
) {
128-
newData.data.parent = deployedInRelationships[node['unique-id']].parent!;
130+
const parentId =
131+
composedOfRel?.type === 'child' && composedOfRel.parent
132+
? composedOfRel.parent
133+
: deployedInRel?.type === 'child' && deployedInRel.parent
134+
? deployedInRel.parent
135+
: undefined;
136+
137+
if (parentId) {
138+
newData.data.parent = parentId;
129139
}
130140
return newData;
131141
});
132-
133-
return nodes;
134142
}
135143

136144
function getEdges(): Edge[] {
137145
if (!calmInstance || !calmInstance.relationships) return [];
138146

139-
const edges = calmInstance.relationships
147+
return calmInstance.relationships
140148
.filter((relationship) => !isComposedOf(relationship) && !isDeployedIn(relationship))
141149
.map((relationship) => {
142150
if (isInteracts(relationship)) {
@@ -162,8 +170,7 @@ export function Drawer({ calmInstance, title, isConDescActive, isNodeDescActive
162170
};
163171
}
164172
})
165-
.filter((edge) => edge !== undefined);
166-
return edges;
173+
.filter((edge): edge is Edge => edge !== undefined);
167174
}
168175

169176
const edges = getEdges();
@@ -195,7 +202,7 @@ export function Drawer({ calmInstance, title, isConDescActive, isNodeDescActive
195202
)}
196203
</div>
197204
{selectedNode && (
198-
<Sidebar selectedData={selectedNode} closeSidebar={closeSidebar} />
205+
<Sidebar selectedData={selectedNode['data']} closeSidebar={closeSidebar} />
199206
)}
200207
</div>
201208
</div>

calm-hub-ui/src/visualizer/components/menu/Menu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function Menu({
5555
name="connection-description"
5656
aria-label="connection-description"
5757
checked={isConDescActive}
58-
onClick={toggleConnectionDesc}
58+
onChange={toggleConnectionDesc}
5959
/>
6060
</label>
6161
<label className="label cursor-pointer">
@@ -67,7 +67,7 @@ export function Menu({
6767
className="toggle"
6868
aria-label="node-description"
6969
checked={isNodeDescActive}
70-
onClick={toggleNodeDesc}
70+
onChange={toggleNodeDesc}
7171
/>
7272
</label>
7373
</>

0 commit comments

Comments
 (0)