feat(ui,api): wave 3 — editorial pricing, real cancel, server history, DeepL purge
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3m36s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3m36s
Pricing: full editorial redesign — serif card headers with accent pills
replace the colored font-black blocks, tone sweep across toggle/metrics/
features/CTAs, PLAN_COLORS removed; one design system app-wide.
Translate: decorative titles one step down (CTA hierarchy restored);
glossary and image-translation blocks hidden entirely for free users
(progressive disclosure — three controls for free).
Reviews: XLIFF hint line explains the exchange format; backend errors
routed through a friendly mapper (session/not-found/rate-limit/server).
Landing: fabricated hero UI cards (fake 'Context Engine' overlay)
removed — the photo no longer promises screens that don't exist.
Nav: single DashboardNavLinks component shared by sidebar and mobile
drawer (was duplicated markup).
API: GET /api/v1/translations (user job history, paginated; completed
jobs retained 24h) and POST /api/v1/translations/{id}/cancel —
cooperative cancellation with worker checkpoints before dispatch and
before finalisation, reserved quota released immediately. Translate
monitor now offers a real 'Cancel translation' next to 'Back to start';
recent-jobs list reads server history first, localStorage fallback.
DeepL purge (backend): provider module, registry registration, config
attrs/defaults, dispatch branch, admin settings schema + test branch,
legacy availability block, validation rules, plan provider lists,
error-code mappings, MCP enums, translator prompt mention, related
tests updated/removed. Fallback resolver skips unknown providers, so
stale chains containing 'deepl' degrade gracefully.
Verified: backend 110 tests passed; frontend build exit 0, vitest 9/9,
0 missing i18n keys, eslint 63 errors (vs 64 at HEAD).
This commit is contained in:
@@ -60,12 +60,6 @@ class ProvidersConfig:
|
||||
os.getenv("GOOGLE_CLOUD_RETRY_DELAY", "1.0")
|
||||
)
|
||||
|
||||
# DeepL
|
||||
DEEPL_ENABLED: bool = os.getenv("DEEPL_ENABLED", "false").lower() == "true"
|
||||
DEEPL_API_KEY: str = os.getenv("DEEPL_API_KEY", "")
|
||||
DEEPL_TIMEOUT: int = int(os.getenv("DEEPL_TIMEOUT", "30"))
|
||||
DEEPL_MAX_RETRIES: int = int(os.getenv("DEEPL_MAX_RETRIES", "3"))
|
||||
DEEPL_RETRY_DELAY: float = float(os.getenv("DEEPL_RETRY_DELAY", "1.0"))
|
||||
|
||||
# OpenAI
|
||||
OPENAI_ENABLED: bool = os.getenv("OPENAI_ENABLED", "false").lower() == "true"
|
||||
@@ -110,7 +104,7 @@ class ProvidersConfig:
|
||||
#
|
||||
# IMPORTANT: the registry-based fallback (translate_with_fallback) only
|
||||
# ever sees providers that _auto_register_providers() registers, i.e.
|
||||
# google, deepl, openai, deepseek and minimax. The OpenAI-compatible
|
||||
# google, openai, deepseek and minimax. The OpenAI-compatible
|
||||
# shims (openrouter, openrouter_premium, zai) and google_cloud are wired
|
||||
# directly in routes/translate_routes.py and are intentionally NOT part of
|
||||
# the registry fallback chain — listing them here would make
|
||||
@@ -120,16 +114,16 @@ class ProvidersConfig:
|
||||
FALLBACK_CHAIN: List[str] = [
|
||||
name.strip()
|
||||
for name in os.getenv(
|
||||
"PROVIDER_FALLBACK_CHAIN", "google,deepl,openai,deepseek,minimax"
|
||||
"PROVIDER_FALLBACK_CHAIN", "google,openai,deepseek,minimax"
|
||||
).split(",")
|
||||
if name.strip()
|
||||
]
|
||||
|
||||
# Mode-specific fallback chains
|
||||
# Classic mode: Google Translate -> DeepL
|
||||
# Classic mode: Google Translate -> Google Cloud
|
||||
FALLBACK_CHAIN_CLASSIC: List[str] = [
|
||||
name.strip()
|
||||
for name in os.getenv("FALLBACK_CHAIN_CLASSIC", "google,deepl").split(",")
|
||||
for name in os.getenv("FALLBACK_CHAIN_CLASSIC", "google").split(",")
|
||||
if name.strip()
|
||||
]
|
||||
|
||||
@@ -166,7 +160,7 @@ class ProvidersConfig:
|
||||
Get settings for a specific provider.
|
||||
|
||||
Args:
|
||||
provider_name: Name of the provider (e.g., "google", "deepl")
|
||||
provider_name: Name of the provider (e.g., "google", "openai")
|
||||
|
||||
Returns:
|
||||
ProviderSettings for the requested provider
|
||||
@@ -181,12 +175,6 @@ class ProvidersConfig:
|
||||
base_url=None,
|
||||
model=None,
|
||||
),
|
||||
"deepl": ProviderSettings(
|
||||
enabled=cls.DEEPL_ENABLED,
|
||||
api_key=cls.DEEPL_API_KEY if cls.DEEPL_API_KEY else None,
|
||||
base_url=None,
|
||||
model=None,
|
||||
),
|
||||
"openai": ProviderSettings(
|
||||
enabled=cls.OPENAI_ENABLED,
|
||||
api_key=cls.OPENAI_API_KEY if cls.OPENAI_API_KEY else None,
|
||||
@@ -231,7 +219,7 @@ class ProvidersConfig:
|
||||
return False
|
||||
|
||||
# Providers requiring API keys
|
||||
providers_requiring_key = {"deepl", "openai", "openrouter", "google_cloud", "deepseek", "minimax"}
|
||||
providers_requiring_key = {"openai", "openrouter", "google_cloud", "deepseek", "minimax"}
|
||||
|
||||
if provider_name.lower() in providers_requiring_key:
|
||||
return bool(settings.api_key)
|
||||
|
||||
Reference in New Issue
Block a user