updated plugin refactor and added FTP and SCP plugins , also hydrusnetwork plugin migration
This commit is contained in:
@@ -32,7 +32,7 @@ from SYS.plugin_config import (
|
||||
get_item_schema_map,
|
||||
get_required_config_keys,
|
||||
)
|
||||
from ProviderCore.registry import get_plugin
|
||||
from ProviderCore.registry import get_plugin, get_plugin_class
|
||||
from TUI.modalscreen.matrix_room_picker import MatrixRoomPicker
|
||||
from TUI.modalscreen.selection_modal import SelectionModal
|
||||
import logging
|
||||
@@ -164,9 +164,12 @@ class ConfigModal(ModalScreen):
|
||||
self.editing_item_type = None # 'store' or 'provider'
|
||||
self.editing_item_name = None
|
||||
self._button_id_map = {}
|
||||
self._provider_button_map: Dict[str, tuple[str, str]] = {}
|
||||
self._input_id_map = {}
|
||||
self._matrix_status: Optional[Static] = None
|
||||
self._matrix_test_running = False
|
||||
self._provider_status: Optional[Static] = None
|
||||
self._provider_action_running = False
|
||||
self._editor_snapshot: Optional[Dict[str, Any]] = None
|
||||
# Inline matrix rooms controls
|
||||
self._matrix_inline_list: Optional[ListView] = None
|
||||
@@ -256,6 +259,7 @@ class ConfigModal(ModalScreen):
|
||||
return
|
||||
|
||||
self._button_id_map.clear()
|
||||
self._provider_button_map.clear()
|
||||
self._input_id_map.clear()
|
||||
|
||||
# Clear existing
|
||||
@@ -594,6 +598,33 @@ class ConfigModal(ModalScreen):
|
||||
row.mount(Button("Paste", id=f"paste-{inp_id}", classes="paste-btn"))
|
||||
idx += 1
|
||||
|
||||
if item_type == "provider" and isinstance(item_name, str):
|
||||
provider = self._instantiate_provider_for_editor(item_name, self.config_data)
|
||||
if provider is not None:
|
||||
provider_actions = provider.config_actions() or []
|
||||
if provider_actions:
|
||||
container.mount(Rule())
|
||||
container.mount(Label(f"{provider.label} helpers", classes="config-label"))
|
||||
helper_text = str(provider.config_helper_text() or "Use these helpers to validate provider settings.").strip()
|
||||
status = Static(helper_text, id="provider-status")
|
||||
container.mount(status)
|
||||
self._provider_status = status
|
||||
row = Horizontal(classes="field-row")
|
||||
container.mount(row)
|
||||
for action in provider_actions:
|
||||
action_id = str(action.get("id") or "").strip()
|
||||
if not action_id:
|
||||
continue
|
||||
button_id = f"provider-action-{item_name}-{action_id}".replace(" ", "-")
|
||||
self._provider_button_map[button_id] = (item_name, action_id)
|
||||
row.mount(
|
||||
Button(
|
||||
str(action.get("label") or action_id.replace("_", " ").title()),
|
||||
id=button_id,
|
||||
variant=str(action.get("variant") or "default"),
|
||||
)
|
||||
)
|
||||
|
||||
if (
|
||||
item_type == "provider"
|
||||
and isinstance(item_name, str)
|
||||
@@ -755,6 +786,10 @@ class ConfigModal(ModalScreen):
|
||||
self.editing_item_type = None
|
||||
self.refresh_view()
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Configuration save failed: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write save failure to logs")
|
||||
self.notify(f"Save failed: {exc}", severity="error", timeout=10)
|
||||
elif bid == "save-durable-btn":
|
||||
# Perform a synchronous, verified save and notify status to the user.
|
||||
@@ -788,6 +823,10 @@ class ConfigModal(ModalScreen):
|
||||
self.refresh_view()
|
||||
self._editor_snapshot = None
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Durable configuration save failed: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write durable save failure to logs")
|
||||
self.notify(f"Durable save failed: {exc}", severity="error", timeout=10)
|
||||
try:
|
||||
log(f"Durable save failed: {exc}")
|
||||
@@ -823,8 +862,15 @@ class ConfigModal(ModalScreen):
|
||||
saved = self.save_all()
|
||||
self.notify("Saving configuration...", timeout=3)
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Configuration save failed while deleting config entry: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write config delete save failure to logs")
|
||||
self.notify(f"Save failed: {exc}", severity="error", timeout=10)
|
||||
self.refresh_view()
|
||||
elif bid in self._provider_button_map:
|
||||
provider_name, action_id = self._provider_button_map[bid]
|
||||
self._request_provider_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)
|
||||
@@ -882,6 +928,10 @@ class ConfigModal(ModalScreen):
|
||||
try:
|
||||
entries = save_config(self.config_data)
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Saving Matrix default rooms failed: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write Matrix room save failure to logs")
|
||||
if self._matrix_status:
|
||||
self._matrix_status.update(f"Saving default rooms failed: {exc}")
|
||||
return
|
||||
@@ -921,6 +971,69 @@ class ConfigModal(ModalScreen):
|
||||
else:
|
||||
self.notify("Clipboard not supported in this terminal", severity="warning")
|
||||
|
||||
def _instantiate_provider_for_editor(self, provider_name: str, config_data: Optional[Dict[str, Any]] = None) -> Optional[Any]:
|
||||
try:
|
||||
provider_class = get_plugin_class(provider_name)
|
||||
except Exception:
|
||||
provider_class = None
|
||||
if provider_class is None:
|
||||
return None
|
||||
try:
|
||||
return provider_class(config_data or self.config_data)
|
||||
except Exception:
|
||||
logger.exception("Failed to instantiate provider '%s' for config helper", provider_name)
|
||||
return None
|
||||
|
||||
def _request_provider_action(self, provider_name: str, action_id: str) -> None:
|
||||
if self._provider_action_running:
|
||||
return
|
||||
self._synchronize_inputs_to_config()
|
||||
self._provider_action_running = True
|
||||
if self._provider_status is not None:
|
||||
self._provider_status.update(f"Running {action_id.replace('_', ' ')}…")
|
||||
self._provider_action_background(provider_name, action_id, deepcopy(self.config_data))
|
||||
|
||||
@work(thread=True)
|
||||
def _provider_action_background(self, provider_name: str, action_id: str, config_snapshot: Dict[str, Any]) -> None:
|
||||
try:
|
||||
provider = self._instantiate_provider_for_editor(provider_name, config_snapshot)
|
||||
if provider is None:
|
||||
raise RuntimeError(f"Provider '{provider_name}' is unavailable")
|
||||
result = provider.run_config_action(action_id)
|
||||
if not isinstance(result, dict):
|
||||
result = {"ok": False, "message": f"Provider '{provider_name}' returned an invalid config action result."}
|
||||
except Exception as exc:
|
||||
result = {"ok": False, "message": str(exc) or f"Provider action '{action_id}' failed."}
|
||||
|
||||
try:
|
||||
self.app.call_from_thread(self._provider_action_complete, provider_name, action_id, result)
|
||||
except Exception:
|
||||
self._provider_action_complete(provider_name, action_id, result)
|
||||
|
||||
def _provider_action_complete(self, provider_name: str, action_id: str, result: Dict[str, Any]) -> None:
|
||||
self._provider_action_running = False
|
||||
ok = bool(result.get("ok"))
|
||||
message = str(result.get("message") or f"Provider action '{action_id}' finished.")
|
||||
updates = result.get("config_updates")
|
||||
|
||||
if ok and isinstance(updates, dict):
|
||||
provider_block = self.config_data.setdefault("provider", {}).setdefault(provider_name, {})
|
||||
if isinstance(provider_block, dict):
|
||||
provider_block.update(updates)
|
||||
message = f"{message}"
|
||||
try:
|
||||
self.refresh_view()
|
||||
except Exception:
|
||||
logger.exception("Failed to refresh config view after provider action")
|
||||
|
||||
if self._provider_status is not None:
|
||||
self._provider_status.update(message)
|
||||
|
||||
try:
|
||||
self.notify(message, severity="error" if not ok else "information", timeout=8)
|
||||
except Exception:
|
||||
logger.exception("Failed to notify provider action result for %s/%s", provider_name, action_id)
|
||||
|
||||
# Backup/restore helpers removed: forensics/audit mode disabled and restore UI removed.
|
||||
|
||||
def on_store_type_selected(self, stype: str) -> None:
|
||||
@@ -1130,6 +1243,10 @@ class ConfigModal(ModalScreen):
|
||||
try:
|
||||
entries = save_config(self.config_data)
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Saving configuration before Matrix test failed: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write Matrix test pre-save failure to logs")
|
||||
if self._matrix_status:
|
||||
self._matrix_status.update(f"Saving configuration failed: {exc}")
|
||||
self._matrix_test_running = False
|
||||
@@ -1290,6 +1407,10 @@ class ConfigModal(ModalScreen):
|
||||
try:
|
||||
entries = save_config(self.config_data)
|
||||
except Exception as exc:
|
||||
try:
|
||||
log(f"Saving configuration before Matrix room load failed: {exc}")
|
||||
except Exception:
|
||||
logger.exception("Failed to write Matrix load pre-save failure to logs")
|
||||
if self._matrix_status:
|
||||
self._matrix_status.update(f"Saving configuration failed: {exc}")
|
||||
self._matrix_test_running = False
|
||||
|
||||
Reference in New Issue
Block a user