Copilot commented on code in PR #36062:
URL: https://github.com/apache/superset/pull/36062#discussion_r2519375293


##########
superset/daos/dashboard.py:
##########
@@ -423,6 +423,72 @@ def update_native_filters_config(
 
         return updated_configuration
 
+    @classmethod
+    def update_chart_customizations_config(
+        cls,
+        dashboard: Dashboard | None = None,
+        attributes: dict[str, Any] | None = None,
+    ) -> list[dict[str, Any]]:
+        if not dashboard:
+            raise DashboardUpdateFailedError("Dashboard not found")
+
+        if attributes:
+            metadata = json.loads(dashboard.json_metadata or "{}")

Review Comment:
   The method doesn't handle the case when `attributes` is `None` or empty 
dict. If `attributes` is `None`, the function will return 
`updated_configuration` which is undefined, causing an `UnboundLocalError`. Add 
validation at the start or initialize `updated_configuration = []` before the 
`if attributes:` block.



##########
superset-frontend/src/dataMask/reducer.ts:
##########
@@ -202,19 +245,35 @@ const dataMaskReducer = produce(
               item.customization !== null &&
               'column' in item.customization
             ) {
-              const customizationFilterId = `chart_customization_${(item as { 
id: string }).id}`;
+              const customizationFilterId = (item as { id: string }).id;
+
+              // Only set metadata default if not already loaded from backend
+              const customization = item.customization as {
+                column?: string | string[];
+                defaultDataMask?: { filterState?: { value?: string[] } };
+              };

Review Comment:
   Multiple type assertions with `as` suggest the types are not well-defined. 
Consider defining proper TypeScript interfaces for chart customization items to 
avoid repeated type casting and improve type safety throughout the codebase.



##########
superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx:
##########
@@ -105,11 +112,19 @@ const FilterValue: FC<FilterControlProps> = ({
   validateStatus,
   clearAllTrigger,
   onClearAllComplete,
+  isCustomization = false,
 }) => {
   const { id, targets, filterType, adhoc_filters, time_range } = filter;
   const metadata = getChartMetadataRegistry().get(filterType);
   const dependencies = useFilterDependencies(id, dataMaskSelected);
   const shouldRefresh = useShouldFilterRefresh();
+
+  const behaviors = useMemo(
+    () => [
+      isCustomization ? Behavior.ChartCustomization : Behavior.NativeFilter,
+    ],
+    [isCustomization],
+  );

Review Comment:
   [nitpick] The `behaviors` array should be defined outside the component or 
as a constant map since it has only two possible values. Creating a new array 
on every render (even with useMemo) is unnecessary. Consider: `const behaviors 
= isCustomization ? [Behavior.ChartCustomization] : [Behavior.NativeFilter];`



##########
superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx:
##########
@@ -109,106 +120,88 @@ function FiltersConfigModal({
 }: FiltersConfigModalProps) {
   const dispatch = useDispatch();
   const theme = useTheme();
-
   const [form] = Form.useForm<NativeFiltersForm>();
-
   const configFormRef = useRef<any>();
 
-  // the filter config from redux state, this does not change until modal is 
closed.
   const filterConfig = useFilterConfiguration();
   const filterConfigMap = useFilterConfigMap();
+  const chartCustomizationConfig = useChartCustomizationConfiguration();
+  const chartCustomizationConfigMap = useChartCustomizationConfigMap();
 
-  // this state contains the changes that we'll be sent through the PATCH 
endpoint
-  const [filterChanges, setFilterChanges] = useState<FilterChangesType>(
-    DEFAULT_FILTER_CHANGES,
-  );
-
-  const resetFilterChanges = () => {
-    setFilterChanges(DEFAULT_FILTER_CHANGES);
-  };
-
-  const handleModifyFilter = useCallback(
-    (filterId: string) => {
-      if (!filterChanges.modified.includes(filterId)) {
-        setFilterChanges(prev => ({
-          ...prev,
-          modified: [...prev.modified, filterId],
-        }));
-      }
-    },
-    [filterChanges.modified],
-  );
-
-  // new filter ids belong to filters have been added during
-  // this configuration session, and only exist in the form state until we 
submit.
-  const [newFilterIds, setNewFilterIds] = useState<string[]>(
-    DEFAULT_EMPTY_FILTERS,
-  );
+  const [filterChanges, setFilterChanges] =
+    useState<FilterChangesType>(DEFAULT_CHANGES);
+  const [chartCustomizationChanges, setChartCustomizationChanges] =
+    useState<FilterChangesType>(DEFAULT_CHANGES);
 
-  // store ids of filters that have been removed with the time they were 
removed
-  // so that we can disappear them after a few secs.
-  // filters are still kept in state until form is submitted.
+  const [newFilterIds, setNewFilterIds] =
+    useState<string[]>(DEFAULT_EMPTY_ARRAY);
   const [removedFilters, setRemovedFilters] = useState<
     Record<string, FilterRemoval>
-  >(DEFAULT_REMOVED_FILTERS);
+  >(DEFAULT_REMOVED_ITEMS);
+  const [newChartCustomizationIds, setNewChartCustomizationIds] =
+    useState<string[]>(DEFAULT_EMPTY_ARRAY);
+  const [removedChartCustomizations, setRemovedChartCustomizations] = useState<
+    Record<string, FilterRemoval>
+  >(DEFAULT_REMOVED_ITEMS);
 
   const [saveAlertVisible, setSaveAlertVisible] = useState<boolean>(false);
+  const [formValues, setFormValues] =
+    useState<NativeFiltersForm>(DEFAULT_FORM_VALUES);
+  const [erroredFilters, setErroredFilters] =
+    useState<string[]>(DEFAULT_EMPTY_ARRAY);
+  const [erroredCustomizations, setErroredCustomizations] =
+    useState<string[]>(DEFAULT_EMPTY_ARRAY);
+  const [expanded, setExpanded] = useState(false);
+  const [activeCollapseKeys, setActiveCollapseKeys] = useState<string[]>([
+    'filters',
+    'chartCustomizations',
+  ]);
 
-  // The full ordered set of ((original + new) - completely removed) filter ids
-  // Use this as the canonical list of what filters are being configured!
-  // This includes filter ids that are pending removal, so check for that.
   const filterIds = useMemo(
+    () => uniq([...getFilterIds(filterConfig), ...newFilterIds]),
+    [filterConfig, newFilterIds],
+  );
+
+  const chartCustomizationIds = useMemo(
     () =>
-      uniq([...getFilterIds(filterConfig), ...newFilterIds]).filter(
-        id => !removedFilters[id] || removedFilters[id]?.isPending,
-      ),
-    [filterConfig, newFilterIds, removedFilters],
+      uniq([
+        ...getChartCustomizationIds(chartCustomizationConfig),
+        ...newChartCustomizationIds,
+      ]),
+    [chartCustomizationConfig, newChartCustomizationIds],
   );
 
-  // open the first filter in the list to start
-  const initialCurrentFilterId = initialFilterId ?? filterIds[0];
-  const [currentFilterId, setCurrentFilterId] = useState(
+  const initialCurrentFilterId =
+    initialFilterId ?? filterIds[0] ?? chartCustomizationIds[0] ?? '';
+  const [currentItemId, setCurrentItemId] = useState<string>(
     initialCurrentFilterId,
   );
-  const [erroredFilters, setErroredFilters] = useState<string[]>(
-    DEFAULT_EMPTY_FILTERS,
+  const [renderedFilters, setRenderedFilters] = useState<string[]>(
+    initialCurrentFilterId && isFilterId(initialCurrentFilterId)
+      ? [initialCurrentFilterId]
+      : [],
   );

Review Comment:
   [nitpick] The initialization logic for `renderedFilters` and 
`renderedCustomizations` is duplicated. Consider extracting this into a helper 
function or consolidating the logic to reduce duplication and improve 
maintainability.



-- 
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]

Reply via email to