diff --git a/backend/bot/app/web/admin_settings_manifest.py b/backend/bot/app/web/admin_settings_manifest.py index f43158a..4f4471b 100644 --- a/backend/bot/app/web/admin_settings_manifest.py +++ b/backend/bot/app/web/admin_settings_manifest.py @@ -353,7 +353,15 @@ def coerce_value(field: SettingField, raw: Any) -> Any: def manifest_payload() -> List[dict]: - """Serialize the manifest for the admin UI.""" + """Serialize the manifest for the admin UI. + + For provider presentation fields we resolve the SPEC-declared default + (e.g. the button text the bot would use if the admin leaves the override + blank) and expose it as ``default``; ``placeholder`` falls back to the + same value so existing UIs that only read ``placeholder`` also show the + hint inside the empty input. + """ + from bot.payment_providers import find_manifest_owner, manifest_field_default sections_order = { "general": 1, @@ -369,6 +377,17 @@ def manifest_payload() -> List[dict]: for field in aggregated_manifest(): auto_label_i18n_key = f"settings_field_{field.key.lower()}_label" auto_description_i18n_key = f"settings_field_{field.key.lower()}_description" + + default_value: Optional[str] = None + owner = find_manifest_owner(field.key) + if owner is not None: + spec, manifest_field = owner + default_value = manifest_field_default(spec, manifest_field) + + placeholder = field.placeholder + if not placeholder and default_value: + placeholder = default_value + item = { "key": field.key, "type": field.type, @@ -380,10 +399,12 @@ def manifest_payload() -> List[dict]: "i18n_label_key": field.i18n_label_key or auto_label_i18n_key, "i18n_description_key": field.i18n_description_key or (auto_description_i18n_key if field.description else None), - "placeholder": field.placeholder, + "placeholder": placeholder, "optional": field.optional, "secret": field.secret, } + if default_value is not None: + item["default"] = default_value if field.choices: item["choices"] = [{"value": v, "label": lbl} for v, lbl in field.choices] items.append(item) diff --git a/backend/bot/payment_providers/__init__.py b/backend/bot/payment_providers/__init__.py index c8d6265..0070d14 100644 --- a/backend/bot/payment_providers/__init__.py +++ b/backend/bot/payment_providers/__init__.py @@ -18,6 +18,7 @@ from .registry import ( get_spec_presentation, iter_provider_manifest_fields, iter_provider_specs, + manifest_field_default, iter_service_keys, iter_unique_provider_routers, pending_statuses, @@ -45,6 +46,7 @@ __all__ = [ "get_spec_presentation", "iter_provider_manifest_fields", "iter_provider_specs", + "manifest_field_default", "iter_service_keys", "iter_unique_provider_routers", "pending_statuses", diff --git a/backend/bot/payment_providers/registry.py b/backend/bot/payment_providers/registry.py index 5021a67..7251248 100644 --- a/backend/bot/payment_providers/registry.py +++ b/backend/bot/payment_providers/registry.py @@ -324,3 +324,38 @@ def find_manifest_owner(key: str) -> Optional[tuple[PaymentProviderSpec, Provide if field.key == key: return spec, field return None + + +def manifest_field_default( + spec: PaymentProviderSpec, + manifest_field: ProviderManifestField, +) -> Optional[str]: + """Resolve the SPEC-declared default for a presentation manifest field. + + Used by the admin UI to render a placeholder/hint that shows users what + button text or icon the bot falls back to when they leave the override + blank. Returns None for non-presentation fields or attributes we don't + have a mapping for (admin shouldn't render a misleading hint). + """ + if manifest_field.target != "presentation": + return None + attr = manifest_field.attr or manifest_field.key + if attr == "WEBAPP_LABEL_RU": + return ( + _localized_default(spec.webapp_labels, "ru", spec.webapp_label) + or spec.label + ) + if attr == "WEBAPP_LABEL_EN": + return ( + _localized_default(spec.webapp_labels, "en", spec.webapp_label) + or spec.label + ) + if attr == "WEBAPP_ICON": + return spec.webapp_icon + if attr == "TELEGRAM_LABEL_RU": + return _localized_default(spec.telegram_labels, "ru", None) or spec.label + if attr == "TELEGRAM_LABEL_EN": + return _localized_default(spec.telegram_labels, "en", None) or spec.label + if attr == "TELEGRAM_EMOJI": + return spec.default_telegram_emoji + return None