diff --git a/web_interface/blueprints/api_v3.py b/web_interface/blueprints/api_v3.py index 3a3b2574..bfa86ddb 100644 --- a/web_interface/blueprints/api_v3.py +++ b/web_interface/blueprints/api_v3.py @@ -1682,7 +1682,13 @@ def execute_system_action(): }) elif action == 'install_plugin_requirements': active_pm = getattr(api_v3, 'plugin_manager', None) - plugins_dir = Path(active_pm.plugins_dir) if active_pm else PROJECT_ROOT / 'plugin-repos' + if active_pm: + plugins_dir = Path(active_pm.plugins_dir) + else: + _cm = getattr(api_v3, 'config_manager', None) + _cfg = _cm.load_config() if _cm else {} + _dir_name = _cfg.get('plugin_system', {}).get('plugins_directory', 'plugin-repos') + plugins_dir = Path(_dir_name) if os.path.isabs(_dir_name) else PROJECT_ROOT / _dir_name results = [] if plugins_dir.exists(): for p in sorted(plugins_dir.iterdir()): @@ -4630,27 +4636,34 @@ def save_plugin_config(): continue pt = ps.get('type') val = cfg[k] - if pt == 'array' and isinstance(val, dict): - keys = list(val.keys()) - if keys and all(str(x).isdigit() for x in keys): - sorted_keys = sorted(keys, key=lambda x: int(str(x))) - items_schema = ps.get('items', {}) - item_type = items_schema.get('type') - arr = [val[sk] for sk in sorted_keys] - if item_type in ('integer', 'number'): - converted = [] - for v in arr: - if isinstance(v, str): - try: - converted.append(int(v) if item_type == 'integer' else float(v)) - except (ValueError, TypeError): + if pt == 'array': + items_schema = ps.get('items', {}) + item_type = items_schema.get('type') + if isinstance(val, dict): + keys = list(val.keys()) + if keys and all(str(x).isdigit() for x in keys): + sorted_keys = sorted(keys, key=lambda x: int(str(x))) + arr = [val[sk] for sk in sorted_keys] + if item_type in ('integer', 'number'): + converted = [] + for v in arr: + if isinstance(v, str): + try: + converted.append(int(v) if item_type == 'integer' else float(v)) + except (ValueError, TypeError): + converted.append(v) + else: converted.append(v) - else: - converted.append(v) - arr = converted - cfg[k] = arr - elif not keys: - cfg[k] = [] + arr = converted + cfg[k] = arr + elif not keys: + cfg[k] = [] + # Recurse into each element when items are objects with properties, + # covering both freshly-converted and already-list values. + if item_type == 'object' and 'properties' in items_schema: + for elem in (cfg[k] if isinstance(cfg[k], list) else []): + if isinstance(elem, dict): + _fix_json_arrays(elem, items_schema['properties']) elif pt == 'object' and 'properties' in ps and isinstance(val, dict): _fix_json_arrays(val, ps['properties']) _fix_json_arrays(plugin_config, schema['properties']) diff --git a/web_interface/templates/v3/partials/tools.html b/web_interface/templates/v3/partials/tools.html index 0fcbeeee..3e249988 100644 --- a/web_interface/templates/v3/partials/tools.html +++ b/web_interface/templates/v3/partials/tools.html @@ -229,7 +229,14 @@ headers: {'Content-Type': 'application/json'}, body: JSON.stringify({action}) }) - .then(r => r.json()) + .then(r => { + if (!r.ok) { + return r.json() + .then(d => Promise.reject(new Error(d.message || `HTTP ${r.status}`))) + .catch(() => Promise.reject(new Error(`HTTP ${r.status}`))); + } + return r.json(); + }) .then(data => { const ok = data.status === 'success'; showResult(