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