Skip to content

Commit 4fe25dc

Browse files
authored
Merge pull request #417 from easyops-cn/steve/parse-module
feat(tsx-parser): refactor as module
2 parents ccc2cea + 2db41ba commit 4fe25dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+3049
-3070
lines changed

bricks/ai-portal/src/cruise-canvas/CruiseCanvas.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import { NodeRequirement } from "./NodeRequirement/NodeRequirement.js";
3636
import { NodeInstruction } from "./NodeInstruction/NodeInstruction.js";
3737
import { NodeJob } from "./NodeJob/NodeJob.js";
3838
import { NodeEnd } from "./NodeEnd/NodeEnd.js";
39-
import { NodeView } from "./NodeView/NodeView.js";
4039
import {
4140
CANVAS_PADDING_BOTTOM,
4241
CANVAS_PADDING_LEFT,
@@ -740,29 +739,19 @@ export function CruiseCanvasComponent(
740739
if (action === "scroll") {
741740
scrollBy(keyboardAction.direction, keyboardAction.range);
742741
} else if (action === "enter") {
743-
if (node.type !== "job" && node.type !== "view") {
744-
return;
745-
}
746-
const askUser = node.job.toolCall?.name === "ask_human";
747-
const askUserPlan =
748-
node.job.toolCall?.name === "ask_human_confirming_plan";
749-
if (askUser || askUserPlan) {
742+
if (node.type !== "job") {
750743
return;
751744
}
752745
}
753746
e.preventDefault();
754747
e.stopPropagation();
755748

756749
if (action === "enter") {
757-
if (node.type === "view") {
758-
setActiveExpandedViewJobId(node.job.id);
759-
} else {
760-
setActiveToolCallJobId((node as JobGraphNode).job.id);
761-
}
750+
setActiveToolCallJobId((node as JobGraphNode).job.id);
762751
} else if (action === "switch-active-node") {
763752
if (node) {
764753
setActiveNodeId(node.id);
765-
if (node.type === "job" || node.type === "view") {
754+
if (node.type === "job") {
766755
scrollTo({
767756
jobId: node.job.id,
768757
behavior: "smooth",
@@ -1006,8 +995,6 @@ function NodeComponent({
1006995
content={job!.instruction}
1007996
loading={instructionLoading}
1008997
/>
1009-
) : type === "view" ? (
1010-
<NodeView job={job!} active={active} />
1011998
) : (
1012999
<NodeJob job={job!} active={active} isLeaf={isLeaf} />
10131000
)}

bricks/ai-portal/src/cruise-canvas/NodeJob/NodeJob.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
.heading {
5555
display: flex;
5656
align-items: center;
57+
justify-content: space-between;
5758
padding: 0 5px 5px;
5859
font-size: 13px;
5960
color: #8c8c8c;
@@ -127,3 +128,7 @@
127128
background: transparent; /* 轨道背景透明 */
128129
}
129130
}
131+
132+
.view-container {
133+
margin-top: 10px;
134+
}

bricks/ai-portal/src/cruise-canvas/NodeJob/NodeJob.tsx

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// istanbul ignore file: experimental
2-
import React, { useMemo } from "react";
2+
import React, {
3+
useCallback,
4+
useContext,
5+
useMemo,
6+
useRef,
7+
useState,
8+
} from "react";
39
import classNames from "classnames";
410
import styles from "./NodeJob.module.css";
511
import sharedStyles from "../shared.module.css";
@@ -11,6 +17,9 @@ import { CmdbInstanceDetail } from "../CmdbInstanceDetail/CmdbInstanceDetail";
1117
import { FileList } from "../FileList/FileList";
1218
import { RequestHumanAction } from "../../shared/RequestHumanAction/RequestHumanAction";
1319
import { AIEmployeeAvatar } from "../AIEmployeeAvatar/AIEmployeeAvatar";
20+
import { CreatedView } from "../../shared/CreatedView/CreatedView";
21+
import { CanvasContext } from "../CanvasContext";
22+
import { ViewToolbar } from "../../shared/CreatedView/ViewToolbar";
1423

1524
// 当 markdown 中包含超过 4 列的表格时,对节点使用大尺寸样式
1625
const RegExpLargeTableInMarkdown = /^\s*\|(?:\s*:?-+:?\s*\|){4,}\s*$/m;
@@ -64,18 +73,25 @@ export function NodeJob({ job, active, isLeaf }: NodeJobProps): JSX.Element {
6473
return [markdownContent, instanceDetails, files, large] as const;
6574
}, [job.messages, toolName]);
6675

76+
const [viewSize, setViewSize] = useState<"medium" | "large">("medium");
77+
78+
const handleViewSizeChange = useCallback((value: "medium" | "large") => {
79+
setViewSize(value);
80+
}, []);
81+
6782
return (
6883
<div
6984
className={classNames(styles["node-job"], {
7085
[styles.error]: job.isError,
7186
[styles.active]: active,
72-
[styles.large]: sizeLarge,
87+
[styles.large]: sizeLarge || viewSize === "large",
7388
})}
7489
>
7590
<div className={styles.background} />
7691
{job.aiEmployeeId ? (
7792
<div className={styles.heading}>
7893
<AIEmployeeAvatar aiEmployeeId={job.aiEmployeeId} />
94+
{job.generatedView ? <ViewToolbar job={job} /> : null}
7995
</div>
8096
) : null}
8197
<div className={styles.body}>
@@ -124,6 +140,70 @@ export function NodeJob({ job, active, isLeaf }: NodeJobProps): JSX.Element {
124140
<RequestHumanAction action={job.requestHumanAction} />
125141
)}
126142
</div>
143+
{job.generatedView ? (
144+
<ViewContainer job={job} onSizeChange={handleViewSizeChange} />
145+
) : null}
146+
</div>
147+
);
148+
}
149+
150+
interface ViewContainerProps {
151+
job: Job;
152+
onSizeChange?: (value: "medium" | "large") => void;
153+
}
154+
155+
function ViewContainer({ job, onSizeChange }: ViewContainerProps) {
156+
const ref = useRef<HTMLDivElement>(null);
157+
const { setHoverOnScrollableContent } = useContext(CanvasContext);
158+
159+
const handleMouseMove = useCallback(
160+
(e: React.MouseEvent) => {
161+
let found = false;
162+
let scrollableContent: HTMLElement | undefined;
163+
for (const el of e.nativeEvent.composedPath()) {
164+
if (el === ref.current) {
165+
break;
166+
}
167+
if (!(el instanceof HTMLElement)) {
168+
continue;
169+
}
170+
if (el.tagName === "PRE") {
171+
if (el.scrollWidth > el.clientWidth) {
172+
found = true;
173+
break;
174+
}
175+
} else if (el.classList.contains("ant-table-content")) {
176+
scrollableContent = el;
177+
} else if (
178+
el.classList.contains("ant-table") &&
179+
el.classList.contains("ant-table-scroll-horizontal")
180+
) {
181+
if (
182+
scrollableContent &&
183+
scrollableContent.scrollWidth > scrollableContent.clientWidth
184+
) {
185+
found = true;
186+
break;
187+
}
188+
}
189+
}
190+
setHoverOnScrollableContent(found);
191+
},
192+
[setHoverOnScrollableContent]
193+
);
194+
195+
const handleMouseLeave = useCallback(() => {
196+
setHoverOnScrollableContent(false);
197+
}, [setHoverOnScrollableContent]);
198+
199+
return (
200+
<div
201+
className={styles["view-container"]}
202+
ref={ref}
203+
onMouseMove={handleMouseMove}
204+
onMouseLeave={handleMouseLeave}
205+
>
206+
<CreatedView job={job} noHeading onSizeChange={onSizeChange} />
127207
</div>
128208
);
129209
}

bricks/ai-portal/src/cruise-canvas/interfaces.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export type GraphNode =
2020
| LoadingGraphNode
2121
| InstructionGraphNode
2222
| JobGraphNode
23-
| ViewGraphNode
2423
| StartGraphNode
2524
| EndGraphNode
2625
| ErrorGraphNode
@@ -47,11 +46,6 @@ export interface JobGraphNode extends BaseGraphNode {
4746
job: Job;
4847
}
4948

50-
export interface ViewGraphNode extends BaseGraphNode {
51-
type: "view";
52-
job: Job;
53-
}
54-
5549
export interface StartGraphNode extends BaseGraphNode {
5650
type: "start";
5751
}

bricks/ai-portal/src/cruise-canvas/useConversationGraph.spec.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe("useConversationGraph", () => {
134134
});
135135
});
136136

137-
it("should create view node when job has generatedView", () => {
137+
it("should collect views when job has generatedView", () => {
138138
const conversation = { id: "conv-1" } as ConversationBaseDetail;
139139
const tasks: Task[] = [
140140
{
@@ -154,12 +154,6 @@ describe("useConversationGraph", () => {
154154
useConversationGraph(conversation, tasks, [])
155155
);
156156

157-
expect(result.current?.nodes).toContainEqual({
158-
type: "view",
159-
id: "view:job-1",
160-
job: expect.objectContaining({ id: "job-1" }),
161-
});
162-
163157
expect(result.current?.views).toContainEqual({
164158
id: "job-1",
165159
view: { viewId: "view-1" },
@@ -255,11 +249,6 @@ describe("useConversationGraph", () => {
255249
source: "instruction:job-1",
256250
target: "job:job-1",
257251
});
258-
259-
expect(result.current?.edges).toContainEqual({
260-
source: "job:job-1",
261-
target: "view:job-1",
262-
});
263252
});
264253

265254
it("should create edges between dependent jobs", () => {

bricks/ai-portal/src/cruise-canvas/useConversationGraph.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,6 @@ export function useConversationGraph(
119119

120120
const view = job.generatedView;
121121
if (view) {
122-
// Add view node for job
123-
const viewNodeId = `view:${job.id}`;
124-
nodes.push({
125-
type: "view",
126-
id: viewNodeId,
127-
job,
128-
});
129-
nodeIds.push(viewNodeId);
130-
131122
views.push({
132123
id: job.id,
133124
view,

bricks/ai-portal/src/shared/CreatedView/CreatedView.module.css

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@
55
margin-bottom: 16px;
66
}
77

8-
.buttons {
9-
display: flex;
10-
align-items: center;
11-
gap: 8px;
12-
}
13-
148
.title {
159
font-size: 12px;
1610
min-width: 0;
@@ -28,21 +22,3 @@ ai-portal\.cruise-canvas .title {
2822
ai-portal\.cruise-canvas .heading {
2923
margin-bottom: 10px;
3024
}
31-
32-
.button {
33-
display: flex;
34-
background: none;
35-
border: none;
36-
padding: 3px;
37-
cursor: pointer;
38-
color: #595959;
39-
}
40-
41-
.button-lucide {
42-
font-size: 16px;
43-
padding: 2px;
44-
}
45-
46-
.button:hover {
47-
color: var(--elevo-color-brand);
48-
}

0 commit comments

Comments
 (0)