Improve admin UI setup flow

This commit is contained in:
Alishahryar1
2026-05-10 15:57:56 -07:00
parent 33de002e04
commit e386a3c8aa
8 changed files with 430 additions and 56 deletions
+2 -1
View File
@@ -995,6 +995,7 @@ def write_managed_env(updates: Mapping[str, Any]) -> dict[str, Any]:
return validation | {"applied": False, "pending_fields": []}
target_values = _target_values_with_updates(updates)
pending_fields = changed_pending_fields(updates)
path = managed_env_path()
path.parent.mkdir(parents=True, exist_ok=True)
temp_path = path.with_suffix(path.suffix + ".tmp")
@@ -1006,7 +1007,7 @@ def write_managed_env(updates: Mapping[str, Any]) -> dict[str, Any]:
"errors": [],
"env_preview": render_env_file(target_values, mask_secrets=True),
"path": str(path),
"pending_fields": changed_pending_fields(updates),
"pending_fields": pending_fields,
}
+45 -2
View File
@@ -2,16 +2,18 @@
from __future__ import annotations
import inspect
import ipaddress
from pathlib import Path
from typing import Any
from urllib.parse import urlsplit
import httpx
from fastapi import APIRouter, HTTPException, Request
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
from fastapi.responses import FileResponse
from pydantic import BaseModel, Field
from config.settings import Settings
from config.settings import get_settings as get_cached_settings
from providers.registry import ProviderRegistry
@@ -22,6 +24,7 @@ from .admin_config import (
validate_updates,
write_managed_env,
)
from .admin_urls import local_admin_url
router = APIRouter()
@@ -104,13 +107,25 @@ async def validate_admin_config(payload: AdminConfigPayload, request: Request):
@router.post("/admin/api/config/apply")
async def apply_admin_config(payload: AdminConfigPayload, request: Request):
async def apply_admin_config(
payload: AdminConfigPayload,
request: Request,
background_tasks: BackgroundTasks,
):
require_loopback_admin(request)
result = write_managed_env(_filtered_values(payload.values))
if not result["applied"]:
return result
get_cached_settings.cache_clear()
restart = _restart_metadata(result["pending_fields"], request)
result["restart"] = restart
if restart["required"] and restart["automatic"]:
callback = request.app.state.admin_restart_callback
background_tasks.add_task(_invoke_admin_restart_callback, callback)
request.app.state.admin_pending_fields = []
return result
old_registry = getattr(request.app.state, "provider_registry", None)
if isinstance(old_registry, ProviderRegistry):
await old_registry.cleanup()
@@ -200,6 +215,34 @@ def _filtered_values(values: dict[str, Any]) -> dict[str, Any]:
return {key: value for key, value in values.items() if key in FIELD_BY_KEY}
async def _invoke_admin_restart_callback(callback: Any) -> None:
result = callback()
if inspect.isawaitable(result):
await result
def _restart_metadata(fields: list[str], request: Request) -> dict[str, Any]:
callback = getattr(request.app.state, "admin_restart_callback", None)
automatic = bool(fields and callable(callback))
return {
"required": bool(fields),
"automatic": automatic,
"admin_url": _next_admin_url() if automatic else None,
"fields": fields,
}
def _next_admin_url() -> str:
fields = {
field["key"]: field["value"] for field in load_config_response()["fields"]
}
settings = Settings.model_construct(
host=fields.get("HOST") or "0.0.0.0",
port=int(fields.get("PORT") or 8082),
)
return local_admin_url(settings)
def _local_provider_url(provider_id: str, values: dict[str, str]) -> str:
if provider_id == "lmstudio":
return values.get("LM_STUDIO_BASE_URL", "")
+11 -2
View File
@@ -339,11 +339,20 @@ async function apply() {
showValidationResult(result);
return;
}
const pending = result.pending_fields || [];
const restart = result.restart || {};
if (restart.required && restart.automatic) {
showMessage("Applied. Restarting server...", "ok");
byId("applyButton").disabled = true;
setTimeout(() => {
window.location.href = restart.admin_url || "/admin";
}, 1600);
return;
}
const pending = restart.required ? restart.fields || [] : result.pending_fields || [];
await load();
showMessage(
pending.length
? `Applied. Pending manual runtime action: ${pending.join(", ")}`
? `Applied. Restart fcc-server to use: ${pending.join(", ")}`
: "Applied",
"ok",
);