mirror of
https://github.com/apache/superset.git
synced 2026-07-19 13:15:49 +00:00
fix: add subdirectory deployment support for brandSpinnerUrl (#37523)
Co-authored-by: Evan Rusackas <evan@preset.io>
This commit is contained in:
@@ -649,6 +649,27 @@ def get_spa_payload(extra_data: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
return payload
|
||||
|
||||
|
||||
def _ensure_static_assets_prefix(url_or_path: str) -> str:
|
||||
"""Add the configured static asset prefix to root-relative asset paths."""
|
||||
static_assets_prefix = app.config.get("STATIC_ASSETS_PREFIX", "")
|
||||
|
||||
if (
|
||||
url_or_path.startswith("//")
|
||||
or not url_or_path.startswith("/")
|
||||
or not static_assets_prefix
|
||||
):
|
||||
return url_or_path
|
||||
|
||||
normalized_prefix = static_assets_prefix.rstrip("/")
|
||||
if normalized_prefix and (
|
||||
url_or_path == normalized_prefix
|
||||
or url_or_path.startswith(f"{normalized_prefix}/")
|
||||
):
|
||||
return url_or_path
|
||||
|
||||
return f"{normalized_prefix}{url_or_path}"
|
||||
|
||||
|
||||
def get_spa_template_context(
|
||||
entry: str | None = "spa",
|
||||
extra_bootstrap_data: dict[str, Any] | None = None,
|
||||
@@ -694,6 +715,12 @@ def get_spa_template_context(
|
||||
# User has customized APP_NAME, use it as brandAppName
|
||||
theme_tokens["brandAppName"] = app_name_from_config
|
||||
|
||||
brand_spinner_url = theme_tokens.get("brandSpinnerUrl")
|
||||
if isinstance(brand_spinner_url, str) and brand_spinner_url:
|
||||
theme_tokens["brandSpinnerUrl"] = _ensure_static_assets_prefix(
|
||||
brand_spinner_url
|
||||
)
|
||||
|
||||
# Write the modified theme data back to payload
|
||||
if "common" not in payload:
|
||||
payload["common"] = {}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
from unittest.mock import MagicMock, mock_open, patch
|
||||
|
||||
from superset.themes.types import ThemeMode
|
||||
from superset.utils import json
|
||||
from superset.views.base import (
|
||||
_load_theme_from_model,
|
||||
_merge_theme_dicts,
|
||||
@@ -892,6 +893,137 @@ class TestBrandAppNameFallback:
|
||||
assert result["default_title"] == "Superset"
|
||||
|
||||
|
||||
class TestBrandSpinnerUrlPrefix:
|
||||
"""Test brandSpinnerUrl static asset prefix handling."""
|
||||
|
||||
@patch("superset.views.base.get_spa_payload")
|
||||
@patch("superset.views.base.app")
|
||||
def test_brandspinnerurl_adds_static_assets_prefix(self, mock_app, mock_payload):
|
||||
"""Test that root-relative spinner URLs include the static assets prefix."""
|
||||
from superset.views.base import get_spa_template_context
|
||||
|
||||
mock_app.config = {
|
||||
"STATIC_ASSETS_PREFIX": "/analytics",
|
||||
}
|
||||
mock_payload.return_value = {
|
||||
"common": {
|
||||
"theme": {
|
||||
"default": {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "/static/assets/spinner.gif",
|
||||
}
|
||||
},
|
||||
"dark": {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "/static/assets/dark-spinner.gif",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = get_spa_template_context("app")
|
||||
|
||||
assert (
|
||||
result["theme_tokens"]["brandSpinnerUrl"]
|
||||
== "/analytics/static/assets/spinner.gif"
|
||||
)
|
||||
bootstrap_data = json.loads(result["bootstrap_data"])
|
||||
assert (
|
||||
bootstrap_data["common"]["theme"]["default"]["token"]["brandSpinnerUrl"]
|
||||
== "/analytics/static/assets/spinner.gif"
|
||||
)
|
||||
assert (
|
||||
bootstrap_data["common"]["theme"]["dark"]["token"]["brandSpinnerUrl"]
|
||||
== "/analytics/static/assets/dark-spinner.gif"
|
||||
)
|
||||
|
||||
@patch("superset.views.base.get_spa_payload")
|
||||
@patch("superset.views.base.app")
|
||||
def test_brandspinnerurl_keeps_absolute_url(self, mock_app, mock_payload):
|
||||
"""Test that absolute spinner URLs are not prefixed."""
|
||||
from superset.views.base import get_spa_template_context
|
||||
|
||||
mock_app.config = {
|
||||
"STATIC_ASSETS_PREFIX": "/analytics",
|
||||
}
|
||||
mock_payload.return_value = {
|
||||
"common": {
|
||||
"theme": {
|
||||
"default": {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "https://cdn.example.com/spinner.gif",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = get_spa_template_context("app")
|
||||
|
||||
assert (
|
||||
result["theme_tokens"]["brandSpinnerUrl"]
|
||||
== "https://cdn.example.com/spinner.gif"
|
||||
)
|
||||
|
||||
@patch("superset.views.base.get_spa_payload")
|
||||
@patch("superset.views.base.app")
|
||||
def test_brandspinnerurl_keeps_protocol_relative_url(self, mock_app, mock_payload):
|
||||
"""Test that protocol-relative spinner URLs are not prefixed."""
|
||||
from superset.views.base import get_spa_template_context
|
||||
|
||||
mock_app.config = {
|
||||
"STATIC_ASSETS_PREFIX": "/analytics",
|
||||
}
|
||||
mock_payload.return_value = {
|
||||
"common": {
|
||||
"theme": {
|
||||
"default": {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "//cdn.example.com/spinner.gif",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = get_spa_template_context("app")
|
||||
|
||||
assert (
|
||||
result["theme_tokens"]["brandSpinnerUrl"] == "//cdn.example.com/spinner.gif"
|
||||
)
|
||||
|
||||
@patch("superset.views.base.get_spa_payload")
|
||||
@patch("superset.views.base.app")
|
||||
def test_brandspinnerurl_does_not_duplicate_static_assets_prefix(
|
||||
self, mock_app, mock_payload
|
||||
):
|
||||
"""Test that already-prefixed spinner URLs are not prefixed again."""
|
||||
from superset.views.base import get_spa_template_context
|
||||
|
||||
mock_app.config = {
|
||||
"STATIC_ASSETS_PREFIX": "/analytics",
|
||||
}
|
||||
mock_payload.return_value = {
|
||||
"common": {
|
||||
"theme": {
|
||||
"default": {
|
||||
"token": {
|
||||
"brandSpinnerUrl": "/analytics/static/assets/spinner.gif",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = get_spa_template_context("app")
|
||||
|
||||
assert (
|
||||
result["theme_tokens"]["brandSpinnerUrl"]
|
||||
== "/analytics/static/assets/spinner.gif"
|
||||
)
|
||||
|
||||
|
||||
class TestGetDefaultSpinnerSvg:
|
||||
"""Test get_default_spinner_svg function"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user