样式修改
This commit is contained in:
1 parent
96947d7636
commit
f3511e5cd0
15 files changed
+933
-84
No files matched your search
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Literal
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -13,6 +14,8 @@ from app.gateway.auth.password import hash_password_async
|
||||
from app.gateway.deps import get_optional_user_from_request
|
||||
from deerflow.config import get_app_config
|
||||
from deerflow.config.system_settings import (
|
||||
AppearanceRouteParam,
|
||||
CompactShortcutButton,
|
||||
LeaderboardSettings,
|
||||
ModelConcurrencySettings,
|
||||
PluginDomainAgentMapping,
|
||||
@@ -537,6 +540,7 @@ class AppearanceResponse(BaseModel):
|
||||
default_skill_view: Literal["card", "list"] = Field(..., description="System default skill list display mode — card or list")
|
||||
default_agent_view: Literal["card", "list"] = Field(..., description="System default agent list display mode — card or list")
|
||||
default_layout_mode: Literal["full", "compact"] = Field(..., description="System default interface layout — full (sidebar + header) or compact (hidden)")
|
||||
compact_shortcut_buttons: list[CompactShortcutButton] = Field(default_factory=list, description="Shortcut buttons rendered in top bars")
|
||||
|
||||
|
||||
class AppearanceUpdateRequest(BaseModel):
|
||||
@@ -544,6 +548,61 @@ class AppearanceUpdateRequest(BaseModel):
|
||||
default_skill_view: Literal["card", "list"] | None = Field(default=None)
|
||||
default_agent_view: Literal["card", "list"] | None = Field(default=None)
|
||||
default_layout_mode: Literal["full", "compact"] | None = Field(default=None)
|
||||
compact_shortcut_buttons: list[CompactShortcutButton] | None = Field(default=None)
|
||||
|
||||
|
||||
def _normalize_compact_shortcut_buttons(
|
||||
buttons: list[CompactShortcutButton] | None,
|
||||
) -> list[CompactShortcutButton]:
|
||||
normalized: list[CompactShortcutButton] = []
|
||||
seen_ids: set[str] = set()
|
||||
for index, item in enumerate(buttons or []):
|
||||
label = (item.label or "").strip() or "快捷入口"
|
||||
url = (item.url or "").strip()
|
||||
row_id = (item.id or "").strip() or uuid4().hex
|
||||
if row_id in seen_ids:
|
||||
row_id = uuid4().hex
|
||||
seen_ids.add(row_id)
|
||||
|
||||
route_params: list[AppearanceRouteParam] = []
|
||||
for param in item.route_params or []:
|
||||
key = (param.key or "").strip()
|
||||
if not key:
|
||||
continue
|
||||
if param.paramType == "theme":
|
||||
route_params.append(
|
||||
AppearanceRouteParam(
|
||||
key=key,
|
||||
paramType="theme",
|
||||
themeValue=(param.themeValue or "").strip()
|
||||
or "red=red;blue=blue;dark-blue=dark-blue",
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
source = (param.source or "access_token").strip() or "access_token"
|
||||
route_params.append(
|
||||
AppearanceRouteParam(
|
||||
key=key,
|
||||
paramType="login",
|
||||
source=source,
|
||||
customValue=(param.customValue or "").strip()
|
||||
if source == "other"
|
||||
else None,
|
||||
)
|
||||
)
|
||||
|
||||
normalized.append(
|
||||
CompactShortcutButton(
|
||||
id=row_id,
|
||||
label=label,
|
||||
url=url,
|
||||
route_params=route_params,
|
||||
enabled=bool(item.enabled),
|
||||
sort_order=index,
|
||||
)
|
||||
)
|
||||
return normalized
|
||||
|
||||
|
||||
def _appearance_response(appearance) -> AppearanceResponse:
|
||||
@@ -552,6 +611,10 @@ def _appearance_response(appearance) -> AppearanceResponse:
|
||||
default_skill_view=appearance.default_skill_view,
|
||||
default_agent_view=appearance.default_agent_view,
|
||||
default_layout_mode=appearance.default_layout_mode,
|
||||
compact_shortcut_buttons=sorted(
|
||||
appearance.compact_shortcut_buttons,
|
||||
key=lambda item: item.sort_order,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -574,6 +637,10 @@ async def update_appearance_settings(
|
||||
for key in ("default_theme", "default_skill_view", "default_agent_view", "default_layout_mode"):
|
||||
if key in fields and fields[key] is not None:
|
||||
update[key] = fields[key]
|
||||
if "compact_shortcut_buttons" in fields and body.compact_shortcut_buttons is not None:
|
||||
update["compact_shortcut_buttons"] = _normalize_compact_shortcut_buttons(
|
||||
body.compact_shortcut_buttons
|
||||
)
|
||||
if update:
|
||||
updated_appearance = current.appearance.model_copy(update=update)
|
||||
saved = save_system_settings(
|
||||
|
||||
@@ -18,6 +18,7 @@ import logging
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
from uuid import uuid4
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
@@ -38,6 +39,60 @@ class PromptPrefixSettings(BaseModel):
|
||||
model_config = ConfigDict(extra="ignore")
|
||||
|
||||
|
||||
class AppearanceRouteParam(BaseModel):
|
||||
"""Runtime query-param descriptor for top-bar shortcut buttons.
|
||||
|
||||
The frontend resolves login params from ``userInfo`` and theme params from
|
||||
the current UI theme, matching the light-app center's link builder.
|
||||
"""
|
||||
|
||||
key: str = Field(default="", description="Query parameter name appended to the shortcut URL")
|
||||
paramType: Literal["login", "theme"] = Field(default="login", description="Where the parameter value comes from")
|
||||
source: str | None = Field(default=None, description="login param source field in userInfo, or 'other'")
|
||||
customValue: str | None = Field(default=None, description="Literal value when source is 'other'")
|
||||
themeValue: str | None = Field(default=None, description="Theme-value mapping string, e.g. red=red;dark-blue=dark")
|
||||
model_config = ConfigDict(extra="ignore")
|
||||
|
||||
|
||||
def _default_shortcut_route_params() -> list[AppearanceRouteParam]:
|
||||
return [
|
||||
AppearanceRouteParam(
|
||||
key="access_token",
|
||||
paramType="login",
|
||||
source="access_token",
|
||||
customValue="",
|
||||
themeValue="red=red;blue=blue;dark-blue=dark-blue",
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class CompactShortcutButton(BaseModel):
|
||||
"""Configurable shortcut shown in top bars before the theme switcher."""
|
||||
|
||||
id: str = Field(default_factory=lambda: uuid4().hex, description="Stable row id for editing")
|
||||
label: str = Field(default="快捷入口", description="Button text shown next to the icon")
|
||||
url: str = Field(default="", description="Target URL opened in a new tab")
|
||||
route_params: list[AppearanceRouteParam] = Field(
|
||||
default_factory=_default_shortcut_route_params,
|
||||
description="Query parameters resolved at launch time and appended to url",
|
||||
)
|
||||
enabled: bool = Field(default=True, description="Whether this shortcut is rendered")
|
||||
sort_order: int = Field(default=0, description="Display order in top bars")
|
||||
model_config = ConfigDict(extra="ignore")
|
||||
|
||||
|
||||
def _default_compact_shortcut_buttons() -> list[CompactShortcutButton]:
|
||||
return [
|
||||
CompactShortcutButton(
|
||||
id="default-compact-shortcut",
|
||||
label="快捷入口",
|
||||
url="",
|
||||
enabled=True,
|
||||
sort_order=0,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class AppearanceSettings(BaseModel):
|
||||
"""System-wide appearance defaults that any *new* user inherits.
|
||||
|
||||
@@ -63,6 +118,10 @@ class AppearanceSettings(BaseModel):
|
||||
default="full",
|
||||
description="Default interface layout for users who haven't picked their own — full (sidebar + header) / compact (hidden)",
|
||||
)
|
||||
compact_shortcut_buttons: list[CompactShortcutButton] = Field(
|
||||
default_factory=_default_compact_shortcut_buttons,
|
||||
description="Shortcut buttons rendered before the theme switcher in top bars",
|
||||
)
|
||||
model_config = ConfigDict(extra="ignore")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user