Header of process and node ports follow each other both ways: a panel edit rewrites only the def line of edited code, a code save reads the header back into input ports and settings (draft and response); Space types in the node editor again
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
This commit is contained in:
@@ -34,7 +34,7 @@ from fluksio.api.deps import (
|
||||
from fluksio.api.socket_auth import TICKET_TTL_S, issue_ticket, socket_token
|
||||
from fluksio.core.db import engine
|
||||
from fluksio.flow.artifacts import is_reference
|
||||
from fluksio.flow.controller import NODE_TYPES, FlowController
|
||||
from fluksio.flow.controller import NODE_TYPES, FlowController, follow_header
|
||||
from fluksio.flow.dashboards import DashboardStore
|
||||
from fluksio.flow.events import event_bus
|
||||
from fluksio.flow.messages import flow_of, qualify
|
||||
@@ -54,6 +54,7 @@ from fluksio.flow.schemas import (
|
||||
MessageValue,
|
||||
NodeDef,
|
||||
NodeSource,
|
||||
NodeSourceSaved,
|
||||
NodeStatusPublic,
|
||||
NodeTypeInfo,
|
||||
)
|
||||
@@ -672,9 +673,41 @@ def read_node_source(
|
||||
)
|
||||
|
||||
|
||||
def _follow_header(
|
||||
controller: FlowController, name: str, node_id: str, code: str
|
||||
) -> FlowDef | None:
|
||||
"""Bring a function node's ports and settings in line with its header.
|
||||
|
||||
The draft is what the editor is on, so that is what moves, and only for a
|
||||
node with its own code: a shared one serves other flows with other ports,
|
||||
and a synced flow's ports are declared in its repository. Returns the
|
||||
draft when it changed.
|
||||
"""
|
||||
definition = controller.store.read_flow(name, draft=True)
|
||||
node = next((n for n in definition.nodes if n.id == node_id), None)
|
||||
spec = NODE_TYPES.get(node.type) if node is not None else None
|
||||
if (
|
||||
node is None
|
||||
or spec is None
|
||||
or not spec.free_params
|
||||
or node.source_ref
|
||||
or definition.origin
|
||||
):
|
||||
return None
|
||||
followed = follow_header(node, code)
|
||||
if followed == node:
|
||||
return None
|
||||
definition.nodes = [followed if n.id == node_id else n for n in definition.nodes]
|
||||
try:
|
||||
return controller.store.write_draft(definition, definition.version)
|
||||
except StaleVersion:
|
||||
# Someone saved in between; the next save of this code tries again.
|
||||
return None
|
||||
|
||||
|
||||
@router.put(
|
||||
"/{name}/nodes/{node_id}/source",
|
||||
response_model=NodeStatusPublic,
|
||||
response_model=NodeSourceSaved,
|
||||
dependencies=[Depends(get_code_author)],
|
||||
)
|
||||
async def save_node_source(
|
||||
@@ -694,6 +727,10 @@ async def save_node_source(
|
||||
it — and that one is live immediately rather than waiting for a publish,
|
||||
because the copy is not any single flow's to hold back. Being live, it is
|
||||
audited like a publish.
|
||||
|
||||
A node with its own code takes its input ports and settings from the
|
||||
header of ``process`` (see `follow_header`), and the answer carries the
|
||||
node when that changed it.
|
||||
"""
|
||||
definition = _read_flow(controller, name)
|
||||
ref = _source_ref(definition, node_id)
|
||||
@@ -708,6 +745,9 @@ async def save_node_source(
|
||||
await run_in_threadpool(
|
||||
controller.store.write_node_source, name, node_id, source.code, True
|
||||
)
|
||||
followed = await run_in_threadpool(
|
||||
_follow_header, controller, name, node_id, source.code
|
||||
)
|
||||
node_def = next((n for n in definition.nodes if n.id == node_id), None)
|
||||
device = (
|
||||
node_def.device
|
||||
@@ -717,10 +757,14 @@ async def save_node_source(
|
||||
error = await run_in_threadpool(
|
||||
controller.compile_check, name, node_id, source.code, device
|
||||
)
|
||||
return NodeStatusPublic(
|
||||
return NodeSourceSaved(
|
||||
id=f"{name}.{node_id}",
|
||||
status="error" if error else "active",
|
||||
error=error,
|
||||
node=next((n for n in followed.nodes if n.id == node_id), None)
|
||||
if followed
|
||||
else None,
|
||||
version=followed.version if followed else None,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user