Skip to content

Commit 03fbc86

Browse files
committed
feat: in react ui, restore topology ui
This still needs some iteration. For one, if we have no dataflow info, the view shows up as blank. Signed-off-by: Nick Mitchell <[email protected]>
1 parent 2fbe7c5 commit 03fbc86

File tree

11 files changed

+247
-181
lines changed

11 files changed

+247
-181
lines changed

pdl-live-react/package-lock.json

Lines changed: 1 addition & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pdl-live-react/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"dependencies": {
2323
"@patternfly/react-code-editor": "^6.1.0",
2424
"@patternfly/react-core": "^6.1.0",
25-
"@patternfly/react-table": "^6.1.0",
2625
"@patternfly/react-topology": "^6.1.0",
2726
"@tauri-apps/api": "^2",
2827
"@tauri-apps/plugin-cli": "^2.2.0",

pdl-live-react/src/view/breadcrumbs/BreadcrumbBarForBlockId.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ export default function BreadcrumbBarForBlockId({
3737

3838
const crumbs = id.replace(/text\.\d+\./g, "").split(/\./)
3939

40+
if (def) {
41+
// We'll add one crumb for the def
42+
maxCrumbs--
43+
}
44+
4045
return (
4146
<BreadcrumbBar>
4247
<>

pdl-live-react/src/view/masonry/Masonry.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ export default function Masonry({ as, sml, model, children }: Props) {
2020
return (
2121
<ResponsiveMasonry columnsCountBreakPoints={breakpoints}>
2222
<MasonryView className="pdl-masonry-view">
23-
{children && (
24-
<div className="pdl-masonry-tile" data-padding={sml}>
25-
{children}
26-
</div>
23+
{(!children ? [] : Array.isArray(children) ? children : [children]).map(
24+
(child, idx) => (
25+
<div key={idx} className="pdl-masonry-tile" data-padding={sml}>
26+
{child}
27+
</div>
28+
),
2729
)}
2830
{model.map((props, idx) => (
2931
<MasonryTile

pdl-live-react/src/view/masonry/MasonryCombo.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect, useMemo, useState } from "react"
22
import { BackToTop, PageSection } from "@patternfly/react-core"
33

4+
import Memory from "../memory/Memory"
45
import Timeline from "../timeline/TimelineFromModel"
56

67
import Masonry from "./Masonry"
@@ -65,6 +66,7 @@ export default function MasonryCombo({ value }: Props) {
6566
>
6667
<Masonry model={masonry} as={as} sml={sml}>
6768
<Timeline model={base} numbering={numbering} />
69+
<Memory block={block} />
6870
</Masonry>
6971
</PageSection>
7072

Lines changed: 5 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,15 @@
1-
import prettyMs from "pretty-ms"
21
import { useMemo } from "react"
3-
import { Link, useLocation } from "react-router"
4-
5-
import {
6-
Table,
7-
Caption,
8-
Tbody,
9-
Td,
10-
Th,
11-
Thead,
12-
Tr,
13-
} from "@patternfly/react-table"
14-
15-
import Result from "../Result"
16-
import BreadcrumbBarForBlock from "../breadcrumbs/BreadcrumbBarForBlock"
17-
18-
import { hasResult } from "../../helpers"
2+
//import { Link, useLocation } from "react-router"
193

4+
import Topology from "./Topology"
205
import extractVariables from "./model"
216

227
type Props = {
238
block: import("../../pdl_ast").PdlBlock
249
}
2510

2611
export default function Variables({ block }: Props) {
27-
const { hash } = useLocation()
28-
const vars = useMemo(() => extractVariables(block), [block])
29-
30-
return (
31-
<Table variant="compact" isStriped>
32-
<Caption>This table shows the variable definitions and uses</Caption>
33-
34-
<Thead>
35-
<Tr>
36-
<Th modifier="fitContent">Start Time</Th>
37-
<Th modifier="fitContent">Location</Th>
38-
{/*<Th modifier="fitContent">Name</Th>*/}
39-
<Th modifier="fitContent">Where was this value defined?</Th>
40-
<Th modifier="wrap">Value</Th>
41-
</Tr>
42-
</Thead>
43-
44-
<Tbody>
45-
{vars.map(
46-
({ incrNanos, block, name, value, defsite, defsiteId }, idx) => (
47-
<Tr
48-
key={
49-
idx +
50-
"." +
51-
block.id +
52-
".use." +
53-
name +
54-
"." +
55-
defsite?.id +
56-
"." +
57-
idx
58-
}
59-
>
60-
<Td>
61-
{idx === 0 ? (
62-
new Date((block.start_nanos || 0) / 1000000).toLocaleString()
63-
) : incrNanos === 0 ? (
64-
<>&mdash;</>
65-
) : (
66-
"+" + prettyMs(incrNanos / 1000000)
67-
)}
68-
</Td>
69-
<Td>
70-
<BreadcrumbBarForBlock block={block} />
71-
</Td>
72-
{/*<Td>{name}</Td>*/}
73-
<Td>
74-
{defsite ? (
75-
<BreadcrumbBarForBlock block={defsite} />
76-
) : defsiteId ? (
77-
<>
78-
This is a use of a literal value defined{" "}
79-
<Link
80-
to={`?detail&type=block&id=${encodeURIComponent(defsiteId.replace(/\.\d+$/, ""))}${hash}`}
81-
>
82-
here
83-
</Link>
84-
.
85-
</>
86-
) : (
87-
"This is a new definition"
88-
)}
89-
</Td>
90-
<Td>
91-
<Result
92-
result={hasResult(value) ? value.result : value}
93-
term=""
94-
/>
95-
</Td>
96-
</Tr>
97-
),
98-
)}
99-
</Tbody>
100-
</Table>
101-
)
12+
//const { hash } = useLocation()
13+
const { nodes, edges } = useMemo(() => extractVariables(block), [block])
14+
return <Topology nodes={nodes} edges={edges} />
10215
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { type FunctionComponent } from "react"
2+
import {
3+
DefaultNode,
4+
type GraphElement,
5+
type WithSelectionProps,
6+
} from "@patternfly/react-topology"
7+
8+
type CustomNodeProps = WithSelectionProps & {
9+
element: GraphElement
10+
}
11+
12+
const CustomNode: FunctionComponent<CustomNodeProps> = (
13+
props: CustomNodeProps,
14+
) => {
15+
const label = props.element.getLabel()
16+
const badge = label[0].toUpperCase()
17+
const badgeColor = /read/.test(label)
18+
? "var(--pf-t--global--color--nonstatus--orange--default)"
19+
: /code/.test(label)
20+
? "var(--pf-t--global--color--nonstatus--blue--default)"
21+
: /LLM/.test(label)
22+
? "var(--pf-t--global--color--nonstatus--teal--default)"
23+
: undefined
24+
console.error(label, badgeColor)
25+
/*const content =
26+
data && "content" in data && typeof data.content === "string"
27+
? data.content
28+
: null*/
29+
30+
/* badge={(ordinal !== undefined ? `[${ordinal}] ` : "") + variant}
31+
badgeColor={
32+
variant === "Final Result"
33+
? "var(--pf-t--global--icon--color--status--success--default)"
34+
: "var(--pf-t--global--color--brand--default)"
35+
}
36+
badgeTextColor="var(--pf-t--global--background--color--primary--default)"
37+
badgeBorderColor="transparent"
38+
*/
39+
40+
return (
41+
<DefaultNode {...props} badge={badge} badgeColor={badgeColor}>
42+
{/*content && (
43+
<g
44+
transform={`translate(${(-Math.min(30, content.length - 1) * 3.5) / 2 + 5}, 10.5)`}
45+
>
46+
<text className="pdl-dataflow-content">
47+
{data.content.slice(0, 30)}
48+
</text>
49+
</g>
50+
)*/}
51+
</DefaultNode>
52+
)
53+
}
54+
55+
export default CustomNode
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { useEffect, useMemo, useState } from "react"
2+
3+
import {
4+
EdgeAnimationSpeed,
5+
EdgeModel,
6+
EdgeStyle,
7+
Model,
8+
NodeModel,
9+
NodeShape,
10+
SELECTION_EVENT,
11+
Visualization,
12+
VisualizationProvider,
13+
VisualizationSurface,
14+
} from "@patternfly/react-topology"
15+
16+
import layoutFactory from "./layout"
17+
import componentFactory from "./components"
18+
19+
const NODE_SHAPE = NodeShape.ellipse
20+
const NODE_DIAMETER = 10
21+
22+
type Props = {
23+
nodes: import("./model").Node[]
24+
edges: import("./model").Edge[]
25+
}
26+
27+
export default function Topology({ nodes, edges }: Props) {
28+
const [selectedIds, setSelectedIds] = useState<string[]>([])
29+
30+
const controller = useMemo(() => {
31+
const newController = new Visualization()
32+
newController.registerLayoutFactory(layoutFactory)
33+
newController.registerComponentFactory(componentFactory)
34+
35+
newController.addEventListener(SELECTION_EVENT, setSelectedIds)
36+
return newController
37+
}, [])
38+
39+
useEffect(() => {
40+
const myNodes: NodeModel[] = nodes.map(({ id, label }) => ({
41+
id,
42+
label,
43+
type: "node",
44+
width: NODE_DIAMETER,
45+
height: NODE_DIAMETER,
46+
shape: NODE_SHAPE,
47+
}))
48+
const myEdges: EdgeModel[] = edges.map(({ source, target }) => ({
49+
id: `${source}-${target}`,
50+
type: "edge",
51+
source,
52+
target,
53+
edgeStyle: EdgeStyle.dashedMd,
54+
animationSpeed: EdgeAnimationSpeed.medium,
55+
}))
56+
const model: Model = {
57+
nodes: myNodes,
58+
edges: myEdges,
59+
graph: {
60+
id: "g1",
61+
type: "graph",
62+
layout: "Cola",
63+
},
64+
}
65+
66+
controller.fromModel(model, false)
67+
}, [nodes, edges, controller])
68+
69+
return (
70+
<VisualizationProvider controller={controller}>
71+
<VisualizationSurface state={{ selectedIds }} />
72+
</VisualizationProvider>
73+
)
74+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {
2+
DefaultEdge,
3+
DefaultGroup,
4+
ModelKind,
5+
withPanZoom,
6+
withSelection,
7+
GraphComponent,
8+
type ComponentFactory,
9+
} from "@patternfly/react-topology"
10+
11+
import CustomNode from "./Node"
12+
13+
const componentFactory: ComponentFactory = (kind: ModelKind, type: string) => {
14+
switch (type) {
15+
case "group":
16+
return DefaultGroup
17+
default:
18+
switch (kind) {
19+
case ModelKind.graph:
20+
return withPanZoom()(GraphComponent)
21+
case ModelKind.node:
22+
return withSelection()(CustomNode)
23+
case ModelKind.edge:
24+
return DefaultEdge
25+
default:
26+
return undefined
27+
}
28+
}
29+
}
30+
31+
export default componentFactory
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import {
2+
ForceLayout as ColaLayout,
3+
Graph,
4+
Layout,
5+
LayoutFactory,
6+
} from "@patternfly/react-topology"
7+
8+
const layoutFactory: LayoutFactory = (
9+
type: string,
10+
graph: Graph,
11+
): Layout | undefined => {
12+
switch (type) {
13+
case "Cola":
14+
return new ColaLayout(graph)
15+
default:
16+
return new ColaLayout(graph, { layoutOnDrag: false })
17+
}
18+
}
19+
20+
export default layoutFactory

0 commit comments

Comments
 (0)