darabos commited on
Commit
7653ba6
·
1 Parent(s): e128fa4

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, np in zip(ws_crdt["nodes"], ws_pyd.nodes):
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
- _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,22 +175,36 @@ def _update_metadata(ws: Workspace) -> Workspace:
175
  Returns:
176
  Workspace: The updated workspace object.
177
  """
178
- catalog = ops.CATALOGS.get(ws.env, {})
179
- nodes = {node.id: node for node in ws.nodes}
180
- done = set()
181
- while len(done) < len(nodes):
182
- for node in ws.nodes:
183
- if node.id in done:
184
- # TODO: Can nodes with the same ID reference different operations?
185
- continue
186
- data = node.data
187
- op = catalog.get(data.title)
188
- if op:
189
  data.meta = op
 
 
 
190
  node.type = op.type
191
- if data.error == "Unknown operation.":
192
- data.error = None
193
- else:
194
- data.error = "Unknown operation."
195
- done.add(node.id)
 
 
 
 
 
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