f
This commit is contained in:
@@ -98,6 +98,8 @@ class ConfigModal(ModalScreen):
|
||||
self.editing_item_type = None # 'store' or 'provider'
|
||||
self.editing_item_name = None
|
||||
self.workspace_root = workspace_root
|
||||
self._button_id_map = {}
|
||||
self._input_id_map = {}
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Container(id="config-container"):
|
||||
@@ -127,6 +129,8 @@ class ConfigModal(ModalScreen):
|
||||
|
||||
def refresh_view(self) -> None:
|
||||
container = self.query_one("#fields-container", ScrollableContainer)
|
||||
self._button_id_map.clear()
|
||||
self._input_id_map.clear()
|
||||
|
||||
# Clear existing synchronously
|
||||
for child in list(container.children):
|
||||
@@ -157,10 +161,14 @@ class ConfigModal(ModalScreen):
|
||||
|
||||
def render_globals(self, container: ScrollableContainer) -> None:
|
||||
container.mount(Label("General Configuration", classes="config-label"))
|
||||
idx = 0
|
||||
for k, v in self.config_data.items():
|
||||
if not isinstance(v, dict) and not k.startswith("_"):
|
||||
inp_id = f"global-{idx}"
|
||||
self._input_id_map[inp_id] = k
|
||||
container.mount(Label(k))
|
||||
container.mount(Input(value=str(v), id=f"global-{k}", classes="config-input"))
|
||||
container.mount(Input(value=str(v), id=inp_id, classes="config-input"))
|
||||
idx += 1
|
||||
|
||||
def render_stores(self, container: ScrollableContainer) -> None:
|
||||
container.mount(Label("Configured Stores", classes="config-label"))
|
||||
@@ -169,6 +177,7 @@ class ConfigModal(ModalScreen):
|
||||
container.mount(Static("No stores configured."))
|
||||
else:
|
||||
# stores is structured as: {type: {name_key: config}}
|
||||
idx = 0
|
||||
for stype, instances in stores.items():
|
||||
if isinstance(instances, dict):
|
||||
for name_key, conf in instances.items():
|
||||
@@ -182,10 +191,16 @@ class ConfigModal(ModalScreen):
|
||||
or name_key
|
||||
)
|
||||
|
||||
edit_id = f"edit-store-{idx}"
|
||||
del_id = f"del-store-{idx}"
|
||||
self._button_id_map[edit_id] = ("edit", f"store-{stype}", name_key)
|
||||
self._button_id_map[del_id] = ("del", f"store-{stype}", name_key)
|
||||
idx += 1
|
||||
|
||||
row = Horizontal(
|
||||
Static(f"{display_name} ({stype})", classes="item-label"),
|
||||
Button("Edit", id=f"edit-store-{stype}-{name_key}"),
|
||||
Button("Delete", variant="error", id=f"del-store-{stype}-{name_key}"),
|
||||
Button("Edit", id=edit_id),
|
||||
Button("Delete", variant="error", id=del_id),
|
||||
classes="item-row"
|
||||
)
|
||||
container.mount(row)
|
||||
@@ -196,11 +211,16 @@ class ConfigModal(ModalScreen):
|
||||
if not providers:
|
||||
container.mount(Static("No providers configured."))
|
||||
else:
|
||||
for name, _ in providers.items():
|
||||
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)
|
||||
|
||||
row = Horizontal(
|
||||
Static(name, classes="item-label"),
|
||||
Button("Edit", id=f"edit-provider-{name}"),
|
||||
Button("Delete", variant="error", id=f"del-provider-{name}"),
|
||||
Button("Edit", id=edit_id),
|
||||
Button("Delete", variant="error", id=del_id),
|
||||
classes="item-row"
|
||||
)
|
||||
container.mount(row)
|
||||
@@ -246,6 +266,7 @@ class ConfigModal(ModalScreen):
|
||||
|
||||
# Show all existing keys
|
||||
existing_keys_upper = set()
|
||||
idx = 0
|
||||
for k, v in section.items():
|
||||
if k.startswith("_"): continue
|
||||
|
||||
@@ -267,10 +288,13 @@ class ConfigModal(ModalScreen):
|
||||
is_secret = True
|
||||
|
||||
container.mount(Label(label_text))
|
||||
inp = Input(value=str(v), id=f"item-{k}", classes="config-input")
|
||||
inp_id = f"item-{idx}"
|
||||
self._input_id_map[inp_id] = k
|
||||
inp = Input(value=str(v), id=inp_id, classes="config-input")
|
||||
if is_secret:
|
||||
inp.password = True
|
||||
container.mount(inp)
|
||||
idx += 1
|
||||
|
||||
# Add required/optional fields from schema that are missing
|
||||
for k_upper, field_def in provider_schema_map.items():
|
||||
@@ -282,7 +306,10 @@ class ConfigModal(ModalScreen):
|
||||
label_text += " *"
|
||||
|
||||
default_val = str(field_def.get("default") or "")
|
||||
inp = Input(value=default_val, id=f"item-{key}", classes="config-input")
|
||||
inp_id = f"item-{idx}"
|
||||
self._input_id_map[inp_id] = key
|
||||
inp = Input(value=default_val, id=inp_id, classes="config-input")
|
||||
idx += 1
|
||||
if field_def.get("secret"):
|
||||
inp.password = True
|
||||
if field_def.get("placeholder"):
|
||||
@@ -301,7 +328,10 @@ class ConfigModal(ModalScreen):
|
||||
# Case-insensitive deduplication (fix path vs PATH)
|
||||
if rk.upper() not in existing_keys_upper:
|
||||
container.mount(Label(rk))
|
||||
container.mount(Input(value="", id=f"item-{rk}", classes="config-input"))
|
||||
inp_id = f"item-{idx}"
|
||||
self._input_id_map[inp_id] = rk
|
||||
container.mount(Input(value="", id=inp_id, classes="config-input"))
|
||||
idx += 1
|
||||
|
||||
# If it's a provider, we might have required keys (legacy check fallback)
|
||||
if item_type == "provider":
|
||||
@@ -314,7 +344,10 @@ class ConfigModal(ModalScreen):
|
||||
for rk in required_keys:
|
||||
if rk.upper() not in existing_keys_upper:
|
||||
container.mount(Label(rk))
|
||||
container.mount(Input(value="", id=f"item-{rk}", classes="config-input"))
|
||||
inp_id = f"item-{idx}"
|
||||
self._input_id_map[inp_id] = rk
|
||||
container.mount(Input(value="", id=inp_id, classes="config-input"))
|
||||
idx += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -355,16 +388,21 @@ class ConfigModal(ModalScreen):
|
||||
self.editing_item_name = None
|
||||
self.editing_item_type = None
|
||||
self.refresh_view()
|
||||
elif bid.startswith("edit-store-"):
|
||||
parts = bid.replace("edit-store-", "").split("-", 1)
|
||||
if len(parts) == 2:
|
||||
stype, name = parts
|
||||
self.editing_item_type = f"store-{stype}"
|
||||
elif bid in self._button_id_map:
|
||||
action, itype, name = self._button_id_map[bid]
|
||||
if action == "edit":
|
||||
self.editing_item_type = itype
|
||||
self.editing_item_name = name
|
||||
self.refresh_view()
|
||||
elif bid.startswith("edit-provider-"):
|
||||
self.editing_item_name = bid.replace("edit-provider-", "")
|
||||
self.editing_item_type = "provider"
|
||||
elif action == "del":
|
||||
if 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]
|
||||
elif itype == "provider":
|
||||
if "provider" in self.config_data and name in self.config_data["provider"]:
|
||||
del self.config_data["provider"][name]
|
||||
self.refresh_view()
|
||||
elif bid == "add-store-btn":
|
||||
all_classes = _discover_store_classes()
|
||||
@@ -390,19 +428,6 @@ class ConfigModal(ModalScreen):
|
||||
except Exception:
|
||||
pass
|
||||
self.app.push_screen(SelectionModal("Select Provider Type", options), callback=self.on_provider_type_selected)
|
||||
elif bid.startswith("del-store-"):
|
||||
parts = bid.replace("del-store-", "").split("-", 1)
|
||||
if len(parts) == 2:
|
||||
stype, name = parts
|
||||
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]
|
||||
self.refresh_view()
|
||||
elif bid.startswith("del-provider-"):
|
||||
name = bid.replace("del-provider-", "")
|
||||
if "provider" in self.config_data and name in self.config_data["provider"]:
|
||||
del self.config_data["provider"][name]
|
||||
self.refresh_view()
|
||||
|
||||
def on_store_type_selected(self, stype: str) -> None:
|
||||
if not stype: return
|
||||
@@ -474,11 +499,16 @@ class ConfigModal(ModalScreen):
|
||||
def on_input_changed(self, event: Input.Changed) -> None:
|
||||
if not event.input.id:
|
||||
return
|
||||
if event.input.id.startswith("global-"):
|
||||
key = event.input.id.replace("global-", "")
|
||||
|
||||
bid = event.input.id
|
||||
if bid not in self._input_id_map:
|
||||
return
|
||||
|
||||
key = self._input_id_map[bid]
|
||||
|
||||
if bid.startswith("global-"):
|
||||
self.config_data[key] = event.value
|
||||
elif event.input.id.startswith("item-") and self.editing_item_name:
|
||||
key = event.input.id.replace("item-", "")
|
||||
elif bid.startswith("item-") and self.editing_item_name:
|
||||
it = str(self.editing_item_type or "")
|
||||
inm = str(self.editing_item_name or "")
|
||||
|
||||
|
||||
@@ -53,13 +53,17 @@ class SelectionModal(ModalScreen[str]):
|
||||
with Container(id="selection-container"):
|
||||
yield Static(self.selection_title, classes="selection-title")
|
||||
with ScrollableContainer():
|
||||
for opt in self.options:
|
||||
yield Button(opt, id=f"opt-{opt}", classes="selection-button")
|
||||
for i, opt in enumerate(self.options):
|
||||
yield Button(opt, id=f"opt-{i}", classes="selection-button")
|
||||
yield Button("Cancel", id="selection-cancel")
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
if event.button.id == "selection-cancel":
|
||||
self.dismiss("")
|
||||
elif event.button.id and event.button.id.startswith("opt-"):
|
||||
selection = event.button.id.replace("opt-", "")
|
||||
try:
|
||||
idx = int(event.button.id.replace("opt-", ""))
|
||||
selection = self.options[idx]
|
||||
self.dismiss(selection)
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user