Spaces:
Paused
Paused
Upload 19 files
Browse files- lagacy_ui/api_controller.py +80 -0
- lagacy_ui/auth_controller.py +26 -0
- lagacy_ui/config_controller.py +34 -0
- lagacy_ui/project_controller.py +103 -0
- lagacy_ui/spark_controller.py +48 -0
- lagacy_ui/static/addIntentModal.html +27 -0
- lagacy_ui/static/index.html +47 -0
- lagacy_ui/static/js/admin.js +12 -0
- lagacy_ui/static/js/api.js +111 -0
- lagacy_ui/static/js/auth.js +17 -0
- lagacy_ui/static/js/common.js +31 -0
- lagacy_ui/static/js/config.js +32 -0
- lagacy_ui/static/js/project.js +203 -0
- lagacy_ui/static/js/spark.js +41 -0
- lagacy_ui/static/js/test.js +5 -0
- lagacy_ui/static/newProjectModal.html +17 -0
- lagacy_ui/static/newVersionModal.html +20 -0
- lagacy_ui/static/style.css +59 -0
- lagacy_ui/test_controller.py +21 -0
lagacy_ui/api_controller.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException, Request, Depends
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from service_config import ServiceConfig
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/list")
|
| 9 |
+
def list_apis(config: ServiceConfig = Depends(get_config)):
|
| 10 |
+
return config.apis
|
| 11 |
+
|
| 12 |
+
@router.post("/add")
|
| 13 |
+
async def add_api(request: Request, config: ServiceConfig = Depends(get_config)):
|
| 14 |
+
data = await request.json()
|
| 15 |
+
api_name = data.get("api_name")
|
| 16 |
+
api_data = data.get("api_data")
|
| 17 |
+
|
| 18 |
+
if not api_name or not api_data:
|
| 19 |
+
raise HTTPException(status_code=400, detail="api_name and api_data are required")
|
| 20 |
+
|
| 21 |
+
if api_name in config.apis:
|
| 22 |
+
raise HTTPException(status_code=400, detail="API with this name already exists")
|
| 23 |
+
|
| 24 |
+
config.apis[api_name] = api_data
|
| 25 |
+
|
| 26 |
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
| 27 |
+
json.dump(config, f, indent=2)
|
| 28 |
+
|
| 29 |
+
return {"message": f"API {api_name} added"}
|
| 30 |
+
|
| 31 |
+
@router.post("/update")
|
| 32 |
+
async def update_api(request: Request, config: ServiceConfig = Depends(get_config)):
|
| 33 |
+
data = await request.json()
|
| 34 |
+
api_name = data.get("api_name")
|
| 35 |
+
api_data = data.get("api_data")
|
| 36 |
+
|
| 37 |
+
if not api_name or not api_data:
|
| 38 |
+
raise HTTPException(status_code=400, detail="api_name and api_data are required")
|
| 39 |
+
|
| 40 |
+
if api_name not in config.apis:
|
| 41 |
+
raise HTTPException(status_code=404, detail="API not found")
|
| 42 |
+
|
| 43 |
+
config.apis[api_name] = api_data
|
| 44 |
+
|
| 45 |
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
| 46 |
+
json.dump(config, f, indent=2)
|
| 47 |
+
|
| 48 |
+
return {"message": f"API {api_name} updated"}
|
| 49 |
+
|
| 50 |
+
@router.post("/delete")
|
| 51 |
+
async def delete_api(request: Request, config: ServiceConfig = Depends(get_config)):
|
| 52 |
+
data = await request.json()
|
| 53 |
+
api_name = data.get("api_name")
|
| 54 |
+
|
| 55 |
+
if not api_name:
|
| 56 |
+
raise HTTPException(status_code=400, detail="api_name is required")
|
| 57 |
+
|
| 58 |
+
if api_name not in config.apis:
|
| 59 |
+
raise HTTPException(status_code=404, detail="API not found")
|
| 60 |
+
|
| 61 |
+
# Check if API is used in any intent
|
| 62 |
+
used_in = []
|
| 63 |
+
for project_name, project in config.projects.items():
|
| 64 |
+
for version in project.get("versions", []):
|
| 65 |
+
for intent in version.get("intents", []):
|
| 66 |
+
if intent.get("action") == api_name:
|
| 67 |
+
used_in.append(f"{project_name} → v{version.get('version_number')} → {intent.get('name')}")
|
| 68 |
+
|
| 69 |
+
if used_in:
|
| 70 |
+
raise HTTPException(
|
| 71 |
+
status_code=400,
|
| 72 |
+
detail=f"API '{api_name}' is used in intents: {', '.join(used_in)}. Cannot delete."
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
del config.apis[api_name]
|
| 76 |
+
|
| 77 |
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
| 78 |
+
json.dump(config, f, indent=2)
|
| 79 |
+
|
| 80 |
+
return {"message": f"API {api_name} deleted"}
|
lagacy_ui/auth_controller.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Depends, HTTPException
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
import hashlib
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
class LoginRequest(BaseModel):
|
| 9 |
+
username: str
|
| 10 |
+
password: str
|
| 11 |
+
|
| 12 |
+
def verify_password(stored_hash, input_password):
|
| 13 |
+
# Basit SHA256 hash kontrolü (salt + hash mekanizması uygulanabilir)
|
| 14 |
+
input_hash = hashlib.sha256(input_password.encode()).hexdigest()
|
| 15 |
+
return stored_hash == input_hash
|
| 16 |
+
|
| 17 |
+
@router.post("/auth/login")
|
| 18 |
+
def login(request: LoginRequest, config: ServiceConfig = Depends(get_config)):
|
| 19 |
+
user = next((u for u in config.data.get('users', []) if u['username'] == request.username), None)
|
| 20 |
+
if not user:
|
| 21 |
+
raise HTTPException(status_code=401, detail="Invalid username or password")
|
| 22 |
+
|
| 23 |
+
if not verify_password(user['password_hash'], request.password):
|
| 24 |
+
raise HTTPException(status_code=401, detail="Invalid username or password")
|
| 25 |
+
|
| 26 |
+
return { "status": "success" }
|
lagacy_ui/config_controller.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException, Request, Depends
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from service_config import ServiceConfig
|
| 4 |
+
import json
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/get")
|
| 9 |
+
def get_config_values(config: ServiceConfig = Depends(get_config)):
|
| 10 |
+
return {
|
| 11 |
+
"work_mode": config.work_mode,
|
| 12 |
+
"cloud_token": config.cloud_token
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
@router.post("/update")
|
| 16 |
+
async def update_config(request: Request, config: ServiceConfig = Depends(get_config)):
|
| 17 |
+
data = await request.json()
|
| 18 |
+
work_mode = data.get("work_mode")
|
| 19 |
+
cloud_token = data.get("cloud_token")
|
| 20 |
+
|
| 21 |
+
if work_mode not in ["hfcloud", "cloud", "on-premise"]:
|
| 22 |
+
raise HTTPException(status_code=400, detail="Invalid work mode")
|
| 23 |
+
|
| 24 |
+
if (work_mode in ["hfcloud", "cloud"]) and not cloud_token:
|
| 25 |
+
raise HTTPException(status_code=400, detail="Cloud token required for selected mode")
|
| 26 |
+
|
| 27 |
+
config.work_mode = work_mode
|
| 28 |
+
config.cloud_token = cloud_token
|
| 29 |
+
|
| 30 |
+
with open(config.config_path, "w", encoding="utf-8") as f:
|
| 31 |
+
json.dump(config, f, indent=2)
|
| 32 |
+
|
| 33 |
+
return {"message": "Configuration updated"}
|
| 34 |
+
|
lagacy_ui/project_controller.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Depends, HTTPException
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from utils import save_service_config, log
|
| 4 |
+
import copy
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/project/details")
|
| 9 |
+
def get_project_details(config: ServiceConfig = Depends(get_config)):
|
| 10 |
+
project = config.get_current_project()
|
| 11 |
+
return project
|
| 12 |
+
|
| 13 |
+
@router.post("/project/update")
|
| 14 |
+
def update_project(config: ServiceConfig = Depends(get_config)):
|
| 15 |
+
# Implement project update logic here if needed
|
| 16 |
+
save_service_config(config)
|
| 17 |
+
log("✅ Project updated")
|
| 18 |
+
return { "status": "updated" }
|
| 19 |
+
|
| 20 |
+
@router.post("/project/publish")
|
| 21 |
+
def publish_project(config: ServiceConfig = Depends(get_config)):
|
| 22 |
+
project = config.get_current_project()
|
| 23 |
+
current_version = next((v for v in project['versions'] if not v.get('published', False)), None)
|
| 24 |
+
if not current_version:
|
| 25 |
+
raise HTTPException(status_code=400, detail="No unpublished version found")
|
| 26 |
+
current_version['published'] = True
|
| 27 |
+
save_service_config(config)
|
| 28 |
+
log(f"✅ Version {current_version['no']} published for project {project['name']}")
|
| 29 |
+
return { "status": "published" }
|
| 30 |
+
|
| 31 |
+
@router.post("/project/new")
|
| 32 |
+
def create_project(name: str, config: ServiceConfig = Depends(get_config)):
|
| 33 |
+
if any(p['name'] == name for p in config.data['projects']):
|
| 34 |
+
raise HTTPException(status_code=400, detail="Project already exists")
|
| 35 |
+
new_project = {
|
| 36 |
+
"name": name,
|
| 37 |
+
"versions": []
|
| 38 |
+
}
|
| 39 |
+
config.data['projects'].append(new_project)
|
| 40 |
+
save_service_config(config)
|
| 41 |
+
log(f"✅ New project '{name}' created")
|
| 42 |
+
return { "status": "success" }
|
| 43 |
+
|
| 44 |
+
@router.post("/project/delete")
|
| 45 |
+
def delete_project(name: str, config: ServiceConfig = Depends(get_config)):
|
| 46 |
+
project = next((p for p in config.data['projects'] if p['name'] == name), None)
|
| 47 |
+
if not project:
|
| 48 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 49 |
+
config.data['projects'].remove(project)
|
| 50 |
+
save_service_config(config)
|
| 51 |
+
log(f"🗑️ Project '{name}' deleted")
|
| 52 |
+
return { "status": "success" }
|
| 53 |
+
|
| 54 |
+
@router.get("/project/versions")
|
| 55 |
+
def get_project_versions(config: ServiceConfig = Depends(get_config)):
|
| 56 |
+
project = config.get_current_project()
|
| 57 |
+
return project['versions']
|
| 58 |
+
|
| 59 |
+
@router.post("/project/new-version")
|
| 60 |
+
def create_new_version(project_name: str, base_version_no: int, config: ServiceConfig = Depends(get_config)):
|
| 61 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 62 |
+
if not project:
|
| 63 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 64 |
+
base_version = next((v for v in project['versions'] if v['no'] == base_version_no), None)
|
| 65 |
+
if not base_version:
|
| 66 |
+
raise HTTPException(status_code=404, detail="Base version not found")
|
| 67 |
+
new_version_no = max((v['no'] for v in project['versions']), default=0) + 1
|
| 68 |
+
new_version = copy.deepcopy(base_version)
|
| 69 |
+
new_version['no'] = new_version_no
|
| 70 |
+
new_version['published'] = False
|
| 71 |
+
project['versions'].append(new_version)
|
| 72 |
+
save_service_config(config)
|
| 73 |
+
log(f"✅ New version {new_version_no} created for project {project_name}")
|
| 74 |
+
return { "status": "success", "new_version": new_version_no }
|
| 75 |
+
|
| 76 |
+
@router.post("/project/delete-version")
|
| 77 |
+
def delete_version(project_name: str, version_no: int, config: ServiceConfig = Depends(get_config)):
|
| 78 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 79 |
+
if not project:
|
| 80 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 81 |
+
version = next((v for v in project['versions'] if v['no'] == version_no), None)
|
| 82 |
+
if not version:
|
| 83 |
+
raise HTTPException(status_code=404, detail="Version not found")
|
| 84 |
+
project['versions'].remove(version)
|
| 85 |
+
save_service_config(config)
|
| 86 |
+
log(f"🗑️ Version {version_no} deleted from project {project_name}")
|
| 87 |
+
return { "status": "success" }
|
| 88 |
+
|
| 89 |
+
@router.post("/project/update-api")
|
| 90 |
+
def update_api(project_name: str, version_no: int, api_data: dict, config: ServiceConfig = Depends(get_config)):
|
| 91 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 92 |
+
if not project:
|
| 93 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 94 |
+
version = next((v for v in project['versions'] if v['no'] == version_no), None)
|
| 95 |
+
if not version:
|
| 96 |
+
raise HTTPException(status_code=404, detail="Version not found")
|
| 97 |
+
existing_api = next((a for a in version['apis'] if a['name'] == api_data['name']), None)
|
| 98 |
+
if existing_api:
|
| 99 |
+
version['apis'].remove(existing_api)
|
| 100 |
+
version['apis'].append(api_data)
|
| 101 |
+
save_service_config(config)
|
| 102 |
+
log(f"🔧 API '{api_data['name']}' updated in project {project_name} version {version_no}")
|
| 103 |
+
return { "status": "success" }
|
lagacy_ui/spark_controller.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, Depends, HTTPException
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from utils import save_service_config, log
|
| 4 |
+
import requests
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/spark/projects")
|
| 9 |
+
def get_spark_projects(config: ServiceConfig = Depends(get_config)):
|
| 10 |
+
try:
|
| 11 |
+
spark_url = config.spark_endpoint + "/projects"
|
| 12 |
+
response = requests.get(spark_url, timeout=5)
|
| 13 |
+
response.raise_for_status()
|
| 14 |
+
projects = response.json()
|
| 15 |
+
return { "projects": projects }
|
| 16 |
+
except Exception as e:
|
| 17 |
+
log(f"⚠️ Spark service unreachable: {str(e)}")
|
| 18 |
+
return { "error": True, "projects": [] }
|
| 19 |
+
|
| 20 |
+
@router.post("/spark/enable")
|
| 21 |
+
def enable_project(project_name: str, config: ServiceConfig = Depends(get_config)):
|
| 22 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 23 |
+
if not project:
|
| 24 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 25 |
+
project['enabled'] = True
|
| 26 |
+
save_service_config(config)
|
| 27 |
+
log(f"✅ Project '{project_name}' enabled")
|
| 28 |
+
return { "status": "enabled" }
|
| 29 |
+
|
| 30 |
+
@router.post("/spark/disable")
|
| 31 |
+
def disable_project(project_name: str, config: ServiceConfig = Depends(get_config)):
|
| 32 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 33 |
+
if not project:
|
| 34 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 35 |
+
project['enabled'] = False
|
| 36 |
+
save_service_config(config)
|
| 37 |
+
log(f"✅ Project '{project_name}' disabled")
|
| 38 |
+
return { "status": "disabled" }
|
| 39 |
+
|
| 40 |
+
@router.post("/spark/delete")
|
| 41 |
+
def delete_project_spark(project_name: str, config: ServiceConfig = Depends(get_config)):
|
| 42 |
+
project = next((p for p in config.data['projects'] if p['name'] == project_name), None)
|
| 43 |
+
if not project:
|
| 44 |
+
raise HTTPException(status_code=404, detail="Project not found")
|
| 45 |
+
config.data['projects'].remove(project)
|
| 46 |
+
save_service_config(config)
|
| 47 |
+
log(f"🗑️ Project '{project_name}' deleted from Spark")
|
| 48 |
+
return { "status": "deleted" }
|
lagacy_ui/static/addIntentModal.html
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- Add/Edit API Modal -->
|
| 2 |
+
<div class="modal fade" id="addIntentModal" tabindex="-1" aria-labelledby="addIntentModalLabel" aria-hidden="true">
|
| 3 |
+
<div class="modal-dialog">
|
| 4 |
+
<div class="modal-content">
|
| 5 |
+
<div class="modal-header">
|
| 6 |
+
<h5 class="modal-title">Add / Edit API</h5>
|
| 7 |
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
| 8 |
+
</div>
|
| 9 |
+
<div class="modal-body">
|
| 10 |
+
<input type="text" id="apiNameInput" class="form-control mb-2" placeholder="API Name">
|
| 11 |
+
<input type="text" id="apiUrlInput" class="form-control mb-2" placeholder="API URL">
|
| 12 |
+
<input type="text" id="apiAuthInput" class="form-control mb-2" placeholder="Auth (if any)">
|
| 13 |
+
<select id="apiMethodSelect" class="form-control mb-2">
|
| 14 |
+
<option value="GET">GET</option>
|
| 15 |
+
<option value="POST">POST</option>
|
| 16 |
+
</select>
|
| 17 |
+
<div id="headerContainer" class="mb-2">
|
| 18 |
+
<!-- Dynamic header rows -->
|
| 19 |
+
</div>
|
| 20 |
+
<button class="btn btn-secondary mb-2" onclick="addHeaderRow()">+ Add Header</button>
|
| 21 |
+
</div>
|
| 22 |
+
<div class="modal-footer">
|
| 23 |
+
<button class="btn btn-primary" onclick="saveAPI()">Save API</button>
|
| 24 |
+
</div>
|
| 25 |
+
</div>
|
| 26 |
+
</div>
|
| 27 |
+
</div>
|
lagacy_ui/static/index.html
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<title>Flare Project Admin</title>
|
| 6 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 7 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
|
| 8 |
+
<script src="project.js" defer></script>
|
| 9 |
+
</head>
|
| 10 |
+
<body>
|
| 11 |
+
<div class="container mt-4">
|
| 12 |
+
<div id="loginPanel">
|
| 13 |
+
<h1>Login</h1>
|
| 14 |
+
<input type="text" id="usernameInput" class="form-control mb-2" placeholder="Username">
|
| 15 |
+
<input type="password" id="passwordInput" class="form-control mb-2" placeholder="Password">
|
| 16 |
+
<button class="btn btn-primary" onclick="login()">Login</button>
|
| 17 |
+
<div id="loginError" class="text-danger mt-2" style="display:none;">Invalid credentials</div>
|
| 18 |
+
</div>
|
| 19 |
+
|
| 20 |
+
<div id="mainPanel" style="display:none;">
|
| 21 |
+
<h1>Flare Project Admin Panel</h1>
|
| 22 |
+
|
| 23 |
+
<div class="mb-3">
|
| 24 |
+
<button class="btn btn-success" id="newProjectBtn">+ New Project</button>
|
| 25 |
+
<button class="btn btn-primary" id="newVersionBtn">+ New Version</button>
|
| 26 |
+
<button class="btn btn-secondary" id="saveChangesBtn">Save Project</button>
|
| 27 |
+
<button class="btn btn-warning" id="publishVersionBtn">Publish Version</button>
|
| 28 |
+
</div>
|
| 29 |
+
|
| 30 |
+
<div id="projectDetails" class="mb-4">
|
| 31 |
+
<!-- Project details will be injected here -->
|
| 32 |
+
</div>
|
| 33 |
+
|
| 34 |
+
<div>
|
| 35 |
+
<h3>Intents</h3>
|
| 36 |
+
<button class="btn btn-outline-primary mb-2" id="addIntentBtn">+ Add Intent / API</button>
|
| 37 |
+
</div>
|
| 38 |
+
|
| 39 |
+
<div>
|
| 40 |
+
<h3>Spark Project List</h3>
|
| 41 |
+
<ul id="sparkProjectList" class="list-group mb-4"></ul>
|
| 42 |
+
<button class="btn btn-info" onclick="loadSparkProjects()">Get Spark Project List</button>
|
| 43 |
+
</div>
|
| 44 |
+
</div>
|
| 45 |
+
</div>
|
| 46 |
+
</body>
|
| 47 |
+
</html>
|
lagacy_ui/static/js/admin.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function seedTestData() {
|
| 2 |
+
apiPost('/project/seed/test_data', {})
|
| 3 |
+
.then(data => showResult('admin-result', data))
|
| 4 |
+
.catch(err => console.error(err));
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
function clearAllProjects() {
|
| 8 |
+
if (!confirm('Are you sure you want to clear all projects? This cannot be undone!')) return;
|
| 9 |
+
apiPost('/project/clear/all', {})
|
| 10 |
+
.then(data => showResult('admin-result', data))
|
| 11 |
+
.catch(err => console.error(err));
|
| 12 |
+
}
|
lagacy_ui/static/js/api.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function listApis() {
|
| 2 |
+
apiGet('/api/list')
|
| 3 |
+
.then(data => {
|
| 4 |
+
const body = document.getElementById('api-body');
|
| 5 |
+
body.innerHTML = '';
|
| 6 |
+
const keys = Object.keys(data);
|
| 7 |
+
if (keys.length === 0) {
|
| 8 |
+
const row = document.createElement('tr');
|
| 9 |
+
row.innerHTML = `<td colspan="4" class="text-danger">No APIs defined.</td>`;
|
| 10 |
+
body.appendChild(row);
|
| 11 |
+
return;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
keys.forEach(apiName => {
|
| 15 |
+
const api = data[apiName];
|
| 16 |
+
const row = document.createElement('tr');
|
| 17 |
+
row.innerHTML = `
|
| 18 |
+
<td>${apiName}</td>
|
| 19 |
+
<td>${api.url}</td>
|
| 20 |
+
<td>${api.method}</td>
|
| 21 |
+
<td>
|
| 22 |
+
<button class="btn btn-sm btn-warning" onclick="editApi('${apiName}')">Edit</button>
|
| 23 |
+
<button class="btn btn-sm btn-danger" onclick="deleteApi('${apiName}')">Delete</button>
|
| 24 |
+
</td>
|
| 25 |
+
`;
|
| 26 |
+
body.appendChild(row);
|
| 27 |
+
});
|
| 28 |
+
})
|
| 29 |
+
.catch(err => {
|
| 30 |
+
console.error(err);
|
| 31 |
+
showResult('api-result', { detail: 'Failed to load API list.' });
|
| 32 |
+
});
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
function addApi() {
|
| 36 |
+
const apiName = prompt('Enter new API name:');
|
| 37 |
+
if (!apiName) return;
|
| 38 |
+
|
| 39 |
+
const url = prompt('Enter API URL:');
|
| 40 |
+
const method = prompt('Enter HTTP method (GET, POST, etc.):');
|
| 41 |
+
|
| 42 |
+
if (!url || !method) {
|
| 43 |
+
alert('URL and method are required.');
|
| 44 |
+
return;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
const apiData = {
|
| 48 |
+
url: url,
|
| 49 |
+
method: method,
|
| 50 |
+
headers: [],
|
| 51 |
+
body: {},
|
| 52 |
+
timeout: 5,
|
| 53 |
+
retry_count: 0
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
apiPost('/api/add', { api_name: apiName, api_data: apiData })
|
| 57 |
+
.then(data => {
|
| 58 |
+
showResult('api-result', data);
|
| 59 |
+
listApis();
|
| 60 |
+
})
|
| 61 |
+
.catch(err => {
|
| 62 |
+
console.error(err);
|
| 63 |
+
showResult('api-result', { detail: 'Failed to add API.' });
|
| 64 |
+
});
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
function editApi(apiName) {
|
| 68 |
+
const url = prompt('Enter new API URL:');
|
| 69 |
+
const method = prompt('Enter new HTTP method:');
|
| 70 |
+
|
| 71 |
+
if (!url || !method) {
|
| 72 |
+
alert('URL and method are required.');
|
| 73 |
+
return;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const apiData = {
|
| 77 |
+
url: url,
|
| 78 |
+
method: method,
|
| 79 |
+
headers: [],
|
| 80 |
+
body: {},
|
| 81 |
+
timeout: 5,
|
| 82 |
+
retry_count: 0
|
| 83 |
+
};
|
| 84 |
+
|
| 85 |
+
apiPost('/api/update', { api_name: apiName, api_data: apiData })
|
| 86 |
+
.then(data => {
|
| 87 |
+
showResult('api-result', data);
|
| 88 |
+
listApis();
|
| 89 |
+
})
|
| 90 |
+
.catch(err => {
|
| 91 |
+
console.error(err);
|
| 92 |
+
showResult('api-result', { detail: 'Failed to update API.' });
|
| 93 |
+
});
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
function deleteApi(apiName) {
|
| 97 |
+
if (!confirm(`Are you sure you want to delete API '${apiName}'?`)) return;
|
| 98 |
+
|
| 99 |
+
apiPost('/api/delete', { api_name: apiName })
|
| 100 |
+
.then(data => {
|
| 101 |
+
showResult('api-result', data);
|
| 102 |
+
listApis();
|
| 103 |
+
})
|
| 104 |
+
.catch(err => {
|
| 105 |
+
console.error(err);
|
| 106 |
+
if (err.detail) {
|
| 107 |
+
alert(`❗ ${err.detail}`);
|
| 108 |
+
}
|
| 109 |
+
showResult('api-result', { detail: 'Failed to delete API.' });
|
| 110 |
+
});
|
| 111 |
+
}
|
lagacy_ui/static/js/auth.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function login() {
|
| 2 |
+
const username = document.getElementById('login-username').value;
|
| 3 |
+
const password = document.getElementById('login-password').value;
|
| 4 |
+
apiPost('/auth/login', { username, password })
|
| 5 |
+
.then(data => {
|
| 6 |
+
if (data.message === "Login successful") {
|
| 7 |
+
document.getElementById('login-panel').classList.add('d-none');
|
| 8 |
+
document.getElementById('main-tabs').classList.remove('d-none');
|
| 9 |
+
} else {
|
| 10 |
+
showResult('login-result', data);
|
| 11 |
+
}
|
| 12 |
+
})
|
| 13 |
+
.catch(err => {
|
| 14 |
+
console.error(err);
|
| 15 |
+
document.getElementById('login-result').innerText = "Error connecting to server.";
|
| 16 |
+
});
|
| 17 |
+
}
|
lagacy_ui/static/js/common.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const apiBase = 'https://ucsturkey-flare.hf.space';
|
| 2 |
+
|
| 3 |
+
function apiPost(path, body) {
|
| 4 |
+
return fetch(`${apiBase}${path}`, {
|
| 5 |
+
method: 'POST',
|
| 6 |
+
headers: { 'Content-Type': 'application/json' },
|
| 7 |
+
body: JSON.stringify(body)
|
| 8 |
+
}).then(res => {
|
| 9 |
+
if (!res.ok) {
|
| 10 |
+
return res.json().then(err => { throw err; });
|
| 11 |
+
}
|
| 12 |
+
return res.json();
|
| 13 |
+
});
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
function apiGet(path) {
|
| 18 |
+
return fetch(`${apiBase}${path}`)
|
| 19 |
+
.then(res => res.json());
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
function showResult(id, data) {
|
| 23 |
+
const el = document.getElementById(id);
|
| 24 |
+
if (data.detail) {
|
| 25 |
+
el.innerText = data.detail;
|
| 26 |
+
el.classList.add('text-danger');
|
| 27 |
+
} else {
|
| 28 |
+
el.innerText = data.message || JSON.stringify(data, null, 2);
|
| 29 |
+
el.classList.remove('text-danger');
|
| 30 |
+
}
|
| 31 |
+
}
|
lagacy_ui/static/js/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function getConfig() {
|
| 2 |
+
apiGet('/config/get')
|
| 3 |
+
.then(data => {
|
| 4 |
+
document.getElementById('work-mode').value = data.work_mode;
|
| 5 |
+
document.getElementById('cloud-token').value = data.cloud_token;
|
| 6 |
+
toggleCloudToken();
|
| 7 |
+
})
|
| 8 |
+
.catch(err => console.error(err));
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
function updateConfig() {
|
| 12 |
+
const workMode = document.getElementById('work-mode').value;
|
| 13 |
+
const cloudToken = document.getElementById('cloud-token').value;
|
| 14 |
+
|
| 15 |
+
if ((workMode === 'hfcloud' || workMode === 'cloud') && cloudToken.trim() === '') {
|
| 16 |
+
alert('Cloud token cannot be empty for selected work mode.');
|
| 17 |
+
return;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
apiPost('/config/update', { work_mode: workMode, cloud_token: cloudToken })
|
| 21 |
+
.then(data => showResult('config-result', data))
|
| 22 |
+
.catch(err => console.error(err));
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
function toggleCloudToken() {
|
| 26 |
+
const workMode = document.getElementById('work-mode').value;
|
| 27 |
+
const cloudTokenField = document.getElementById('cloud-token');
|
| 28 |
+
cloudTokenField.disabled = (workMode === 'on-premise');
|
| 29 |
+
if (cloudTokenField.disabled) {
|
| 30 |
+
cloudTokenField.value = '';
|
| 31 |
+
}
|
| 32 |
+
}
|
lagacy_ui/static/js/project.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 2 |
+
loadProjectDetails();
|
| 3 |
+
setupEventListeners();
|
| 4 |
+
});
|
| 5 |
+
|
| 6 |
+
let CURRENT_PROJECT = null;
|
| 7 |
+
let CURRENT_VERSION = null;
|
| 8 |
+
|
| 9 |
+
function setupEventListeners() {
|
| 10 |
+
document.getElementById('saveChangesBtn').addEventListener('click', saveProject);
|
| 11 |
+
document.getElementById('publishVersionBtn').addEventListener('click', publishProject);
|
| 12 |
+
document.getElementById('addIntentBtn').addEventListener('click', showAddIntentModal);
|
| 13 |
+
document.getElementById('newVersionBtn').addEventListener('click', showNewVersionModal);
|
| 14 |
+
document.getElementById('newProjectBtn').addEventListener('click', showNewProjectModal);
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
function loadProjectDetails() {
|
| 18 |
+
fetch('/project/details')
|
| 19 |
+
.then(response => response.json())
|
| 20 |
+
.then(data => {
|
| 21 |
+
CURRENT_PROJECT = data.name;
|
| 22 |
+
CURRENT_VERSION = data.version;
|
| 23 |
+
renderProjectDetails(data);
|
| 24 |
+
})
|
| 25 |
+
.catch(error => {
|
| 26 |
+
console.error('Error loading project details:', error);
|
| 27 |
+
alert('Failed to load project details.');
|
| 28 |
+
});
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
function renderProjectDetails(data) {
|
| 32 |
+
const container = document.getElementById('projectDetails');
|
| 33 |
+
container.innerHTML = '';
|
| 34 |
+
|
| 35 |
+
const published = data.published ? '✅ Yes' : '❌ No';
|
| 36 |
+
container.innerHTML += `<p><strong>Project:</strong> ${data.name}</p>`;
|
| 37 |
+
container.innerHTML += `<p><strong>Version:</strong> ${data.version}</p>`;
|
| 38 |
+
container.innerHTML += `<p><strong>Published:</strong> ${published}</p>`;
|
| 39 |
+
|
| 40 |
+
const list = document.createElement('ul');
|
| 41 |
+
data.intents.forEach(intent => {
|
| 42 |
+
const li = document.createElement('li');
|
| 43 |
+
li.style.marginBottom = '8px';
|
| 44 |
+
li.innerHTML = `${intent.name}
|
| 45 |
+
<button class="btn btn-sm btn-primary" onclick="editIntent('${intent.id}')">Edit</button>
|
| 46 |
+
<button class="btn btn-sm btn-danger" onclick="removeIntent('${intent.id}')">-</button>`;
|
| 47 |
+
list.appendChild(li);
|
| 48 |
+
});
|
| 49 |
+
container.appendChild(list);
|
| 50 |
+
|
| 51 |
+
document.getElementById('publishVersionBtn').disabled = data.published;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
function saveProject() {
|
| 55 |
+
fetch('/project/update', { method: 'POST' })
|
| 56 |
+
.then(response => response.json())
|
| 57 |
+
.then(() => alert('Project saved!'))
|
| 58 |
+
.catch(() => alert('Failed to save project.'));
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
function publishProject() {
|
| 62 |
+
fetch('/project/publish', { method: 'POST' })
|
| 63 |
+
.then(response => response.json())
|
| 64 |
+
.then(() => alert('Project published!'))
|
| 65 |
+
.catch(() => alert('Failed to publish project.'));
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
function showNewProjectModal() {
|
| 69 |
+
const name = prompt('Enter new project name:');
|
| 70 |
+
if (name) {
|
| 71 |
+
fetch('/project/new', {
|
| 72 |
+
method: 'POST',
|
| 73 |
+
headers: { 'Content-Type': 'application/json' },
|
| 74 |
+
body: JSON.stringify({ name })
|
| 75 |
+
})
|
| 76 |
+
.then(r => r.json())
|
| 77 |
+
.then(() => alert('Project created!'))
|
| 78 |
+
.catch(() => alert('Failed to create project.'));
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
function showNewVersionModal() {
|
| 83 |
+
fetch('/project/versions')
|
| 84 |
+
.then(response => response.json())
|
| 85 |
+
.then(versions => {
|
| 86 |
+
const select = document.getElementById('baseVersionSelect');
|
| 87 |
+
select.innerHTML = '';
|
| 88 |
+
versions.forEach(v => {
|
| 89 |
+
const option = document.createElement('option');
|
| 90 |
+
option.value = v.no;
|
| 91 |
+
option.textContent = `Version ${v.no}`;
|
| 92 |
+
select.appendChild(option);
|
| 93 |
+
});
|
| 94 |
+
$('#newVersionModal').modal('show');
|
| 95 |
+
})
|
| 96 |
+
.catch(() => alert('Failed to load versions.'));
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
function createNewVersion() {
|
| 100 |
+
const baseVersionId = document.getElementById('baseVersionSelect').value;
|
| 101 |
+
fetch('/project/new-version', {
|
| 102 |
+
method: 'POST',
|
| 103 |
+
headers: { 'Content-Type': 'application/json' },
|
| 104 |
+
body: JSON.stringify({
|
| 105 |
+
project_name: CURRENT_PROJECT,
|
| 106 |
+
base_version_no: parseInt(baseVersionId)
|
| 107 |
+
})
|
| 108 |
+
})
|
| 109 |
+
.then(r => r.json())
|
| 110 |
+
.then(() => {
|
| 111 |
+
alert('New version created!');
|
| 112 |
+
loadProjectDetails();
|
| 113 |
+
})
|
| 114 |
+
.catch(() => alert('Failed to create new version.'));
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
function loadSparkProjects() {
|
| 118 |
+
fetch('/spark/projects')
|
| 119 |
+
.then(response => response.json())
|
| 120 |
+
.then(data => {
|
| 121 |
+
if (data.error) {
|
| 122 |
+
alert('⚠ Spark service unreachable.');
|
| 123 |
+
return;
|
| 124 |
+
}
|
| 125 |
+
const list = document.getElementById('sparkProjectList');
|
| 126 |
+
list.innerHTML = '';
|
| 127 |
+
data.projects.forEach(p => {
|
| 128 |
+
const li = document.createElement('li');
|
| 129 |
+
li.textContent = p.name;
|
| 130 |
+
list.appendChild(li);
|
| 131 |
+
});
|
| 132 |
+
})
|
| 133 |
+
.catch(() => alert('⚠ Spark service unreachable.'));
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
function showAddIntentModal() {
|
| 137 |
+
$('#addIntentModal').modal('show');
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
function addHeaderRow() {
|
| 141 |
+
const container = document.getElementById('headerContainer');
|
| 142 |
+
const row = document.createElement('div');
|
| 143 |
+
row.className = 'header-row mb-2';
|
| 144 |
+
row.innerHTML = `
|
| 145 |
+
<input type="text" class="form-control d-inline-block header-key" placeholder="Key" style="width: 40%">
|
| 146 |
+
<input type="text" class="form-control d-inline-block header-value" placeholder="Value" style="width: 40%">
|
| 147 |
+
<button class="btn btn-danger btn-sm" onclick="this.parentElement.remove()">-</button>`;
|
| 148 |
+
container.appendChild(row);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
function saveAPI() {
|
| 152 |
+
const name = document.getElementById('apiNameInput').value;
|
| 153 |
+
const url = document.getElementById('apiUrlInput').value;
|
| 154 |
+
const method = document.getElementById('apiMethodSelect').value;
|
| 155 |
+
const auth = document.getElementById('apiAuthInput').value;
|
| 156 |
+
const headers = [];
|
| 157 |
+
|
| 158 |
+
document.querySelectorAll('.header-row').forEach(row => {
|
| 159 |
+
const key = row.querySelector('.header-key').value;
|
| 160 |
+
const value = row.querySelector('.header-value').value;
|
| 161 |
+
if (key && value) {
|
| 162 |
+
headers.push({ key, value });
|
| 163 |
+
}
|
| 164 |
+
});
|
| 165 |
+
|
| 166 |
+
const apiData = { name, url, method, auth, headers };
|
| 167 |
+
|
| 168 |
+
fetch('/project/update-api', {
|
| 169 |
+
method: 'POST',
|
| 170 |
+
headers: { 'Content-Type': 'application/json' },
|
| 171 |
+
body: JSON.stringify({
|
| 172 |
+
project_name: CURRENT_PROJECT,
|
| 173 |
+
version_no: CURRENT_VERSION,
|
| 174 |
+
api_data: apiData
|
| 175 |
+
})
|
| 176 |
+
})
|
| 177 |
+
.then(r => r.json())
|
| 178 |
+
.then(() => alert('API updated!'))
|
| 179 |
+
.catch(() => alert('Failed to update API.'));
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
function login() {
|
| 183 |
+
const username = document.getElementById('usernameInput').value;
|
| 184 |
+
const password = document.getElementById('passwordInput').value;
|
| 185 |
+
|
| 186 |
+
fetch('/auth/login', {
|
| 187 |
+
method: 'POST',
|
| 188 |
+
headers: { 'Content-Type': 'application/json' },
|
| 189 |
+
body: JSON.stringify({ username, password })
|
| 190 |
+
})
|
| 191 |
+
.then(response => {
|
| 192 |
+
if (response.ok) {
|
| 193 |
+
document.getElementById('loginPanel').style.display = 'none';
|
| 194 |
+
document.getElementById('mainPanel').style.display = 'block';
|
| 195 |
+
loadProjectDetails();
|
| 196 |
+
} else {
|
| 197 |
+
document.getElementById('loginError').style.display = 'block';
|
| 198 |
+
}
|
| 199 |
+
})
|
| 200 |
+
.catch(() => {
|
| 201 |
+
document.getElementById('loginError').style.display = 'block';
|
| 202 |
+
});
|
| 203 |
+
}
|
lagacy_ui/static/js/spark.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function sparkProjectList() {
|
| 2 |
+
apiGet('/spark/project_list')
|
| 3 |
+
.then(data => {
|
| 4 |
+
const body = document.getElementById('spark-body');
|
| 5 |
+
body.innerHTML = '';
|
| 6 |
+
|
| 7 |
+
if (data && Array.isArray(data.projects) && data.projects.length > 0) {
|
| 8 |
+
data.projects.forEach(proj => {
|
| 9 |
+
const row = document.createElement('tr');
|
| 10 |
+
|
| 11 |
+
row.innerHTML = `
|
| 12 |
+
<td>${proj.project_name}</td>
|
| 13 |
+
<td>${proj.version}</td>
|
| 14 |
+
<td>${proj.enabled ? '🟢' : '🔴'}</td>
|
| 15 |
+
<td>${getStatusIcon(proj.status)} ${proj.status}</td>
|
| 16 |
+
<td>${proj.last_accessed}</td>
|
| 17 |
+
`;
|
| 18 |
+
body.appendChild(row);
|
| 19 |
+
});
|
| 20 |
+
} else {
|
| 21 |
+
const row = document.createElement('tr');
|
| 22 |
+
row.innerHTML = `<td colspan="5" class="text-danger">⚠️ Failed to load Spark project list or no projects available.</td>`;
|
| 23 |
+
body.appendChild(row);
|
| 24 |
+
}
|
| 25 |
+
})
|
| 26 |
+
.catch(err => {
|
| 27 |
+
console.error(err);
|
| 28 |
+
const body = document.getElementById('spark-body');
|
| 29 |
+
body.innerHTML = '';
|
| 30 |
+
const row = document.createElement('tr');
|
| 31 |
+
row.innerHTML = `<td colspan="5" class="text-danger">❌ Error connecting to Spark service.</td>`;
|
| 32 |
+
body.appendChild(row);
|
| 33 |
+
});
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
function getStatusIcon(status) {
|
| 37 |
+
if (status === 'loading') return '⚙️';
|
| 38 |
+
if (status === 'ready') return '✅';
|
| 39 |
+
if (status === 'error') return '❌';
|
| 40 |
+
return 'ℹ️';
|
| 41 |
+
}
|
lagacy_ui/static/js/test.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function runTests() {
|
| 2 |
+
apiPost('/test/run', {})
|
| 3 |
+
.then(data => showResult('test-result', data))
|
| 4 |
+
.catch(err => console.error(err));
|
| 5 |
+
}
|
lagacy_ui/static/newProjectModal.html
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- New Project Modal (if using a modal, otherwise use prompt in JS) -->
|
| 2 |
+
<div class="modal fade" id="newProjectModal" tabindex="-1" aria-labelledby="newProjectModalLabel" aria-hidden="true">
|
| 3 |
+
<div class="modal-dialog">
|
| 4 |
+
<div class="modal-content">
|
| 5 |
+
<div class="modal-header">
|
| 6 |
+
<h5 class="modal-title">Create New Project</h5>
|
| 7 |
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
| 8 |
+
</div>
|
| 9 |
+
<div class="modal-body">
|
| 10 |
+
<input type="text" id="newProjectNameInput" class="form-control mb-2" placeholder="Project Name">
|
| 11 |
+
</div>
|
| 12 |
+
<div class="modal-footer">
|
| 13 |
+
<button class="btn btn-success" onclick="createNewProject()">Create</button>
|
| 14 |
+
</div>
|
| 15 |
+
</div>
|
| 16 |
+
</div>
|
| 17 |
+
</div>
|
lagacy_ui/static/newVersionModal.html
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- New Version Modal -->
|
| 2 |
+
<div class="modal fade" id="newVersionModal" tabindex="-1" aria-labelledby="newVersionModalLabel" aria-hidden="true">
|
| 3 |
+
<div class="modal-dialog">
|
| 4 |
+
<div class="modal-content">
|
| 5 |
+
<div class="modal-header">
|
| 6 |
+
<h5 class="modal-title">Create New Version</h5>
|
| 7 |
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
| 8 |
+
</div>
|
| 9 |
+
<div class="modal-body">
|
| 10 |
+
<label for="baseVersionSelect">Select Base Version</label>
|
| 11 |
+
<select id="baseVersionSelect" class="form-control">
|
| 12 |
+
<!-- Dynamically populated -->
|
| 13 |
+
</select>
|
| 14 |
+
</div>
|
| 15 |
+
<div class="modal-footer">
|
| 16 |
+
<button class="btn btn-success" onclick="createNewVersion()">Create</button>
|
| 17 |
+
</div>
|
| 18 |
+
</div>
|
| 19 |
+
</div>
|
| 20 |
+
</div>
|
lagacy_ui/static/style.css
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body {
|
| 2 |
+
background-color: #f8f9fa;
|
| 3 |
+
font-family: Arial, sans-serif;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
h1 {
|
| 7 |
+
color: #343a40;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
.card {
|
| 11 |
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.card-header {
|
| 15 |
+
background-color: #343a40;
|
| 16 |
+
color: white;
|
| 17 |
+
font-weight: bold;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.btn-block {
|
| 21 |
+
width: 100%;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
textarea, pre {
|
| 25 |
+
font-family: monospace;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
.tab-content {
|
| 29 |
+
padding: 1rem;
|
| 30 |
+
background-color: white;
|
| 31 |
+
border: 1px solid #dee2e6;
|
| 32 |
+
border-top: none;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
#main-tabs .nav-link {
|
| 36 |
+
cursor: pointer;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.text-danger {
|
| 40 |
+
font-weight: bold;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
table th {
|
| 44 |
+
cursor: pointer;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
table th:hover {
|
| 48 |
+
background-color: #f1f1f1;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.table-responsive {
|
| 52 |
+
max-height: 400px;
|
| 53 |
+
overflow-y: auto;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/* intent list buttons spacing */
|
| 57 |
+
#projectDetails li button {
|
| 58 |
+
margin-left: 8px;
|
| 59 |
+
}
|
lagacy_ui/test_controller.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException, Request, Depends
|
| 2 |
+
from config_provider import get_config, ServiceConfig
|
| 3 |
+
from service_config import ServiceConfig
|
| 4 |
+
import random
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/run_all")
|
| 9 |
+
def run_all_tests(config: ServiceConfig = Depends(get_config)):
|
| 10 |
+
# Mock test results
|
| 11 |
+
test_results = []
|
| 12 |
+
for project_name in config.projects.keys():
|
| 13 |
+
result = {
|
| 14 |
+
"project": project_name,
|
| 15 |
+
"status": random.choice(["passed", "failed"]),
|
| 16 |
+
"details": f"Mock test for {project_name}"
|
| 17 |
+
}
|
| 18 |
+
test_results.append(result)
|
| 19 |
+
|
| 20 |
+
return {"results": test_results}
|
| 21 |
+
|