Panels dialog saves a ready I/O port draft on close and keeps an unfinished one; one qualified message-name rule on both sides

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
This commit is contained in:
2026-10-15 16:49:26 +02:00
co-authored by Claude Opus 5.5
parent 749393034d
commit 2bea71db7f
6 changed files with 150 additions and 34 deletions
+19
View File
@@ -12,6 +12,7 @@ from __future__ import annotations
import json
import math
import re
from enum import Enum
from typing import Any
@@ -320,6 +321,24 @@ class MessageSpec(BaseModel):
return hash((self.name, self.port))
#: A message named with its flow: the flow's own name, then the name inside it.
#: The one rule for anywhere a name has to arrive qualified; the frontend holds
#: a copy (``QUALIFIED_MESSAGE`` in ``deriveEdges.ts``).
QUALIFIED_PATTERN = re.compile(r"[a-z][a-z0-9_]*(\.[A-Za-z0-9_]+)+")
QUALIFIED_RULE = (
"Name the message as flow.name: a lowercase flow name, a dot, "
"then letters, digits and underscores"
)
def validate_qualified(value: str) -> str:
"""A qualified message name, or a ``ValueError`` saying what one looks like."""
if not QUALIFIED_PATTERN.fullmatch(value):
raise ValueError(QUALIFIED_RULE)
return value
def qualify(flow: str, name: str) -> str:
"""Resolve a message name against its flow namespace."""
if not name:
+2 -8
View File
@@ -21,6 +21,7 @@ from pydantic import BaseModel, Field, field_validator
from fluksio.core.config import settings
from fluksio.flow.dashboards import DashboardDef, DashboardNotFound, DashboardStore
from fluksio.flow.messages import validate_qualified
from fluksio.flow.schemas import _validate_name
#: Free text the device interprets: ``gpio.4``, ``backlight``, ``mic``.
@@ -51,14 +52,7 @@ class PanelPort(BaseModel):
raise ValueError("Use lowercase letters, digits, underscores and dots")
return value
@field_validator("message")
@classmethod
def _check_message(cls, value: str) -> str:
flow, _, name = value.partition(".")
if not name:
raise ValueError("Name the message with its flow, as flow.name")
_validate_name(flow)
return value
_check_message = field_validator("message")(validate_qualified)
class PanelDef(BaseModel):