ypandey-fluidata commented on issue #37069:
URL: https://github.com/apache/superset/issues/37069#issuecomment-3742440212
I implemented the above code in index.tsx with the corrected function --
#index.tsx
/*
import {
FC,
memo,
useEffect,
useState,
useCallback,
useRef,
useMemo,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
DataMaskStateWithId,
DataMaskWithId,
Filter,
DataMask,
isNativeFilter,
usePrevious,
styled,
} from '@superset-ui/core';
import { Constants } from '@superset-ui/core/components';
import { useHistory } from 'react-router-dom';
import { updateDataMask } from 'src/dataMask/actions';
import { useImmer } from 'use-immer';
import { isEmpty, isEqual, debounce } from 'lodash';
import { getInitialDataMask } from 'src/dataMask/reducer';
import { URL_PARAMS } from 'src/constants';
import { applicationRoot } from 'src/utils/getBootstrapData';
import { getUrlParam } from 'src/utils/urlUtils';
import { useTabId } from 'src/hooks/useTabId';
import { logEvent } from 'src/logger/actions';
import { LOG_ACTIONS_CHANGE_DASHBOARD_FILTER } from 'src/logger/LogUtils';
import { FilterBarOrientation, RootState } from 'src/dashboard/types';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
import { checkIsApplyDisabled } from './utils';
import { FiltersBarProps } from './types';
import {
useNativeFiltersDataMask,
useFilters,
useFilterUpdates,
useInitialization,
} from './state';
import { createFilterKey, updateFilterKey } from './keyValue';
import ActionButtons from './ActionButtons';
import Horizontal from './Horizontal';
import Vertical from './Vertical';
import { useSelectFiltersInScope } from '../state';
// FilterBar is just being hidden as it must still
// render fully due to encapsulated logics
const HiddenFilterBar = styled.div`
display: none;
`;
const EXCLUDED_URL_PARAMS: string[] = [
URL_PARAMS.nativeFilters.name,
URL_PARAMS.permalinkKey.name,
];
const publishDataMask = debounce(
async (
history,
dashboardId,
updateKey,
dataMaskSelected: DataMaskStateWithId,
tabId,
) => {
const { location } = history;
const { search } = location;
const previousParams = new URLSearchParams(search);
const newParams = new URLSearchParams();
let dataMaskKey: string | null;
previousParams.forEach((value, key) => {
if (!EXCLUDED_URL_PARAMS.includes(key)) {
newParams.append(key, value);
}
});
const nativeFiltersCacheKey = getUrlParam(URL_PARAMS.nativeFiltersKey);
const dataMask = JSON.stringify(dataMaskSelected);
if (
updateKey &&
nativeFiltersCacheKey &&
(await updateFilterKey(
dashboardId,
dataMask,
nativeFiltersCacheKey,
tabId,
))
) {
dataMaskKey = nativeFiltersCacheKey;
} else {
dataMaskKey = await createFilterKey(dashboardId, dataMask, tabId);
}
if (dataMaskKey) {
newParams.set(URL_PARAMS.nativeFiltersKey.name, dataMaskKey);
}
// pathname could be updated somewhere else through window.history
// keep react router history in sync with window history
// replace params only when current page is /superset/dashboard
// this prevents a race condition between updating filters and
navigating to Explore
if (window.location.pathname.includes('/superset/dashboard')) {
// The history API is part of React router and understands that a
basename may exist.
// Internally it treats all paths as if they are relative to the root
and appends
// it when necessary. We strip any prefix so that history.replace adds
it back and doesn't
// double it up.
const appRoot = applicationRoot();
let replacement_pathname = window.location.pathname;
if (appRoot !== '/' && replacement_pathname.startsWith(appRoot)) {
replacement_pathname =
replacement_pathname.substring(appRoot.length);
}
history.location.pathname = replacement_pathname;
history.replace({
search: newParams.toString(),
});
}
},
Constants.SLOW_DEBOUNCE,
);
const FilterBar: FC<FiltersBarProps> = ({
orientation = FilterBarOrientation.Vertical,
verticalConfig,
hidden = false,
}) => {
const history = useHistory();
const dataMaskApplied: DataMaskStateWithId = useNativeFiltersDataMask();
const [dataMaskSelected, setDataMaskSelected] =
useImmer<DataMaskStateWithId>(dataMaskApplied);
const dispatch = useDispatch();
const [updateKey, setUpdateKey] = useState(0);
const tabId = useTabId();
const filters = useFilters();
const previousFilters = usePrevious(filters);
const filterValues = useMemo(() => Object.values(filters), [filters]);
const nativeFilterValues = useMemo(
() => filterValues.filter(isNativeFilter),
[filterValues],
);
const dashboardId = useSelector<any, number>(
({ dashboardInfo }) => dashboardInfo?.id,
);
const previousDashboardId = usePrevious(dashboardId);
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);
const user: UserWithPermissionsAndRoles = useSelector<
RootState,
UserWithPermissionsAndRoles
>(state => state.user);
const [filtersInScope] = useSelectFiltersInScope(nativeFilterValues);
const [clearAllTriggers, setClearAllTriggers] = useState<
Record<string, boolean>
>({});
const [initializedFilters, setInitializedFilters] = useState<Set<string>>(
new Set(),
);
const dataMaskSelectedRef = useRef(dataMaskSelected);
dataMaskSelectedRef.current = dataMaskSelected;
const handleFilterSelectionChange = useCallback(
(
filter: Pick<Filter, 'id'> & Partial<Filter>,
dataMask: Partial<DataMask>,
) => {
setDataMaskSelected(draft => {
const isFirstTimeInitialization =
!initializedFilters.has(filter.id) &&
dataMaskSelectedRef.current[filter.id]?.filterState?.value ===
undefined;
// force instant updating on initialization for filters with
`requiredFirst` is true or instant filters
if (
// filterState.value === undefined - means that value not
initialized
dataMask.filterState?.value !== undefined &&
isFirstTimeInitialization &&
filter.requiredFirst
) {
dispatch(updateDataMask(filter.id, dataMask));
}
// Mark filter as initialized after getting its first value
if (
dataMask.filterState?.value !== undefined &&
!initializedFilters.has(filter.id)
) {
setInitializedFilters(prev => new Set(prev).add(filter.id));
}
const baseDataMask = {
...(getInitialDataMask(filter.id) as DataMaskWithId),
...dataMask,
};
// Recalculate validation status
const hasRequiredValue =
filter.controlValues?.enableEmptyFilter &&
baseDataMask.filterState?.value == null;
draft[filter.id] = {
...baseDataMask,
filterState: {
...baseDataMask.filterState,
validateStatus: hasRequiredValue ? 'error' : undefined,
},
};
});
},
[dispatch, setDataMaskSelected, initializedFilters,
setInitializedFilters],
);
useEffect(() => {
if (previousFilters && dashboardId === previousDashboardId) {
const updates: Record<string, DataMaskWithId> = {};
Object.values(filters).forEach(currentFilter => {
const previousFilter = previousFilters?.[currentFilter.id];
if (!previousFilter) {
return;
}
const currentType = currentFilter.filterType;
const currentTargets = currentFilter.targets;
const currentDataMask = currentFilter.defaultDataMask;
const previousType = previousFilter?.filterType;
const previousTargets = previousFilter?.targets;
const previousDataMask = previousFilter?.defaultDataMask;
const typeChanged = currentType !== previousType;
const targetsChanged = !isEqual(currentTargets, previousTargets);
const dataMaskChanged = !isEqual(currentDataMask, previousDataMask);
if (typeChanged || targetsChanged || dataMaskChanged) {
updates[currentFilter.id] = getInitialDataMask(
currentFilter.id,
) as DataMaskWithId;
}
});
if (!isEmpty(updates)) {
setDataMaskSelected(draft => ({ ...draft, ...updates }));
}
}
}, [dashboardId, filters, previousDashboardId, setDataMaskSelected]);
const dataMaskAppliedText = JSON.stringify(dataMaskApplied);
useEffect(() => {
setDataMaskSelected(() => dataMaskApplied);
}, [dataMaskAppliedText, setDataMaskSelected]);
useEffect(() => {
// embedded users can't persist filter combinations
if (user?.userId) {
publishDataMask(history, dashboardId, updateKey, dataMaskApplied,
tabId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dashboardId, dataMaskAppliedText, history, updateKey, tabId]);
const handleApply = useCallback(() => {
dispatch(logEvent(LOG_ACTIONS_CHANGE_DASHBOARD_FILTER, {}));
const filterIds = Object.keys(dataMaskSelected);
setUpdateKey(1);
filterIds.forEach(filterId => {
if (dataMaskSelected[filterId]) {
dispatch(updateDataMask(filterId, dataMaskSelected[filterId]));
}
});
}, [dataMaskSelected, dispatch]);
const handleClearAll = useCallback(() => {
dispatch(logEvent(LOG_ACTIONS_CHANGE_DASHBOARD_FILTER, {}));
setUpdateKey(1);
const newClearAllTriggers = { ...clearAllTriggers };
const updates = {};
nativeFilterValues.forEach(filter => {
const { id } = filter;
if (dataMaskSelected[id]) {
updates[id] = {
...dataMaskSelected[id],
filterState: {
...dataMaskSelected[id].filterState,
value: null,
},
extraFormData: {},
};
newClearAllTriggers[id] = true;
}
});
setDataMaskSelected(draft => {
Object.entries(updates).forEach(([id, mask]) => {
draft[id] = mask;
});
});
Object.entries(updates).forEach(([id, mask]) => {
dispatch(updateDataMask(id, mask));
});
setClearAllTriggers(newClearAllTriggers);
}, [dataMaskSelected, nativeFilterValues, setDataMaskSelected,
clearAllTriggers, dispatch]);
const handleClearAllComplete = useCallback((filterId: string) => {
setClearAllTriggers(prev => {
const newTriggers = { ...prev };
delete newTriggers[filterId];
return newTriggers;
});
}, []);
useFilterUpdates(dataMaskSelected, setDataMaskSelected);
const isApplyDisabled = checkIsApplyDisabled(
dataMaskSelected,
dataMaskApplied,
filtersInScope.filter(isNativeFilter),
);
const isInitialized = useInitialization();
const actions = useMemo(
() => (
<ActionButtons
filterBarOrientation={orientation}
width={verticalConfig?.width}
onApply={handleApply}
onClearAll={handleClearAll}
dataMaskSelected={dataMaskSelected}
dataMaskApplied={dataMaskApplied}
isApplyDisabled={isApplyDisabled}
/>
),
[
orientation,
verticalConfig?.width,
handleApply,
handleClearAll,
dataMaskSelected,
dataMaskAppliedText,
isApplyDisabled,
],
);
const filterBarComponent =
orientation === FilterBarOrientation.Horizontal ? (
<Horizontal
actions={actions}
canEdit={canEdit}
dashboardId={dashboardId}
dataMaskSelected={dataMaskSelected}
filterValues={filterValues}
isInitialized={isInitialized}
onSelectionChange={handleFilterSelectionChange}
clearAllTriggers={clearAllTriggers}
onClearAllComplete={handleClearAllComplete}
/>
) : verticalConfig ? (
<Vertical
actions={actions}
canEdit={canEdit}
dataMaskSelected={dataMaskSelected}
filtersOpen={verticalConfig.filtersOpen}
filterValues={filterValues}
isInitialized={isInitialized}
height={verticalConfig.height}
offset={verticalConfig.offset}
onSelectionChange={handleFilterSelectionChange}
toggleFiltersBar={verticalConfig.toggleFiltersBar}
width={verticalConfig.width}
clearAllTriggers={clearAllTriggers}
onClearAllComplete={handleClearAllComplete}
/>
) : null;
return hidden ? (
<HiddenFilterBar>{filterBarComponent}</HiddenFilterBar>
) : (
filterBarComponent
);
};
export default memo(FilterBar);
*/
then in my Dockerfile i added this--
# -----------------------------------------------------
COPY frontend_overrides/native_filters/index.tsx \
src/dashboard/components/nativeFilters/FilterBar/index.tsx
then i run this command to rebuilt the image-- DOCKER_BUILDKIT=0 docker
compose -f docker-compose-test.yml build --no-cache
ERROR in ./src/dashboard/components/nativeFilters/FilterBar/index.tsx:298:7
TS7053: Element implicitly has an 'any' type because expression of type
'string' can't be used to index type '{}'.
No index signature with a parameter of type 'string' was found on type
'{}'.
296 | const { id } = filter;
297 | if (dataMaskSelected[id]) {
> 298 | updates[id] = {
| ^^^^^^^^^^^
299 | ...dataMaskSelected[id],
300 | filterState: {
301 | ...dataMaskSelected[id].filterState,
ERROR in ./src/dashboard/components/nativeFilters/FilterBar/index.tsx:312:7
TS2322: Type 'unknown' is not assignable to type
'WritableDraft<DataMaskWithId>'.
310 | setDataMaskSelected(draft => {
311 | Object.entries(updates).forEach(([id, mask]) => {
> 312 | draft[id] = mask;
| ^^^^^^^^^
313 | });
314 | });
315 |
ERROR in ./src/dashboard/components/nativeFilters/FilterBar/index.tsx:317:33
TS2345: Argument of type 'unknown' is not assignable to parameter of type
'DataMask'.
315 |
316 | Object.entries(updates).forEach(([id, mask]) => {
> 317 | dispatch(updateDataMask(id, mask));
| ^^^^
318 | });
319 |
320 | setClearAllTriggers(newClearAllTriggers);
[+] Building 0/1
таз Service superset_test Building
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]