This is an automated email from the ASF dual-hosted git repository.

hugh pushed a commit to branch hm/ar-filters
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 16751c09c3328eab4970d7c6e8f5e8d1870dc6d8
Author: Hugh Miles <[email protected]>
AuthorDate: Fri Feb 7 00:15:42 2025 +0000

    save
---
 .../src/features/alerts/AlertReportModal.tsx       | 25 ++++++-----
 superset-frontend/src/features/alerts/types.ts     |  7 +++
 superset/commands/dashboard/permalink/create.py    | 19 +++++++-
 superset/commands/explore/get.py                   |  1 +
 superset/commands/report/execute.py                | 31 +++++++++++--
 superset/reports/models.py                         | 52 +++++++++++-----------
 superset/views/core.py                             | 12 ++++-
 7 files changed, 101 insertions(+), 46 deletions(-)

diff --git a/superset-frontend/src/features/alerts/AlertReportModal.tsx 
b/superset-frontend/src/features/alerts/AlertReportModal.tsx
index 5152160b4f..d971847637 100644
--- a/superset-frontend/src/features/alerts/AlertReportModal.tsx
+++ b/superset-frontend/src/features/alerts/AlertReportModal.tsx
@@ -463,6 +463,8 @@ const AlertReportModal: 
FunctionComponent<AlertReportModalProps> = ({
   const [nativeFilter, setSelectedNativeFilter] = useState<object>({});
   const [nativeFilters, setGlobalNativeFilters] = useState<object>({});
 
+  console.log('okkkkk', nativeFilter)
+
   // Validation
   const [validationStatus, setValidationStatus] = useState<ValidationObject>({
     [Sections.General]: {
@@ -676,7 +678,7 @@ const AlertReportModal: 
FunctionComponent<AlertReportModalProps> = ({
 
 
     // todo(hughhh): refactor to handle multiple native filters
-    currentAlert.extra.nativeFilter = nativeFilter
+    currentAlert.extra.dashboard.nativeFilters = [nativeFilter]
 
     const data: any = {
       ...currentAlert,
@@ -1186,14 +1188,14 @@ const AlertReportModal: 
FunctionComponent<AlertReportModalProps> = ({
     setForceScreenshot(event.target.checked);
   };
 
-  const onChangeDashboardFilter = (value: any) => {
-    console.log('dashboardFilter', value);
+  const onChangeDashboardFilter = (nativeFilterId: string) => {
+    console.log('dashboardFilter', nativeFilterId);
     // set dashboardFilter
     const anchor = currentAlert?.extra?.dashboard?.anchor
     const inScopeFilters = nativeFilters[anchor];
-    const filter = inScopeFilters.filter((f: any) => f.id === value)[0]
+    const filter = inScopeFilters.filter((f: any) => f.id === 
nativeFilterId)[0]
     console.log(filter) // use filter to grab values from API
-    console.log('about to get filter values', value);
+    console.log('about to get filter values', nativeFilterId);
     
     const datasetId = filter.targets[0].datasetId;
     const columnName = filter.targets[0].column.name;
@@ -1227,19 +1229,18 @@ const AlertReportModal: 
FunctionComponent<AlertReportModalProps> = ({
       force: false,
       ownState: {}
     }
-    
+    setSelectedNativeFilter({...nativeFilter, columnName, nativeFilterId})
     getChartDataRequest(filterValues).then(response => {
       setNativeFilterValues(response.json.result[0].data.map((item: any) => 
({value: item[columnName], label: item[columnName]})))
     });
-
   }
 
-  const onChangeDashboardFilterValue = (value: any) => {
-    console.log('dashboardValue', value);
-    // set dashboardValue
-    setSelectedNativeFilter({...nativeFilter, nativeFilterValue: value});
+  const onChangeDashboardFilterValue = (filterValue: any) => {
+    console.log('dashboardValue', filterValue);
 
-    
+    // todo(hughhh): refactor to handle multiple native filters 
+    // once you have multiselect
+    setSelectedNativeFilter({...nativeFilter, filterValues: [filterValue]});
   }
 
   // Make sure notification settings has the required info
diff --git a/superset-frontend/src/features/alerts/types.ts 
b/superset-frontend/src/features/alerts/types.ts
index 06449697c3..3b00067a48 100644
--- a/superset-frontend/src/features/alerts/types.ts
+++ b/superset-frontend/src/features/alerts/types.ts
@@ -94,8 +94,15 @@ export type DashboardState = {
   anchor?: string;
 };
 
+export type ExtraNativeFilter = {
+  columnName?: string;
+  filterValues?: Array<any>;
+  // filterOp?: string; // assuming all operators are 'IN' for now
+};
+
 export type Extra = {
   dashboard?: DashboardState;
+  nativeFilters?: Array<ExtraNativeFilter>;
 };
 
 export type Operator = '<' | '>' | '<=' | '>=' | '==' | '!=' | 'not null';
diff --git a/superset/commands/dashboard/permalink/create.py 
b/superset/commands/dashboard/permalink/create.py
index 20bc5118f5..7bd91f8640 100644
--- a/superset/commands/dashboard/permalink/create.py
+++ b/superset/commands/dashboard/permalink/create.py
@@ -66,11 +66,21 @@ class 
CreateDashboardPermalinkCommand(BaseDashboardPermalinkCommand):
     def run(self) -> str:
         self.validate()
         dashboard = DashboardDAO.get_by_id_or_slug(self.dashboard_id)
+        print("creating permalink...")
+        
         value = {
             "dashboardId": str(dashboard.uuid),
-            "state": self.state,
+            "state": {**self.state, "urlParams": [['native_filter', 
'(NATIVE_FILTER-8jS1fx4hl:(extraFormData:(filters:!((col:country_name,op:IN,val:!(Brazil)))),filterState:(label:country_name,validateStatus:!f,value:!(Brazil)),id:NATIVE_FILTER-8jS1fx4hl,ownState:()))']]},
         }
         user_id = get_user_id()
+        
+        print('.' * 10)
+        print(self.resource)
+        print(user_id)
+        print(value)
+        print(self.codec)   
+        print('.' * 10)
+        
         entry = KeyValueDAO.upsert_entry(
             resource=self.resource,
             key=get_deterministic_uuid(self.salt, (user_id, value)),
@@ -79,7 +89,12 @@ class 
CreateDashboardPermalinkCommand(BaseDashboardPermalinkCommand):
         )
         db.session.flush()
         assert entry.id  # for type checks
-        return encode_permalink_key(key=entry.id, salt=self.salt)
+        
+        hash = encode_permalink_key(key=entry.id, salt=self.salt)
+        print("permalink created")
+        print(hash)
+        
+        return hash
 
     def validate(self) -> None:
         pass
diff --git a/superset/commands/explore/get.py b/superset/commands/explore/get.py
index dc600bbf97..d32b910137 100644
--- a/superset/commands/explore/get.py
+++ b/superset/commands/explore/get.py
@@ -69,6 +69,7 @@ class GetExploreCommand(BaseCommand, ABC):
             state = permalink_value["state"]
             initial_form_data = state["formData"]
             url_params = state.get("urlParams")
+            print('perm_url_params', url_params)
             if url_params:
                 initial_form_data["url_params"] = dict(url_params)
         elif self._form_data_key:
diff --git a/superset/commands/report/execute.py 
b/superset/commands/report/execute.py
index 4345a7160b..493d0a64f1 100644
--- a/superset/commands/report/execute.py
+++ b/superset/commands/report/execute.py
@@ -228,16 +228,27 @@ class BaseReportState:
         Retrieve the URL for the dashboard tabs, or return the dashboard URL 
if no tabs are available.
         """  # noqa: E501
         force = "true" if self._report_schedule.force_screenshot else "false"
+
+        
         if (
             dashboard_state := self._report_schedule.extra.get("dashboard")
         ) and feature_flag_manager.is_feature_enabled("ALERT_REPORT_TABS"):
             if anchor := dashboard_state.get("anchor"):
                 try:
                     anchor_list: list[str] = json.loads(anchor)
-                    return self._get_tabs_urls(anchor_list, 
user_friendly=user_friendly)
+                    urls = self._get_tabs_urls(anchor_list, 
user_friendly=user_friendly)
+                    return urls
                 except json.JSONDecodeError:
                     logger.debug("Anchor value is not a list, Fall back to 
single tab")
-            return [self._get_tab_url(dashboard_state)]
+
+            print('returning single tab url....')
+            native_filter_params = 
self._report_schedule.get_native_filters_params()
+            return [self._get_tab_url({
+                'anchor': anchor, 
+                'urlParams': {'native_filters': native_filter_params}, 
+                'dataMask': None,
+                'activeTabs': None}, 
+                user_friendly=user_friendly)]
 
         dashboard = self._report_schedule.dashboard
         dashboard_id_or_slug = (
@@ -260,10 +271,13 @@ class BaseReportState:
         """
         Get one tab url
         """
+        print('in single tab....')
+        print(dashboard_state)
         permalink_key = CreateDashboardPermalinkCommand(
             dashboard_id=str(self._report_schedule.dashboard.uuid),
             state=dashboard_state,
         ).run()
+        
         return get_url_path(
             "Superset.dashboard_permalink",
             key=permalink_key,
@@ -271,18 +285,21 @@ class BaseReportState:
         )
 
     def _get_tabs_urls(
-        self, tab_anchors: list[str], user_friendly: bool = False
+        self, 
+        tab_anchors: list[str],
+        user_friendly: bool = False
     ) -> list[str]:
         """
         Get multple tabs urls
         """
+        print('hello5')
         return [
             self._get_tab_url(
                 {
                     "anchor": tab_anchor,
                     "dataMask": None,
                     "activeTabs": None,
-                    "urlParams": None, # could potentially back the 
native_filters here?
+                    "urlParams": url_params,
                 },
                 user_friendly=user_friendly,
             )
@@ -320,6 +337,7 @@ class BaseReportState:
             ]
         else:
             urls = self.get_dashboard_urls()
+            print('urls', urls)
 
             window_width, window_height = 
app.config["WEBDRIVER_WINDOW"]["dashboard"]
             width = min(max_width, self._report_schedule.custom_width or 
window_width)
@@ -481,6 +499,11 @@ class BaseReportState:
         error_text = None
         header_data = self._get_log_data()
         url = self._get_url(user_friendly=True)
+
+        print("*"*100)
+        print(url)
+        print("*"*100)
+
         if (
             feature_flag_manager.is_feature_enabled("ALERTS_ATTACH_REPORTS")
             or self._report_schedule.type == ReportScheduleType.REPORT
diff --git a/superset/reports/models.py b/superset/reports/models.py
index 932c4d6077..063e8d6b6c 100644
--- a/superset/reports/models.py
+++ b/superset/reports/models.py
@@ -186,36 +186,36 @@ class ReportSchedule(AuditMixinNullable, ExtraJSONMixin, 
Model):
     def crontab_humanized(self) -> str:
         return get_description(self.crontab)
     
-    def get_native_filters_params(self) -> Optional[str]:
+    def get_native_filters_params(self) -> Optional[dict[str, any]]:
         params = None
-        if self.extra and self.extra.get("native_filters"):
-            filter = self.extra.get("native_filters", {})
-            params = self._generate_native_filter(filter.get("id"), 
filter.get("column"), filter.get("value"))
-        return prison.dumps(params)
+        dashboard = self.extra.get('dashboard')
+        if dashboard and dashboard.get("nativeFilters"):
+            for filter in dashboard.get("nativeFilters", []):
+                # todo(hugh): handle multiple nativeFilters + multi values
+                params = 
self._generate_native_filter(filter.get("nativeFilterId"), 
filter.get("columnName"), filter.get("filterValues")[0])
+        return params
     
-    def _generate_native_filter(native_filter_id: str, column: str, value: 
str) -> dict:
+    def _generate_native_filter(self, native_filter_id: str, column_name: str, 
value: str) -> dict:
         return { 
-            "native_filters": {
-                native_filter_id: {
-                    "id": native_filter_id,
-                    "extraFormData": {
-                        "filters": [
-                            {
-                                "col": column,
-                                "op": "IN",
-                                "val": [value]
-                            }
-                        ]
-                    },
-                    "filterState": {
-                        "label": column, # pretty name but still works without 
this value
-                        "validateStatus": False,
-                        "value": [value]
-                    },
-                    "ownState": {}
-                }
+            native_filter_id: {
+                "id": native_filter_id,
+                "extraFormData": {
+                    "filters": [
+                        {
+                            "col": column_name,
+                            "op": "IN",
+                            "val": [value]
+                        }
+                    ]
+                },
+                "filterState": {
+                    "label": column_name, # pretty name but still works 
without this value
+                    "validateStatus": False,
+                    "value": [value]
+                },
+                "ownState": {}
             }
-        }        
+        }    
 
 
 class ReportRecipients(Model, AuditMixinNullable):
diff --git a/superset/views/core.py b/superset/views/core.py
index 8a56befe0b..f31bba4a2b 100755
--- a/superset/views/core.py
+++ b/superset/views/core.py
@@ -19,6 +19,7 @@ from __future__ import annotations
 
 import contextlib
 import logging
+import prison
 from datetime import datetime
 from typing import Any, Callable, cast
 from urllib import parse
@@ -846,15 +847,22 @@ class Superset(BaseSupersetView):
             return redirect("/dashboard/list/")
         if not value:
             return json_error_response(_("permalink state not found"), 
status=404)
+        
+        print('value___', value)
         dashboard_id, state = value["dashboardId"], value.get("state", {})
         url = f"/superset/dashboard/{dashboard_id}?permalink_key={key}"
         if url_params := state.get("urlParams"):
-            params = parse.urlencode(url_params)
-            url = f"{url}&{params}"
+            for param_key, param_val in url_params:
+                if param_key == "native_filter":
+                    url = f"{url}&native_filters={param_val}"
+                else:
+                    params = parse.urlencode([param_key, param_val])
+                    url = f"{url}&{params}"
         if original_params := request.query_string.decode():
             url = f"{url}&{original_params}"
         if hash_ := state.get("anchor", state.get("hash")):
             url = f"{url}#{hash_}"
+        
         return redirect(url)
 
     @api

Reply via email to