continuing refactor

This commit is contained in:
2026-05-03 21:20:05 -07:00
parent 77cab1bd27
commit 5534812426
50 changed files with 1004 additions and 428 deletions
+113 -92
View File
@@ -18,6 +18,7 @@ from SYS.config import (
count_changed_entries,
ConfigSaveConflict,
coerce_config_value,
_is_multi_instance_plugin_config,
)
from SYS.database import db
from SYS.logger import log, debug
@@ -200,7 +201,6 @@ class ConfigModal(ModalScreen):
yield Label("Categories", classes="config-label")
with ListView(id="category-list"):
yield ListItem(Label("Global Settings"), id="cat-globals")
yield ListItem(Label("Stores"), id="cat-stores")
yield ListItem(Label("Plugins"), id="cat-providers")
yield ListItem(Label("Tools"), id="cat-tools")
@@ -210,14 +210,12 @@ class ConfigModal(ModalScreen):
yield Button("Save", variant="success", id="save-btn")
# Durable synchronous save: waits and verifies DB persisted critical keys
yield Button("Save (durable)", variant="primary", id="save-durable-btn")
yield Button("Add Store", variant="primary", id="add-store-btn")
yield Button("Add Plugin", variant="primary", id="add-provider-btn")
yield Button("Add Tool", variant="primary", id="add-tool-btn")
yield Button("Back", id="back-btn")
yield Button("Close", variant="error", id="cancel-btn")
def on_mount(self) -> None:
self.query_one("#add-store-btn", Button).display = False
self.query_one("#add-provider-btn", Button).display = False
try:
self.query_one("#add-tool-btn", Button).display = False
@@ -267,7 +265,6 @@ class ConfigModal(ModalScreen):
# Update visibility of buttons
try:
self.query_one("#add-store-btn", Button).display = (self.current_category == "stores" and self.editing_item_name is None)
self.query_one("#add-provider-btn", Button).display = (self.current_category == "providers" and self.editing_item_name is None)
self.query_one("#add-tool-btn", Button).display = (self.current_category == "tools" and self.editing_item_name is None)
self.query_one("#back-btn", Button).display = (self.editing_item_name is not None)
@@ -467,20 +464,46 @@ class ConfigModal(ModalScreen):
providers = self.config_data.get("provider", {})
if not providers:
container.mount(Static("No plugins configured."))
else:
for i, (name, _) in enumerate(providers.items()):
edit_id = f"edit-provider-{i}"
del_id = f"del-provider-{i}"
self._button_id_map[edit_id] = ("edit", "provider", name)
self._button_id_map[del_id] = ("del", "provider", name)
return
idx = 0
for plugin_name, plugin_cfg in providers.items():
if isinstance(plugin_cfg, dict) and _is_multi_instance_plugin_config(plugin_cfg):
# Multi-instance plugin: show each instance as a separate row
for instance_name, instance_cfg in plugin_cfg.items():
display_name = instance_name
if isinstance(instance_cfg, dict):
display_name = (
instance_cfg.get("NAME")
or instance_cfg.get("name")
or instance_name
)
edit_id = f"edit-provider-{idx}"
del_id = f"del-provider-{idx}"
self._button_id_map[edit_id] = ("edit", f"plugin-{plugin_name}", instance_name)
self._button_id_map[del_id] = ("del", f"plugin-{plugin_name}", instance_name)
row = Horizontal(
Static(f"{display_name} ({plugin_name})", classes="item-label"),
Button("Edit", id=edit_id),
Button("Delete", variant="error", id=del_id),
classes="item-row"
)
container.mount(row)
idx += 1
else:
# Single-instance plugin
edit_id = f"edit-provider-{idx}"
del_id = f"del-provider-{idx}"
self._button_id_map[edit_id] = ("edit", "plugin", plugin_name)
self._button_id_map[del_id] = ("del", "plugin", plugin_name)
row = Horizontal(
Static(name, classes="item-label"),
Static(plugin_name, classes="item-label"),
Button("Edit", id=edit_id),
Button("Delete", variant="error", id=del_id),
classes="item-row"
)
container.mount(row)
idx += 1
def render_tools(self, container: ScrollableContainer) -> None:
container.mount(Label("Configured Tools", classes="config-label"))
@@ -508,11 +531,13 @@ class ConfigModal(ModalScreen):
item_schema_map = get_item_schema_map(item_type, item_name)
render_state = {"group": None, "mounted_any": False}
# Parse item_type for store-{stype} or just provider
if item_type.startswith("store-"):
stype = item_type.replace("store-", "")
container.mount(Label(f"Editing Store: {item_name} ({stype})", classes="config-label"))
section = self.config_data.get("store", {}).get(stype, {}).get(item_name, {})
# Parse item_type: plugin-{ptype} (multi-instance) or flat type
if item_type.startswith("plugin-"):
ptype = item_type[len("plugin-"):]
container.mount(Label(f"Editing {ptype}: {item_name}", classes="config-label"))
plugin_block = self.config_data.get("plugin") or self.config_data.get("provider") or {}
plugin_instances = plugin_block.get(ptype, {}) if isinstance(plugin_block, dict) else {}
section = plugin_instances.get(item_name, {}) if isinstance(plugin_instances, dict) else {}
else:
container.mount(Label(f"Editing {item_type.capitalize()}: {item_name}", classes="config-label"))
section = self.config_data.get(item_type, {}).get(item_name, {})
@@ -598,7 +623,7 @@ class ConfigModal(ModalScreen):
row.mount(Button("Paste", id=f"paste-{inp_id}", classes="paste-btn"))
idx += 1
if item_type == "plugin" and isinstance(item_name, str):
if item_type in ("plugin", "provider") and isinstance(item_name, str):
provider = self._instantiate_plugin_for_editor(item_name, self.config_data)
if provider is not None:
provider_actions = provider.config_actions() or []
@@ -626,7 +651,7 @@ class ConfigModal(ModalScreen):
)
if (
item_type == "plugin"
item_type in ("plugin", "provider")
and isinstance(item_name, str)
and item_name.strip().lower() == "matrix"
):
@@ -720,13 +745,11 @@ class ConfigModal(ModalScreen):
if not event.item:
return
item_id = getattr(event.item, "id", None)
if item_id not in ("cat-globals", "cat-stores", "cat-providers", "cat-tools"):
if item_id not in ("cat-globals", "cat-providers", "cat-tools"):
return
if item_id == "cat-globals":
self.current_category = "globals"
elif item_id == "cat-stores":
self.current_category = "stores"
elif item_id == "cat-providers":
self.current_category = "providers"
elif item_id == "cat-tools":
@@ -841,13 +864,23 @@ class ConfigModal(ModalScreen):
self.refresh_view()
elif action == "del":
removed = False
if itype.startswith("store-"):
if itype.startswith("plugin-"):
ptype = itype[len("plugin-"):]
plugin_block = self.config_data.get("plugin") or self.config_data.get("provider")
if isinstance(plugin_block, dict):
instances = plugin_block.get(ptype)
if isinstance(instances, dict) and name in instances:
del instances[name]
if not instances:
plugin_block.pop(ptype, None)
removed = True
elif itype.startswith("store-"):
stype = itype.replace("store-", "")
if "store" in self.config_data and stype in self.config_data["store"]:
if name in self.config_data["store"][stype]:
del self.config_data["store"][stype][name]
removed = True
elif itype == "provider":
elif itype in ("provider", "plugin"):
if "provider" in self.config_data and name in self.config_data["provider"]:
del self.config_data["provider"][name]
removed = True
@@ -871,9 +904,6 @@ class ConfigModal(ModalScreen):
elif bid in self._provider_button_map:
provider_name, action_id = self._provider_button_map[bid]
self._request_plugin_action(provider_name, action_id)
elif bid == "add-store-btn":
options = get_configurable_store_types()
self.app.push_screen(SelectionModal("Select Store Type", options), callback=self.on_store_type_selected)
elif bid == "add-provider-btn":
options = get_configurable_plugin_types()
self.app.push_screen(SelectionModal("Select Plugin Type", options), callback=self.on_provider_type_selected)
@@ -1036,51 +1066,44 @@ class ConfigModal(ModalScreen):
# Backup/restore helpers removed: forensics/audit mode disabled and restore UI removed.
def on_store_type_selected(self, stype: str) -> None:
if not stype:
return
self._capture_editor_snapshot()
existing_names: set[str] = set()
store_block = self.config_data.get("store")
if isinstance(store_block, dict):
st_entries = store_block.get(stype)
if isinstance(st_entries, dict):
existing_names = {str(name) for name in st_entries.keys() if name}
base_name = f"new_{stype}"
new_name = base_name
suffix = 1
while new_name in existing_names:
suffix += 1
new_name = f"{base_name}_{suffix}"
if "store" not in self.config_data:
self.config_data["store"] = {}
if stype not in self.config_data["store"]:
self.config_data["store"][stype] = {}
# Default config for the new store
new_config = build_default_store_config(stype, new_name)
self.config_data["store"][stype][new_name] = new_config
self.editing_item_type = f"store-{stype}"
self.editing_item_name = new_name
self.refresh_view()
def on_provider_type_selected(self, ptype: str) -> None:
if not ptype: return
if not ptype:
return
self._capture_editor_snapshot()
if "provider" not in self.config_data:
self.config_data["provider"] = {}
# Plugins are configured under the top-level 'provider' dict for now.
if ptype not in self.config_data["provider"]:
self.config_data["provider"][ptype] = build_default_plugin_config(ptype)
self.editing_item_type = "plugin"
self.editing_item_name = ptype
from ProviderCore.registry import get_plugin_class as _get_cls
plugin_class = _get_cls(ptype)
is_multi = bool(getattr(plugin_class, 'MULTI_INSTANCE', False)) if plugin_class else False
if is_multi:
# Multi-instance plugin: create a named instance entry in config["plugin"][ptype]
plugin_block = self.config_data.setdefault("plugin", {})
instances = plugin_block.setdefault(ptype, {})
# Also keep config["provider"] in sync (they should be the same dict after normalization,
# but if they're not yet, link them)
if "provider" in self.config_data and self.config_data["provider"] is not plugin_block:
self.config_data["provider"].setdefault(ptype, instances)
existing_names: set[str] = set(instances.keys())
base_name = f"new_{ptype}"
new_name = base_name
suffix = 1
while new_name in existing_names:
suffix += 1
new_name = f"{base_name}_{suffix}"
instances[new_name] = build_default_store_config(ptype, new_name)
self.editing_item_type = f"plugin-{ptype}"
self.editing_item_name = new_name
else:
# Single-instance plugin
if "provider" not in self.config_data:
self.config_data["provider"] = {}
if ptype not in self.config_data["provider"]:
self.config_data["provider"][ptype] = build_default_plugin_config(ptype)
self.editing_item_type = "plugin"
self.editing_item_name = ptype
self.refresh_view()
def on_tool_type_selected(self, tname: str) -> None:
@@ -1112,13 +1135,13 @@ class ConfigModal(ModalScreen):
if widget_id.startswith("global-"):
existing_value = self.config_data.get(key)
elif widget_id.startswith("item-") and item_name:
if item_type.startswith("store-"):
stype = item_type.replace("store-", "")
store_block = self.config_data.get("store")
if isinstance(store_block, dict):
type_block = store_block.get(stype)
if isinstance(type_block, dict):
section = type_block.get(item_name)
if item_type.startswith("plugin-"):
ptype = item_type[len("plugin-"):]
plugin_block = self.config_data.get("plugin") or self.config_data.get("provider")
if isinstance(plugin_block, dict):
instances = plugin_block.get(ptype)
if isinstance(instances, dict):
section = instances.get(item_name)
if isinstance(section, dict):
existing_value = section.get(key)
else:
@@ -1137,23 +1160,19 @@ class ConfigModal(ModalScreen):
if widget_id.startswith("global-"):
self.config_data[key] = processed_value
elif widget_id.startswith("item-") and item_name:
if item_type.startswith("store-"):
stype = item_type.replace("store-", "")
if "store" not in self.config_data:
self.config_data["store"] = {}
if stype not in self.config_data["store"]:
self.config_data["store"][stype] = {}
if item_name not in self.config_data["store"][stype]:
self.config_data["store"][stype][item_name] = {}
# Special case: Renaming the store via the NAME field
if item_type.startswith("plugin-"):
ptype = item_type[len("plugin-"):]
plugin_block = self.config_data.setdefault("plugin", {})
instances = plugin_block.setdefault(ptype, {})
if item_name not in instances:
instances[item_name] = {}
# Special case: rename via the NAME field
if key.upper() == "NAME" and processed_value and str(processed_value) != item_name:
new_name = str(processed_value)
self.config_data["store"][stype][new_name] = self.config_data["store"][stype].pop(item_name)
instances[new_name] = instances.pop(item_name)
self.editing_item_name = new_name
item_name = new_name
self.config_data["store"][stype][item_name][key] = processed_value
instances[item_name][key] = processed_value
else:
if item_type not in self.config_data:
self.config_data[item_type] = {}
@@ -1858,11 +1877,13 @@ class ConfigModal(ModalScreen):
item_name = str(self.editing_item_name or "")
section = {}
if item_type.startswith("store-"):
stype = item_type.replace("store-", "")
section = self.config_data.get("store", {}).get(stype, {}).get(item_name, {})
if item_type.startswith("plugin-"):
ptype = item_type[len("plugin-"):]
section = self.config_data.get("plugin", {}).get(ptype, {}).get(item_name, {})
elif item_type == "provider":
section = self.config_data.get("provider", {}).get(item_name, {})
elif item_type == "plugin":
section = self.config_data.get("plugin", {}).get(item_name, {}) or self.config_data.get("provider", {}).get(item_name, {})
elif item_type == "tool":
section = self.config_data.get("tool", {}).get(item_name, {})