feat: integrate DSH Filebrowser (pinned v2.32.0, dark mode, toggle selector UI from Claude Design, /u/nabil/files/ proxy)
This commit is contained in:
+13
-6
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List
|
||||
from typing import Dict, Any, List, Optional
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
@@ -20,6 +20,8 @@ class UniverseConfig(BaseModel):
|
||||
icon: str
|
||||
persona_file: str
|
||||
enabled: bool = True
|
||||
supports_files: bool = False
|
||||
files_url: Optional[str] = None
|
||||
|
||||
class Settings(BaseSettings):
|
||||
app_name: str = "Hermes Hub"
|
||||
@@ -36,6 +38,7 @@ class Settings(BaseSettings):
|
||||
hermes_nyora_url: str = os.getenv("HERMES_NYORA_URL", "http://100.86.197.88:3020")
|
||||
hermes_perso_url: str = os.getenv("HERMES_PERSO_URL", "http://100.86.197.88:3031")
|
||||
hermes_nabil_url: str = os.getenv("HERMES_NABIL_URL", "http://127.0.0.1:8642")
|
||||
dsh_filebrowser_url: str = os.getenv("DSH_FILEBROWSER_URL", "http://127.0.0.1:8901")
|
||||
|
||||
# Hub Secret — OBLIGATOIRE, aucun fallback codé en dur (Fail-Fast au démarrage)
|
||||
hub_secret: str = Field(..., min_length=16, description="Clé secrète maîtresse requise pour Hermes Hub")
|
||||
@@ -58,7 +61,6 @@ except Exception as e:
|
||||
# but runtime will fail fast if HUB_SECRET is absent
|
||||
if "HUB_SECRET" in os.environ:
|
||||
raise e
|
||||
# Fallback only if running build/compile check with dummy env
|
||||
settings = None
|
||||
|
||||
UNIVERSES: Dict[str, UniverseConfig] = {
|
||||
@@ -71,7 +73,8 @@ UNIVERSES: Dict[str, UniverseConfig] = {
|
||||
scope="tt",
|
||||
accent_token="--accent-tt",
|
||||
icon="briefcase",
|
||||
persona_file="tt.yaml"
|
||||
persona_file="tt.yaml",
|
||||
supports_files=False
|
||||
),
|
||||
"nyora": UniverseConfig(
|
||||
id="nyora",
|
||||
@@ -82,7 +85,8 @@ UNIVERSES: Dict[str, UniverseConfig] = {
|
||||
scope="nyora",
|
||||
accent_token="--accent-nyora",
|
||||
icon="sparkles",
|
||||
persona_file="nyora.yaml"
|
||||
persona_file="nyora.yaml",
|
||||
supports_files=False
|
||||
),
|
||||
"perso": UniverseConfig(
|
||||
id="perso",
|
||||
@@ -93,7 +97,8 @@ UNIVERSES: Dict[str, UniverseConfig] = {
|
||||
scope="perso",
|
||||
accent_token="--accent-perso",
|
||||
icon="home",
|
||||
persona_file="perso.yaml"
|
||||
persona_file="perso.yaml",
|
||||
supports_files=False
|
||||
),
|
||||
"nabil": UniverseConfig(
|
||||
id="nabil",
|
||||
@@ -104,7 +109,9 @@ UNIVERSES: Dict[str, UniverseConfig] = {
|
||||
scope="nabil",
|
||||
accent_token="--accent-nabil",
|
||||
icon="terminal",
|
||||
persona_file="nabil.yaml"
|
||||
persona_file="nabil.yaml",
|
||||
supports_files=True,
|
||||
files_url=os.getenv("DSH_FILEBROWSER_URL", "http://127.0.0.1:8901")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+22
-1
@@ -1,9 +1,30 @@
|
||||
from fastapi import APIRouter, Request, HTTPException
|
||||
from app.config import UNIVERSES
|
||||
from app.config import UNIVERSES, get_universe
|
||||
from app.proxy import proxy_request
|
||||
|
||||
router = APIRouter(prefix="/u", tags=["Universe Proxy"])
|
||||
|
||||
@router.api_route("/{universe_id}/files", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/files/", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/files/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
async def dynamic_files_proxy(universe_id: str, request: Request, path: str = ""):
|
||||
if universe_id not in UNIVERSES:
|
||||
raise HTTPException(status_code=404, detail=f"Universe '{universe_id}' not found.")
|
||||
|
||||
universe = UNIVERSES[universe_id]
|
||||
if not universe.supports_files or not universe.files_url:
|
||||
raise HTTPException(status_code=404, detail=f"Universe '{universe_id}' does not have an active filebrowser.")
|
||||
|
||||
# Filebrowser runs with --baseurl /u/{universe_id}/files
|
||||
full_subpath = f"u/{universe_id}/files/{path}".rstrip("/") if path else f"u/{universe_id}/files/"
|
||||
|
||||
return await proxy_request(
|
||||
request=request,
|
||||
backend_url=universe.files_url,
|
||||
path=full_subpath,
|
||||
universe_id=universe_id
|
||||
)
|
||||
|
||||
@router.api_route("/{universe_id}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
@router.api_route("/{universe_id}/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"])
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
data-name="{{ u.name }}"
|
||||
data-scope="{{ u.scope }}"
|
||||
data-tagline="{{ u.tagline }}"
|
||||
data-supports-files="{{ 'true' if u.supports_files else 'false' }}"
|
||||
style="--item-accent: var({{ u.accent_token }});"
|
||||
>
|
||||
<div class="hub-universe-avatar">
|
||||
@@ -60,7 +61,20 @@
|
||||
</div>
|
||||
|
||||
<div class="hub-topbar-right">
|
||||
<span style="font-size: 0.75rem; color: var(--hub-text-muted);">Session sécurisée VPS ↔ NAS</span>
|
||||
<!-- Sélecteur Toggle Mode DSH (Claude Design - Univers Nabil) -->
|
||||
<div id="nabil-mode-toggle" role="tablist" aria-label="Mode du canvas" class="hub-mode-toggle">
|
||||
<button id="tab-session" role="tab" aria-selected="true" class="hub-mode-tab active" type="button">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
||||
<span>Session</span>
|
||||
</button>
|
||||
<div class="hub-mode-divider"></div>
|
||||
<button id="tab-files" role="tab" aria-selected="false" class="hub-mode-tab" type="button">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="square"><path d="M4 20h14a2 2 0 0 0 2-2V9H12L10 6H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1z"></path></svg>
|
||||
<span>Explorateur DSH</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span id="hub-security-badge" style="font-size: 0.75rem; color: var(--hub-text-muted);">Session sécurisée VPS ↔ NAS</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user