Compare commits

...

4 Commits

Author SHA1 Message Date
Elizabeth Thompson
7c00f5567f fix(filters): preserve backend metric-based sorting in select filters (#35130)
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-13 13:34:54 +03:00
Elizabeth Thompson
76c5b40c13 fix(embedded): fix template context for embedded views
- Use render_app_template() in EmbeddedView to provide proper template context
- Move tokens variable definition before its usage in spa.html template
- Fixes 'tokens is undefined' error in embedded dashboard views

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 18:03:23 -07:00
Elizabeth Thompson
9617b8b392 fix(modals): make Modal.confirm dialogs respect theme mode
- Add App wrapper to SupersetThemeProvider to enable theme inheritance for imperative modals
- Modal.confirm dialogs now properly inherit dark/light theme from ConfigProvider
- Simplifies theming approach by leveraging antd's built-in App context

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 17:56:32 -07:00
Elizabeth Thompson
a7b180d8dd fix(filters): remove filter bar gap, fix loading screen theming, fix filter sorting, and fix modal theming
- Remove top padding from horizontal filter bar to eliminate visual gap
- Set themed background color on loading screen to respect dark mode
- Remove fallback "Loading..." text to prevent Times New Roman display
- Use colorBgBase theme token for proper light/dark mode support
- Fix filter value sorting to preserve backend metric-based order when sortMetric is specified
- Make Modal.confirm theme-aware to respect current light/dark mode

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 17:18:53 -07:00
6 changed files with 23 additions and 20 deletions

View File

@@ -368,9 +368,13 @@ const CustomModal = ({
}; };
CustomModal.displayName = 'Modal'; CustomModal.displayName = 'Modal';
// Theme-aware confirmation modal - now inherits theme through App wrapper in SupersetThemeProvider
const themedConfirm = (props: Parameters<typeof AntdModal.confirm>[0]) =>
AntdModal.confirm(props);
export const Modal = Object.assign(CustomModal, { export const Modal = Object.assign(CustomModal, {
error: AntdModal.error, error: AntdModal.error,
warning: AntdModal.warning, warning: AntdModal.warning,
confirm: AntdModal.confirm, confirm: themedConfirm,
useModal: AntdModal.useModal, useModal: AntdModal.useModal,
}); });

View File

@@ -19,7 +19,7 @@
/* eslint-disable react-prefer-function-component/react-prefer-function-component */ /* eslint-disable react-prefer-function-component/react-prefer-function-component */
// eslint-disable-next-line no-restricted-syntax // eslint-disable-next-line no-restricted-syntax
import React from 'react'; import React from 'react';
import { theme as antdThemeImport, ConfigProvider } from 'antd'; import { theme as antdThemeImport, ConfigProvider, App } from 'antd';
// @fontsource/* v5.1+ doesn't play nice with eslint-import plugin v2.31+ // @fontsource/* v5.1+ doesn't play nice with eslint-import plugin v2.31+
/* eslint-disable import/extensions */ /* eslint-disable import/extensions */
@@ -243,7 +243,7 @@ export class Theme {
<ThemeProvider theme={themeState.theme}> <ThemeProvider theme={themeState.theme}>
<GlobalStyles /> <GlobalStyles />
<ConfigProvider theme={themeState.antdConfig}> <ConfigProvider theme={themeState.antdConfig}>
{children} <App>{children}</App>
</ConfigProvider> </ConfigProvider>
</ThemeProvider> </ThemeProvider>
</EmotionCacheProvider> </EmotionCacheProvider>

View File

@@ -32,7 +32,7 @@ import crossFiltersSelector from './CrossFilters/selectors';
const HorizontalBar = styled.div` const HorizontalBar = styled.div`
${({ theme }) => ` ${({ theme }) => `
padding: ${theme.sizeUnit * 3}px ${theme.sizeUnit * 2}px ${ padding: 0 ${theme.sizeUnit * 2}px ${
theme.sizeUnit * 3 theme.sizeUnit * 3
}px ${theme.sizeUnit * 4}px; }px ${theme.sizeUnit * 4}px;
background: ${theme.colorBgBase}; background: ${theme.colorBgBase};

View File

@@ -317,13 +317,20 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
const sortComparator = useCallback( const sortComparator = useCallback(
(a: LabeledValue, b: LabeledValue) => { (a: LabeledValue, b: LabeledValue) => {
// When sortMetric is specified, the backend already sorted the data correctly
// Don't override the backend's metric-based sorting with frontend alphabetical sorting
if (formData.sortMetric) {
return 0; // Preserve the original order from the backend
}
// Only apply alphabetical sorting when no sortMetric is specified
const labelComparator = propertyComparator('label'); const labelComparator = propertyComparator('label');
if (formData.sortAscending) { if (formData.sortAscending) {
return labelComparator(a, b); return labelComparator(a, b);
} }
return labelComparator(b, a); return labelComparator(b, a);
}, },
[formData.sortAscending], [formData.sortAscending, formData.sortMetric],
); );
// Use effect for initialisation for filter plugin // Use effect for initialisation for filter plugin

View File

@@ -24,7 +24,6 @@ from flask_wtf.csrf import same_origin
from superset import event_logger, is_feature_enabled from superset import event_logger, is_feature_enabled
from superset.daos.dashboard import EmbeddedDashboardDAO from superset.daos.dashboard import EmbeddedDashboardDAO
from superset.superset_typing import FlaskResponse from superset.superset_typing import FlaskResponse
from superset.utils import json
from superset.views.base import BaseSupersetView, common_bootstrap_payload from superset.views.base import BaseSupersetView, common_bootstrap_payload
@@ -76,7 +75,7 @@ class EmbeddedView(BaseSupersetView):
dashboard_version="v2", dashboard_version="v2",
) )
bootstrap_data = { extra_bootstrap_data = {
"config": { "config": {
"GUEST_TOKEN_HEADER_NAME": current_app.config["GUEST_TOKEN_HEADER_NAME"] "GUEST_TOKEN_HEADER_NAME": current_app.config["GUEST_TOKEN_HEADER_NAME"]
}, },
@@ -86,10 +85,7 @@ class EmbeddedView(BaseSupersetView):
}, },
} }
return self.render_template( return self.render_app_template(
"superset/spa.html", extra_bootstrap_data=extra_bootstrap_data,
entry="embedded", entry="embedded",
bootstrap_data=json.dumps(
bootstrap_data, default=json.pessimistic_json_iso_dttm_ser
),
) )

View File

@@ -69,11 +69,11 @@
{% endblock %} {% endblock %}
</head> </head>
<body {% if standalone_mode %}class="standalone"{% endif %}> {% set tokens = theme_tokens | default({}) %}
<body {% if standalone_mode %}class="standalone"{% endif %} style="margin: 0; padding: 0; background-color: {{ tokens.get('colorBgBase', '#ffffff') }};">
{% block body %} {% block body %}
<div id="app" data-bootstrap="{{ bootstrap_data }}"> <div id="app" data-bootstrap="{{ bootstrap_data }}">
{% set tokens = theme_tokens | default({}) %}
{% set spinner_style = "width: 70px; height: auto; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);" %} {% set spinner_style = "width: 70px; height: auto; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);" %}
{% if spinner_svg %} {% if spinner_svg %}
@@ -85,14 +85,10 @@
<!-- Custom URL from theme --> <!-- Custom URL from theme -->
<img <img
src="{{ tokens.brandSpinnerUrl }}" src="{{ tokens.brandSpinnerUrl }}"
alt="Loading..." alt=""
style="{{ spinner_style }}" style="{{ spinner_style }}"
/> />
{% else %} {# Remove fallback text - let React app handle loading state #}
<!-- Fallback: This should rarely happen with new logic -->
<div style="{{ spinner_style }}">
Loading...
</div>
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}