You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2026/04/21 05:02:36 UTC
(superset) branch fix-chart-list-user-filter-numeric-id created (now d952109cbcb)
This is an automated email from the ASF dual-hosted git repository.
mistercrunch pushed a change to branch fix-chart-list-user-filter-numeric-id
in repository https://gitbox.apache.org/repos/asf/superset.git
at d952109cbcb fix(list-view): preserve user name in filter pill after navigation
This branch includes the following new commits:
new d952109cbcb fix(list-view): preserve user name in filter pill after navigation
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: fix(list-view): preserve user name in filter pill after navigation
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
mistercrunch pushed a commit to branch fix-chart-list-user-filter-numeric-id
in repository https://gitbox.apache.org/repos/asf/superset.git
commit d952109cbcb149c427c95890e7f427eccb714181
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Tue Apr 21 04:51:48 2026 +0000
fix(list-view): preserve user name in filter pill after navigation
In the Chart list (and other CRUD lists), filtering by a user, navigating
into an asset, and returning to the list replaced the user's name in the
filter pill with a numeric user id.
Root cause: Owner filter options supply a React element as `label` (via
`OwnerSelectLabel`, which renders name + email). When a selection was
serialized to URL / filter state, `SelectFilter.onChange` only accepted
string labels and otherwise fell back to `String(selected.value)` (the
numeric id). On return to the list, the rehydrated `{label, value}` held
the numeric id as the label and that is what the pill rendered.
Prefer the option's plain-text `title` (already set to the human-readable
name by `createFetchOwners`) before falling back to the stringified value.
Add a unit test covering both the ReactNode-with-title path and the
no-title fallback.
---
.../components/ListView/Filters/Select.test.tsx | 123 +++++++++++++++++++++
.../src/components/ListView/Filters/Select.tsx | 9 +-
2 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/superset-frontend/src/components/ListView/Filters/Select.test.tsx b/superset-frontend/src/components/ListView/Filters/Select.test.tsx
new file mode 100644
index 00000000000..09d5d26ab89
--- /dev/null
+++ b/superset-frontend/src/components/ListView/Filters/Select.test.tsx
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { render, selectOption, waitFor } from 'spec/helpers/testing-library';
+import { ListViewFilterOperator } from '../types';
+import UIFilters from './index';
+
+const mockUpdateFilterValue = jest.fn();
+
+beforeEach(() => {
+ mockUpdateFilterValue.mockClear();
+});
+
+test('select filter with ReactNode label uses option title when serializing selection', async () => {
+ // Regression for sc-104554: the chart-list Owner filter renders options
+ // with ReactNode labels (name + email). The value passed to
+ // updateFilterValue is serialized into URL / filter state and re-used to
+ // render the filter pill on return. It must carry the plain-text name
+ // (from `title`) and not fall back to the numeric user id.
+ const ReactNodeLabel = (
+ <div>
+ <span>John Doe</span>
+ <span>john@example.com</span>
+ </div>
+ );
+
+ const fetchSelects = jest.fn().mockResolvedValue({
+ data: [
+ {
+ label: ReactNodeLabel,
+ value: 42,
+ title: 'John Doe',
+ },
+ ],
+ totalCount: 1,
+ });
+
+ const filters = [
+ {
+ Header: 'Owner',
+ key: 'owner',
+ id: 'owners',
+ input: 'select' as const,
+ operator: ListViewFilterOperator.RelationManyMany,
+ unfilteredLabel: 'All',
+ fetchSelects,
+ paginate: true,
+ },
+ ];
+
+ render(
+ <UIFilters
+ filters={filters}
+ internalFilters={[]}
+ updateFilterValue={mockUpdateFilterValue}
+ />,
+ );
+
+ await selectOption('John Doe', 'Owner');
+
+ await waitFor(() => {
+ expect(mockUpdateFilterValue).toHaveBeenCalledWith({
+ label: 'John Doe',
+ value: 42,
+ });
+ });
+});
+
+test('select filter falls back to stringified value when no string label or title is available', async () => {
+ const fetchSelects = jest.fn().mockResolvedValue({
+ data: [
+ {
+ label: <span>123</span>,
+ value: 123,
+ },
+ ],
+ totalCount: 1,
+ });
+
+ const filters = [
+ {
+ Header: 'Something',
+ key: 'something',
+ id: 'something',
+ input: 'select' as const,
+ operator: ListViewFilterOperator.RelationOneMany,
+ unfilteredLabel: 'All',
+ fetchSelects,
+ },
+ ];
+
+ render(
+ <UIFilters
+ filters={filters}
+ internalFilters={[]}
+ updateFilterValue={mockUpdateFilterValue}
+ />,
+ );
+
+ await selectOption('123', 'Something');
+
+ await waitFor(() => {
+ expect(mockUpdateFilterValue).toHaveBeenCalledWith({
+ label: '123',
+ value: 123,
+ });
+ });
+});
diff --git a/superset-frontend/src/components/ListView/Filters/Select.tsx b/superset-frontend/src/components/ListView/Filters/Select.tsx
index 5e38d99bd84..48b7da2debf 100644
--- a/superset-frontend/src/components/ListView/Filters/Select.tsx
+++ b/superset-frontend/src/components/ListView/Filters/Select.tsx
@@ -62,10 +62,17 @@ function SelectFilter(
onSelect(
selected
? {
+ // Options may supply a ReactNode label (e.g. OwnerSelectLabel for
+ // the chart list Owner filter). Since this object is serialized
+ // into the URL and rehydrated as the filter pill on return, we
+ // need a plain string. Prefer `title` (set by callers to the
+ // human-readable name) before falling back to the value.
label:
typeof selected.label === 'string'
? selected.label
- : String(selected.value),
+ : typeof selected.title === 'string'
+ ? selected.title
+ : String(selected.value),
value: selected.value,
}
: undefined,