Open Stanhoucke opened 2 hours ago
Hey there, @Stanhoucke! I'm here to help you with bug fixes, answer your questions, and guide you to become a contributor. Let's tackle this issue together!
I found two similar closed issues that might be relevant to your problem:
To resolve the useFilterScope
TypeError in an embedded dashboard when interacting with filters in Superset version 4.0.2, ensure that the useFilterScope
function is correctly implemented and used. Here is the relevant part of the code:
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { Filter, t } from '@superset-ui/core';
import { Layout, LayoutItem, RootState } from 'src/dashboard/types';
import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
import { CHART_TYPE } from 'src/dashboard/util/componentTypes';
import { useChartIds } from 'src/dashboard/util/charts/useChartIds';
const extractTabLabel = (tab?: LayoutItem) =>
tab?.meta?.text || tab?.meta?.defaultText || '';
const extractChartLabel = (chart?: LayoutItem) =>
chart?.meta?.sliceNameOverride || chart?.meta?.sliceName || chart?.id || '';
export const useFilterScope = (filter: Filter) => {
const layout = useSelector<RootState, Layout>(
state => state.dashboardLayout.present,
);
const chartIds = useChartIds();
return useMemo(() => {
let topLevelTabs: string[] | undefined;
const topElementId = layout[DASHBOARD_ROOT_ID].children[0];
if (topElementId.startsWith('TABS-')) {
topLevelTabs = layout[topElementId].children;
}
if (filter.scope.rootPath.length === 0) {
return undefined;
}
if (
filter.scope.excluded.length === 0 &&
(filter.scope.rootPath[0] === DASHBOARD_ROOT_ID ||
topLevelTabs?.every(topLevelTab =>
filter.scope.rootPath.includes(topLevelTab),
))
) {
return { all: [t('All charts')] };
}
if (filter.scope.excluded.length === 0 && topLevelTabs) {
return {
tabs: filter.scope.rootPath
.map(tabId => extractTabLabel(layout[tabId]))
.filter(Boolean),
};
}
const layoutCharts = Object.values(layout).filter(
layoutElement => layoutElement.type === CHART_TYPE,
);
if (filter.scope.rootPath[0] === DASHBOARD_ROOT_ID) {
return {
charts: chartIds
.filter(chartId => !filter.scope.excluded.includes(chartId))
.map(chartId => {
const layoutElement = layoutCharts.find(
layoutChart => layoutChart.meta.chartId === chartId,
);
return extractChartLabel(layoutElement);
})
.filter(Boolean),
};
}
if (topLevelTabs) {
const topLevelTabsInFullScope = [...filter.scope.rootPath];
const layoutChartElementsInTabsInScope = layoutCharts.filter(element =>
element.parents.some(parent =>
topLevelTabsInFullScope.includes(parent),
),
);
filter.scope.excluded.forEach(chartId => {
const excludedIndex = topLevelTabsInFullScope.findIndex(tabId =>
layoutChartElementsInTabsInScope
.find(chart => chart.meta.chartId === chartId)
?.parents.includes(tabId),
);
if (excludedIndex > -1) {
topLevelTabsInFullScope.splice(excludedIndex, 1);
}
});
const chartsInExcludedTabs = chartIds
.filter(chartId => !filter.scope.excluded.includes(chartId))
.reduce((acc: LayoutItem[], chartId) => {
const layoutChartElementInExcludedTab =
layoutChartElementsInTabsInScope.find(
element =>
element.meta.chartId === chartId &&
element.parents.every(
parent => !topLevelTabsInFullScope.includes(parent),
),
);
if (layoutChartElementInExcludedTab) {
acc.push(layoutChartElementInExcludedTab);
}
return acc;
}, []);
return {
tabs: topLevelTabsInFullScope
.map(tabId => extractTabLabel(layout[tabId]))
.filter(Boolean),
charts: chartsInExcludedTabs.map(extractChartLabel).filter(Boolean),
};
}
return undefined;
}, [chartIds, filter.scope.excluded, filter.scope.rootPath, layout]);
};
Ensure that the useFilterScope
function is correctly used in your component. If you encounter a TypeError, it might be due to incorrect usage or missing dependencies in the context where useFilterScope
is called.
Here is an example of how to use useFilterScope
correctly:
import React from 'react';
import { useFilterScope } from 'path-to-your-state-file';
const MyDashboardComponent = ({ filter }) => {
const filterScope = useFilterScope(filter);
return (
<div>
{/* Render your filters based on the scope */}
{filterScope?.all && <div>All charts are in scope</div>}
{filterScope?.tabs && filterScope.tabs.map(tab => <div key={tab}>{tab}</div>)}
{filterScope?.charts && filterScope.charts.map(chart => <div key={chart}>{chart}</div>)}
</div>
);
};
Additionally, ensure that the filters passed to useFilterScope
are correctly structured and that the necessary state selectors (useSelector
, useChartIds
, etc.) are functioning as expected. You may also want to check the implementation of the ScopeRow
component and related utilities like useTruncation
to ensure they are correctly set up and integrated [1][2][3][4][5].
To continue talking to Dosu, mention @dosu.
Bug description
The bug is that when interacting with the filters in an embedded dashboard, the filters will be replaced with an
Unexpected Error
message. The user is forced to refresh the dashboard, losing the state of their filters prior to the error.Steps to reproduce
Apply Filters
I could not reliably find a way or pattern to trigger this error. It may take a minute or two of selecting, deselecting, updating some filter options before seeing the error.
The browser console displays the following TypeError related to the
useFilterScope
function.Screenshots/recordings
No response
Superset version
4.0.2
Python version
3.10
Node version
16
Browser
Chrome
Additional context
No response
Checklist