Grey out incompatible slots in the link dialog

Parse the readonly facet from kit manifests and use it to disable
slots that cannot participate in a link: read-only slots are greyed
on the target side only (they remain selectable as sources), action
and void slots are greyed on both sides, and type mismatches are
greyed when the other side has a selection. A status label previews
the link path at the bottom of the dialog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 21:58:17 +03:00
co-authored by Claude Opus 4.6
parent 424caf777c
commit 47bfaf04e0
2 changed files with 110 additions and 17 deletions
+16 -3
View File
@@ -53,6 +53,17 @@ def read_summary_facet(slot_element):
return True
def read_readonly_facet(slot_element):
"""Reads a slot's '@readonly' facet. Absent means writable."""
facets = slot_element.find("facets")
if facets is None:
return False
for bool_facet in facets.findall("bool"):
if bool_facet.get("name") == "readonly":
return (bool_facet.get("val", "false").strip().lower() == "true")
return False
def get_slots_with_inheritance(type_name, kit_schemas):
"""Recursively resolves the slots for a given type by traversing its base chain."""
if type_name not in kit_schemas:
@@ -72,7 +83,8 @@ def get_slots_with_inheritance(type_name, kit_schemas):
"name": slot.get("name"),
"type": slot.get("type"),
"default": slot.get("default", "false"),
"flags": slot.get("flags", ""), # Capture visibility flags ('o' maps to operator/hidden)
"flags": slot.get("flags", ""),
"readonly": read_readonly_facet(slot),
"summary": read_summary_facet(slot),
"declared_id": int(slot.get("id"))
})
@@ -110,6 +122,7 @@ def compile_schema_registry(manifest_paths):
"type": slot_data["type"],
"default": slot_data["default"],
"flags": slot_data["flags"],
"readonly": slot_data["readonly"],
"summary": slot_data["summary"]
})
app_state.final_components_registry[type_name] = resolved_type_structure
@@ -162,11 +175,11 @@ def load_schema_kits_and_manifests():
def get_all_slots_for_type(type_str):
"""Returns every slot for a type as (name, type_string) tuples, for the link dialog."""
"""Returns every slot for a type as (name, type_string, flags, readonly) tuples."""
if type_str not in app_state.final_components_registry:
return []
return [
(slot["name"], slot["type"])
(slot["name"], slot["type"], slot["flags"], slot["readonly"])
for slot in app_state.final_components_registry[type_str]
if slot["name"]
]