Skip to content

Commit 6c0535b

Browse files
committed
Add agent live stream
1 parent dafc296 commit 6c0535b

File tree

21 files changed

+848
-83
lines changed

21 files changed

+848
-83
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { DigmaLogoThemeableIcon } from "../../../../common/icons/24px/DigmaLogoThemeableIcon";
2+
import { KubernetesLogoIcon } from "../../../../common/icons/25px/KubernetesLogoIcon";
3+
import { PostgresLogoIcon } from "../../../../common/icons/25px/PostgresLogoIcon";
4+
import { GitHubLogoIcon } from "../../../../common/icons/28px/GitHubLogoIcon";
5+
import * as s from "./styles";
6+
import type { MCPServerBlockProps, MCPServerIconProps } from "./types";
7+
8+
export const MCPServerIcon = ({ type, isActive }: MCPServerIconProps) => {
9+
switch (type) {
10+
case "github":
11+
return <GitHubLogoIcon size={27} color={"currentColor"} />;
12+
case "postgres":
13+
return <PostgresLogoIcon size={27} color={"currentColor"} />;
14+
case "kubernetes":
15+
return <KubernetesLogoIcon size={27} color={"currentColor"} />;
16+
case "digma":
17+
return (
18+
<DigmaLogoThemeableIcon
19+
size={27}
20+
color={"currentColor"}
21+
themeKind={isActive ? "light" : "dark"}
22+
/>
23+
);
24+
default:
25+
return null;
26+
}
27+
};
28+
29+
export const MCPServerBlock = ({ type, isActive }: MCPServerBlockProps) => {
30+
return (
31+
<s.MCPServerBlock $isActive={isActive}>
32+
<MCPServerIcon type={type} isActive={isActive} />
33+
</s.MCPServerBlock>
34+
);
35+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import styled from "styled-components";
2+
import type { MCPServerBlockElementProps } from "./types";
3+
4+
export const MCPServerBlock = styled.div<MCPServerBlockElementProps>`
5+
display: flex;
6+
align-items: center;
7+
justify-content: center;
8+
width: 50px;
9+
height: 50px;
10+
border-radius: 9px;
11+
border: 1px solid rgb(255 255 255 / 10%);
12+
color: ${({ theme, $isActive }) =>
13+
$isActive ? theme.colors.v3.text.primary : "#3B3D46"};
14+
background: ${({ $isActive }) =>
15+
$isActive
16+
? `linear-gradient(180deg, #28292D 0%, #1A1B1E 100%), linear-gradient(180deg, rgb(255 255 255 / 10%) 0%, rgb(255 255 255 / 0%) 100%)`
17+
: "none"};
18+
`;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export interface MCPServerIconProps {
2+
type: string;
3+
isActive?: boolean;
4+
}
5+
6+
export interface MCPServerBlockProps {
7+
type: string;
8+
isActive?: boolean;
9+
}
10+
11+
export interface MCPServerBlockElementProps {
12+
$isActive?: boolean;
13+
}

src/components/Agentic/IncidentDetails/AgentFlowChart/index.tsx

Lines changed: 145 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
import type { Edge, Node } from "@xyflow/react";
1+
import { Position, type Edge } from "@xyflow/react";
2+
import { useAgenticDispatch } from "../../../../containers/Agentic/hooks";
23
import type {
34
Agent,
45
GetIncidentAgentsResponse
56
} from "../../../../redux/services/types";
7+
import { setAgentId } from "../../../../redux/slices/incidentsSlice";
68
import { FlowChart } from "../../common/FlowChart";
7-
import type { FlowChartNodeData } from "../../common/FlowChart/FlowChartNode";
9+
import type {
10+
FlowChartNode,
11+
FlowChartNodeData
12+
} from "../../common/FlowChart/FlowChartNode";
13+
import { MCPServerBlock } from "./MCPServerBlock";
14+
import * as s from "./styles";
815

916
const mockData: GetIncidentAgentsResponse = {
1017
agents: [
@@ -20,61 +27,165 @@ const mockData: GetIncidentAgentsResponse = {
2027
displayName: "Watchman",
2128
running: true,
2229
status: "active",
23-
mcpServers: []
30+
mcpServers: [
31+
{
32+
name: "github",
33+
displayName: "GitHub",
34+
active: false
35+
},
36+
{
37+
name: "postgres",
38+
displayName: "Postgres",
39+
active: false
40+
},
41+
{
42+
name: "digma",
43+
displayName: "Digma",
44+
active: true
45+
}
46+
]
2447
},
2548
{
26-
name: "triage",
49+
name: "triager",
2750
displayName: "Triage",
2851
running: false,
2952
status: "pending",
30-
mcpServers: []
53+
mcpServers: [
54+
{
55+
name: "github",
56+
displayName: "GitHub",
57+
active: false
58+
},
59+
{
60+
name: "postgres",
61+
displayName: "Postgres",
62+
active: true
63+
},
64+
{
65+
name: "digma",
66+
displayName: "Digma",
67+
active: true
68+
}
69+
]
3170
},
3271
{
33-
name: "infraResolution",
72+
name: "infra_resolver",
3473
displayName: "Infra Resolution",
3574
running: false,
3675
status: "pending",
37-
mcpServers: []
76+
mcpServers: [
77+
{
78+
name: "github",
79+
displayName: "GitHub",
80+
active: false
81+
},
82+
{
83+
name: "kubernetes",
84+
displayName: "Kubernetes",
85+
active: true
86+
},
87+
{
88+
name: "digma",
89+
displayName: "Digma",
90+
active: false
91+
}
92+
]
3893
},
3994
{
40-
name: "codeResolution",
95+
name: "code_resolver",
4196
displayName: "Code Resolution",
4297
running: false,
4398
status: "inactive",
44-
mcpServers: []
99+
mcpServers: [
100+
{
101+
name: "github",
102+
displayName: "GitHub",
103+
active: false
104+
},
105+
{
106+
name: "kubernetes",
107+
displayName: "Kubernetes",
108+
active: false
109+
},
110+
{
111+
name: "digma",
112+
displayName: "Digma",
113+
active: false
114+
}
115+
]
45116
},
46117
{
47118
name: "validator",
48119
displayName: "Validator",
49120
running: false,
50121
status: "pending",
51-
mcpServers: []
122+
mcpServers: [
123+
{
124+
name: "github",
125+
displayName: "GitHub",
126+
active: true
127+
},
128+
{
129+
name: "postgres",
130+
displayName: "Postgres",
131+
active: false
132+
},
133+
{
134+
name: "digma",
135+
displayName: "Digma",
136+
active: false
137+
}
138+
]
52139
}
53140
]
54141
};
55142

56143
// const REFRESH_INTERVAL = 10 * 1000; // in milliseconds
57144

58-
const getFlowChartNodeData = (agent?: Agent): Partial<FlowChartNodeData> => {
145+
const getFlowChartNodeData = (
146+
agent?: Agent,
147+
sideContainerPosition?: Position
148+
): Partial<FlowChartNodeData> => {
59149
return agent
60150
? {
61151
label: agent.displayName,
62152
isActive: agent.running,
63-
isDisabled: agent.status === "inactive"
153+
isDisabled: agent.status === "inactive",
154+
sideContainer: {
155+
isVisible: agent.mcpServers.length > 0,
156+
position: sideContainerPosition,
157+
element: (
158+
<s.MCPServersSideContainer>
159+
{agent.mcpServers.map((x) => (
160+
<MCPServerBlock
161+
key={x.name}
162+
type={x.name}
163+
isActive={x.active}
164+
/>
165+
))}
166+
</s.MCPServersSideContainer>
167+
)
168+
}
64169
}
65170
: {};
66171
};
67172

68173
export const AgentFlowChart = () => {
69174
// const incidentId = useAgenticSelector((state) => state.incidents.incidentId);
175+
const dispatch = useAgenticDispatch();
176+
70177
// const { data } = useGetIncidentAgentsQuery(
71178
// { id: incidentId ?? "" },
72179
// { skip: !incidentId, pollingInterval: REFRESH_INTERVAL }
73180
// );
74181

75182
const data = mockData; // TODO: remove this line and uncomment the above line
76183

77-
const nodes: Node[] = data
184+
const handleNodeClick = (id: string) => {
185+
dispatch(setAgentId(id));
186+
};
187+
188+
const nodes: FlowChartNode[] = data
78189
? [
79190
{
80191
id: "digma",
@@ -97,29 +208,30 @@ export const AgentFlowChart = () => {
97208
}
98209
},
99210
{
100-
id: "triage",
211+
id: "triager",
101212
position: { x: 500, y: 0 },
102213
data: {
103214
...getFlowChartNodeData(
104-
data?.agents.find((a) => a.name === "triage")
215+
data?.agents.find((a) => a.name === "triager")
105216
)
106217
}
107218
},
108219
{
109-
id: "infraResolution",
220+
id: "infra_resolver",
110221
position: { x: 800, y: -50 },
111222
data: {
112223
...getFlowChartNodeData(
113-
data?.agents.find((a) => a.name === "infraResolution")
224+
data?.agents.find((a) => a.name === "infra_resolver")
114225
)
115226
}
116227
},
117228
{
118-
id: "codeResolution",
229+
id: "code_resolver",
119230
position: { x: 800, y: 50 },
120231
data: {
121232
...getFlowChartNodeData(
122-
data?.agents.find((a) => a.name === "codeResolution")
233+
data?.agents.find((a) => a.name === "code_resolver"),
234+
Position.Bottom
123235
)
124236
}
125237
},
@@ -139,29 +251,31 @@ export const AgentFlowChart = () => {
139251
const edges: Edge[] = data
140252
? [
141253
{ id: "digma-watchman", source: "digma", target: "watchman" },
142-
{ id: "watchman-triage", source: "watchman", target: "triage" },
254+
{ id: "watchman-triager", source: "watchman", target: "triager" },
143255
{
144-
id: "triage-infraResolution",
145-
source: "triage",
146-
target: "infraResolution"
256+
id: "triager-infra_resolver",
257+
source: "triager",
258+
target: "infra_resolver"
147259
},
148260
{
149-
id: "triage-codeResolution",
150-
source: "triage",
151-
target: "codeResolution"
261+
id: "triager-code_resolver",
262+
source: "triager",
263+
target: "code_resolver"
152264
},
153265
{
154-
id: "infraResolution-validator",
155-
source: "infraResolution",
266+
id: "infra_resolver-validator",
267+
source: "infra_resolver",
156268
target: "validator"
157269
},
158270
{
159-
id: "codeResolution-validator",
160-
source: "codeResolution",
271+
id: "code_resolver-validator",
272+
source: "code_resolver",
161273
target: "validator"
162274
}
163275
]
164276
: [];
165277

166-
return <FlowChart nodes={nodes} edges={edges} />;
278+
return (
279+
<FlowChart nodes={nodes} edges={edges} onNodeClick={handleNodeClick} />
280+
);
167281
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import styled from "styled-components";
2+
3+
export const MCPServersSideContainer = styled.div`
4+
display: flex;
5+
gap: 13px;
6+
`;

0 commit comments

Comments
 (0)