Spaces:
Running
Running
Update node metadata on execution.
Browse files
lynxkite-app/src/lynxkite_app/crdt.py
CHANGED
@@ -205,7 +205,7 @@ def try_to_load_workspace(ws: pycrdt.Map, name: str):
|
|
205 |
ws,
|
206 |
ws_pyd.model_dump(),
|
207 |
# We treat some fields as black boxes. They are not edited on the frontend.
|
208 |
-
non_collaborative_fields={"display", "input_metadata"},
|
209 |
)
|
210 |
|
211 |
|
@@ -264,17 +264,14 @@ async def execute(name: str, ws_crdt: pycrdt.Map, ws_pyd: workspace.Workspace, d
|
|
264 |
assert path.is_relative_to(cwd), "Provided workspace path is invalid"
|
265 |
# Save user changes before executing, in case the execution fails.
|
266 |
workspace.save(ws_pyd, path)
|
|
|
|
|
|
|
267 |
if not workspace.has_executor(ws_pyd):
|
268 |
return
|
269 |
-
ops.load_user_scripts(name)
|
270 |
-
ws_pyd._crdt = ws_crdt
|
271 |
with ws_crdt.doc.transaction():
|
272 |
-
for nc
|
273 |
-
if "data" not in nc:
|
274 |
-
nc["data"] = pycrdt.Map()
|
275 |
nc["data"]["status"] = "planned"
|
276 |
-
# Nodes get a reference to their CRDT maps, so they can update them as the results come in.
|
277 |
-
np._crdt = nc
|
278 |
ws_pyd = ws_pyd.normalize()
|
279 |
await workspace.execute(ws_pyd)
|
280 |
workspace.save(ws_pyd, path)
|
|
|
205 |
ws,
|
206 |
ws_pyd.model_dump(),
|
207 |
# We treat some fields as black boxes. They are not edited on the frontend.
|
208 |
+
non_collaborative_fields={"display", "input_metadata", "meta"},
|
209 |
)
|
210 |
|
211 |
|
|
|
264 |
assert path.is_relative_to(cwd), "Provided workspace path is invalid"
|
265 |
# Save user changes before executing, in case the execution fails.
|
266 |
workspace.save(ws_pyd, path)
|
267 |
+
ops.load_user_scripts(name)
|
268 |
+
workspace.connect_crdt(ws_pyd, ws_crdt)
|
269 |
+
workspace.update_metadata(ws_pyd)
|
270 |
if not workspace.has_executor(ws_pyd):
|
271 |
return
|
|
|
|
|
272 |
with ws_crdt.doc.transaction():
|
273 |
+
for nc in ws_crdt["nodes"]:
|
|
|
|
|
274 |
nc["data"]["status"] = "planned"
|
|
|
|
|
275 |
ws_pyd = ws_pyd.normalize()
|
276 |
await workspace.execute(ws_pyd)
|
277 |
workspace.save(ws_pyd, path)
|
lynxkite-app/web/src/workspace/nodes/LynxKiteNode.tsx
CHANGED
@@ -53,7 +53,7 @@ function LynxKiteNodeComponent(props: LynxKiteNodeProps) {
|
|
53 |
const reactFlow = useReactFlow();
|
54 |
const data = props.data;
|
55 |
const expanded = !data.collapsed;
|
56 |
-
const handles = getHandles(data.meta?.inputs || {}, data.meta?.outputs || {});
|
57 |
function titleClicked() {
|
58 |
reactFlow.updateNodeData(props.id, { collapsed: expanded });
|
59 |
}
|
@@ -64,8 +64,8 @@ function LynxKiteNodeComponent(props: LynxKiteNodeProps) {
|
|
64 |
right: "top",
|
65 |
};
|
66 |
const titleStyle: { backgroundColor?: string } = {};
|
67 |
-
if (data.meta?.color) {
|
68 |
-
titleStyle.backgroundColor = OP_COLORS[data.meta.color] || data.meta.color;
|
69 |
}
|
70 |
return (
|
71 |
<div
|
|
|
53 |
const reactFlow = useReactFlow();
|
54 |
const data = props.data;
|
55 |
const expanded = !data.collapsed;
|
56 |
+
const handles = getHandles(data.meta?.value?.inputs || {}, data.meta?.value?.outputs || {});
|
57 |
function titleClicked() {
|
58 |
reactFlow.updateNodeData(props.id, { collapsed: expanded });
|
59 |
}
|
|
|
64 |
right: "top",
|
65 |
};
|
66 |
const titleStyle: { backgroundColor?: string } = {};
|
67 |
+
if (data.meta?.value?.color) {
|
68 |
+
titleStyle.backgroundColor = OP_COLORS[data.meta.value.color] || data.meta.value.color;
|
69 |
}
|
70 |
return (
|
71 |
<div
|
lynxkite-app/web/src/workspace/nodes/NodeWithParams.tsx
CHANGED
@@ -10,7 +10,7 @@ export type UpdateOptions = { delay?: number };
|
|
10 |
|
11 |
export function NodeWithParams(props: any) {
|
12 |
const reactFlow = useReactFlow();
|
13 |
-
const metaParams = props.data.meta?.params;
|
14 |
const [collapsed, setCollapsed] = React.useState(props.collapsed);
|
15 |
|
16 |
function setParam(name: string, newValue: any, opts: UpdateOptions) {
|
|
|
10 |
|
11 |
export function NodeWithParams(props: any) {
|
12 |
const reactFlow = useReactFlow();
|
13 |
+
const metaParams = props.data.meta?.value?.params;
|
14 |
const [collapsed, setCollapsed] = React.useState(props.collapsed);
|
15 |
|
16 |
function setParam(name: string, newValue: any, opts: UpdateOptions) {
|
lynxkite-core/src/lynxkite/core/workspace.py
CHANGED
@@ -158,11 +158,11 @@ def load(path: str) -> Workspace:
|
|
158 |
j = f.read()
|
159 |
ws = Workspace.model_validate_json(j)
|
160 |
# Metadata is added after loading. This way code changes take effect on old boxes too.
|
161 |
-
|
162 |
return ws
|
163 |
|
164 |
|
165 |
-
def
|
166 |
"""Update the metadata of the given workspace object.
|
167 |
|
168 |
The metadata is the information about the operations that the nodes in the workspace represent,
|
@@ -175,22 +175,36 @@ def _update_metadata(ws: Workspace) -> Workspace:
|
|
175 |
Returns:
|
176 |
Workspace: The updated workspace object.
|
177 |
"""
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
data = node.data
|
187 |
-
op = catalog.get(data.title)
|
188 |
-
if op:
|
189 |
data.meta = op
|
|
|
|
|
|
|
190 |
node.type = op.type
|
191 |
-
if
|
192 |
-
|
193 |
-
|
194 |
-
data.error =
|
195 |
-
|
|
|
|
|
|
|
|
|
|
|
196 |
return ws
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
j = f.read()
|
159 |
ws = Workspace.model_validate_json(j)
|
160 |
# Metadata is added after loading. This way code changes take effect on old boxes too.
|
161 |
+
update_metadata(ws)
|
162 |
return ws
|
163 |
|
164 |
|
165 |
+
def update_metadata(ws: Workspace) -> Workspace:
|
166 |
"""Update the metadata of the given workspace object.
|
167 |
|
168 |
The metadata is the information about the operations that the nodes in the workspace represent,
|
|
|
175 |
Returns:
|
176 |
Workspace: The updated workspace object.
|
177 |
"""
|
178 |
+
if ws.env not in ops.CATALOGS:
|
179 |
+
return ws
|
180 |
+
catalog = ops.CATALOGS[ws.env]
|
181 |
+
for node in ws.nodes:
|
182 |
+
data = node.data
|
183 |
+
op = catalog.get(data.title)
|
184 |
+
if op:
|
185 |
+
if data.meta != op:
|
|
|
|
|
|
|
186 |
data.meta = op
|
187 |
+
if hasattr(node, "_crdt"):
|
188 |
+
node._crdt["data"]["meta"] = op.model_dump()
|
189 |
+
if node.type != op.type:
|
190 |
node.type = op.type
|
191 |
+
if hasattr(node, "_crdt"):
|
192 |
+
node._crdt["type"] = op.type
|
193 |
+
if data.error == "Unknown operation.":
|
194 |
+
data.error = None
|
195 |
+
if hasattr(node, "_crdt"):
|
196 |
+
node._crdt["data"]["error"] = None
|
197 |
+
else:
|
198 |
+
data.error = "Unknown operation."
|
199 |
+
if hasattr(node, "_crdt"):
|
200 |
+
node._crdt["data"]["error"] = "Unknown operation."
|
201 |
return ws
|
202 |
+
|
203 |
+
|
204 |
+
def connect_crdt(ws_pyd: Workspace, ws_crdt: pycrdt.Map):
|
205 |
+
ws_pyd._crdt = ws_crdt
|
206 |
+
with ws_crdt.doc.transaction():
|
207 |
+
for nc, np in zip(ws_crdt["nodes"], ws_pyd.nodes):
|
208 |
+
if "data" not in nc:
|
209 |
+
nc["data"] = pycrdt.Map()
|
210 |
+
np._crdt = nc
|