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 ef0a7ee4ef694cb123f182f732121f33846c8fe1
Merge: 25d2850a0c 9e5876dc17
Author: Hugh Miles <[email protected]>
AuthorDate: Mon Feb 3 16:49:33 2025 +0100

    Merge branch 'master' of https://github.com/apache/superset into 
hm/ar-filters

 docs/docs/configuration/databases.mdx              |  18 +
 pyproject.toml                                     |   1 +
 superset-frontend/package-lock.json                |  28 ++
 superset-frontend/package.json                     |   2 +
 .../superset-ui-core/src/ui-overrides/types.ts     |  11 +
 superset-frontend/src/GlobalStyles.tsx             |   3 +-
 superset-frontend/src/SqlLab/actions/sqlLab.js     |  40 +-
 .../src/SqlLab/actions/sqlLab.test.js              |  70 +++-
 .../AceEditorWrapper/AceEditorWrapper.test.tsx     |  19 +-
 .../AceEditorWrapper/useKeywords.test.ts           |   2 +
 .../src/SqlLab/components/App/index.tsx            |   2 +-
 .../SqlLab/components/ResultSet/ResultSet.test.tsx |  10 +-
 .../SqlLab/components/SaveDatasetModal/index.tsx   |   4 +-
 .../src/SqlLab/components/ShowSQL/index.tsx        |  12 +-
 .../SqlLab/components/SouthPane/SouthPane.test.tsx |   6 +-
 .../src/SqlLab/components/SouthPane/index.tsx      |  95 +++--
 .../SqlEditorLeftBar/SqlEditorLeftBar.test.tsx     |  63 ++-
 .../SqlLab/components/SqlEditorLeftBar/index.tsx   |  11 +-
 .../components/TableElement/TableElement.test.tsx  |  10 +-
 .../components/TablePreview/TablePreview.test.tsx  | 173 +++++++++
 .../src/SqlLab/components/TablePreview/index.tsx   | 430 +++++++++++++++++++++
 superset-frontend/src/SqlLab/fixtures.ts           |   5 +-
 .../src/SqlLab/reducers/getInitialState.test.ts    |  10 +-
 .../src/SqlLab/reducers/getInitialState.ts         |   7 +-
 superset-frontend/src/SqlLab/reducers/sqlLab.js    |  50 ++-
 superset-frontend/src/SqlLab/types.ts              |   2 +-
 .../Chart/DrillBy/useDisplayModeToggle.tsx         |  28 +-
 .../FilterableTable/FilterableTable.test.tsx       |  33 +-
 .../src/components/FilterableTable/index.tsx       | 251 ++++--------
 .../src/components/GridTable/GridTable.test.tsx    |  66 ++++
 .../src/components/GridTable/Header.test.tsx       | 109 ++++++
 .../src/components/GridTable/Header.tsx            | 200 ++++++++++
 .../src/components/GridTable/HeaderMenu.test.tsx   | 266 +++++++++++++
 .../src/components/GridTable/HeaderMenu.tsx        | 247 ++++++++++++
 .../Radio.stories.tsx => GridTable/constants.ts}   |  41 +-
 .../src/components/GridTable/index.tsx             | 241 ++++++++++++
 .../src/components/Icons/AntdEnhanced.tsx          |  16 +
 .../src/components/Radio/Radio.stories.tsx         | 149 +++++--
 superset-frontend/src/components/Radio/index.tsx   |  80 ++--
 .../header-renderers/HeaderWithRadioGroup.tsx      |  20 +-
 .../FiltersConfigForm/FiltersConfigForm.tsx        |  36 +-
 .../explore/components/DataTableControl/index.tsx  |  22 +-
 .../components/ExploreChartHeader/index.jsx        |   2 +-
 .../controls/DateFilterControl/DateFilterLabel.tsx |   6 -
 .../DateFilterControl/components/CalendarFrame.tsx |  18 +-
 .../DateFilterControl/components/CommonFrame.tsx   |  18 +-
 .../components/CurrentCalendarFrame.tsx            |  25 +-
 .../DateFilterControl/components/CustomFrame.tsx   |  15 +-
 .../DateFilterControl/tests/CalendarFrame.test.tsx |   8 +-
 .../DateFilterControl/tests/CustomFrame.test.tsx   |   8 +-
 .../controls/DateFilterControl/utils/constants.ts  |  13 +-
 .../src/features/alerts/AlertReportModal.tsx       |  86 ++++-
 .../src/features/reports/ReportModal/index.tsx     |  40 +-
 .../src/features/reports/ReportModal/styles.tsx    |   4 -
 superset-frontend/src/hooks/apiResources/sqlLab.ts |   4 +-
 superset-frontend/src/hooks/apiResources/tables.ts |  10 +-
 superset/charts/api.py                             | 111 +++---
 superset/charts/schemas.py                         |  15 +
 superset/commands/database/tables.py               |   6 +
 superset/commands/report/execute.py                |  28 +-
 superset/config.py                                 |  11 +
 superset/dashboards/api.py                         | 261 +++++++------
 superset/dashboards/schemas.py                     |   6 +
 superset/db_engine_specs/parseable.py              |  84 ++++
 superset/migrations/shared/catalogs.py             |  11 +-
 superset/models/slice.py                           |   4 +-
 superset/reports/models.py                         |  34 ++
 superset/tasks/thumbnails.py                       |  15 +-
 superset/utils/screenshots.py                      | 190 +++++----
 superset/utils/webdriver.py                        |  10 +-
 tests/integration_tests/async_events/api_tests.py  |   9 +-
 tests/integration_tests/cli_tests.py               |   6 +-
 tests/integration_tests/dashboards/api_tests.py    |  40 +-
 tests/integration_tests/thumbnails_tests.py        |  27 +-
 tests/unit_tests/commands/databases/tables_test.py |  28 +-
 tests/unit_tests/commands/report/execute_test.py   | 115 ++++++
 tests/unit_tests/db_engine_specs/test_parseable.py |  77 ++++
 .../unit_tests/migrations/shared/catalogs_test.py  | 250 ++++++++++++
 tests/unit_tests/models/core_test.py               |  56 +++
 tests/unit_tests/utils/screenshot_test.py          | 194 ++++++++++
 80 files changed, 3824 insertions(+), 910 deletions(-)

diff --cc superset-frontend/src/features/alerts/AlertReportModal.tsx
index 8cd3ca112a,f3f8bab182..5152160b4f
--- a/superset-frontend/src/features/alerts/AlertReportModal.tsx
+++ b/superset-frontend/src/features/alerts/AlertReportModal.tsx
@@@ -456,12 -454,6 +456,12 @@@ const AlertReportModal: FunctionCompone
    const [dashboardOptions, setDashboardOptions] = useState<MetaObject[]>([]);
    const [chartOptions, setChartOptions] = useState<MetaObject[]>([]);
    const [tabOptions, setTabOptions] = useState<TabNode[]>([]);
 +  const [nativeFilterOptions, setNativeFilterOptions] = useState<object>([]);
 +  const [nativeFilterValues, setNativeFilterValues] = useState<object>([]);
 +
-   const [nativeFilterOptionsTwo, setNativeFilterOptionsTwo] = 
useState<object>([]);
- 
-   console.log('nativeFilters', nativeFilterOptions);
++  // todo(hughhh): refactor to handle multiple native filters
++  const [nativeFilter, setSelectedNativeFilter] = useState<object>({});
++  const [nativeFilters, setGlobalNativeFilters] = useState<object>({});
  
    // Validation
    const [validationStatus, setValidationStatus] = useState<ValidationObject>({
@@@ -673,6 -665,6 +673,11 @@@
  
      const shouldEnableForceScreenshot =
        contentType === ContentType.Chart && !isReport;
++
++
++    // todo(hughhh): refactor to handle multiple native filters
++    currentAlert.extra.nativeFilter = nativeFilter
++
      const data: any = {
        ...currentAlert,
        type: isReport ? 'Report' : 'Alert',
@@@ -841,64 -832,9 +846,68 @@@
              value: JSON.stringify(Object.keys(allTabs)),
            });
            setTabOptions(tabTree);
 -
 +          // console.log('setting native filters', nativeFilters);
-           // setNativeFilterOptions(nativeFilters);
++          setGlobalNativeFilters(nativeFilters);
 +
 +          // const dashboardId = dashboard.value;
 +          // const newFormData = getFormData({
 +              // ...filter,
 +              // datasetId,
 +              // dependencies,
 +              // groupby,
 +              // adhoc_filters,
 +              // time_range,
 +              // dashboardId,
 +          // });
 +
 +          const chartDataExample = {
 +            formData: {
 +              // enableEmptyFilter: false,
 +              // defaultToFirstItem: false,
 +              // multiSelect: true,
 +              // searchAllOptions: false,
 +              // inverseSelection: false,
 +              datasource: "15__table",
 +              groupby: ["clinical_stage"],
 +              // adhoc_filters: [],
 +              // extra_filters: [],
 +              // extra_form_data: {},
 +              metrics: ["count"],
 +              row_limit: 1000,
 +              showSearch: true,
 +              // url_params: {
 +              //   native_filters_key: "0ktJOz1FTTo"
 +              // },
 +              // inView: true,
 +              viz_type: "filter_select",
 +              // type: "NATIVE_FILTER",
 +              dashboardId: 6,
 +              // native_filter_id: "NATIVE_FILTER-8jS1fx4hl"
 +            },
 +            force: false,
 +            ownState: {}
 +          }
 +          
 +          // get filter values
 +          // getChartDataRequest(chartDataExample).then(response => {
 +          //   console.log('response.json.result', 
response.json.result[0].data)
 +          // });
 +          
            const anchor = currentAlert?.extra?.dashboard?.anchor;
 +          console.log('anchor', anchor);
            if (anchor) {
 +              // const nativeFiltersOptions = 
nativeFilters[anchor].map((filter: any) => {value: filter.id, label: 
filter.name})
 +              console.log('nativeFiltersOptions', nativeFilters[anchor]);
-               setNativeFilterOptions(nativeFilters[anchor].map((filter: any) 
=> ({value: filter.id, label: filter.name})));
-               getChartDataRequest(chartDataExample).then(response => {
-                 console.log('hello', response)
-                 setNativeFilterValues(response.json.result[0].data.map((item: 
any) => ({value: item.clinical_stage, label: item.clinical_stage})))
-               });
++            setNativeFilterOptions(
++              nativeFilters[anchor].map((filter: any) => ({
++                value: filter.id,
++                label: filter.name,
++              }))
++              // getChartDataRequest(chartDataExample).then(response => {
++              //   console.log('hello', response)
++              //   
setNativeFilterValues(response.json.result[0].data.map((item: any) => ({value: 
item.clinical_stage, label: item.clinical_stage})))
++              // });
 +            
              try {
                const parsedAnchor = JSON.parse(anchor);
                if (Array.isArray(parsedAnchor)) {
@@@ -1177,10 -1111,6 +1186,62 @@@
      setForceScreenshot(event.target.checked);
    };
  
 +  const onChangeDashboardFilter = (value: any) => {
 +    console.log('dashboardFilter', value);
++    // set dashboardFilter
++    const anchor = currentAlert?.extra?.dashboard?.anchor
++    const inScopeFilters = nativeFilters[anchor];
++    const filter = inScopeFilters.filter((f: any) => f.id === value)[0]
++    console.log(filter) // use filter to grab values from API
++    console.log('about to get filter values', value);
++    
++    const datasetId = filter.targets[0].datasetId;
++    const columnName = filter.targets[0].column.name;
++    const dashboardId = currentAlert?.dashboard?.value;
++  
++    // Get values tied to the selected filter
++    const filterValues = {
++      formData: {
++        // enableEmptyFilter: false,
++        // defaultToFirstItem: false,
++        // multiSelect: true,
++        // searchAllOptions: false,
++        // inverseSelection: false,
++        datasource: `${datasetId}__table`,
++        groupby: [columnName],
++        // adhoc_filters: [],
++        // extra_filters: [],
++        // extra_form_data: {},
++        metrics: ["count"],
++        row_limit: 1000,
++        showSearch: true,
++        // url_params: {
++        //   native_filters_key: "0ktJOz1FTTo"
++        // },
++        // inView: true,
++        viz_type: "filter_select",
++        // type: "NATIVE_FILTER",
++        dashboardId: dashboardId,
++        // native_filter_id: "NATIVE_FILTER-8jS1fx4hl"
++      },
++      force: false,
++      ownState: {}
++    }
++    
++    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});
++
++    
 +  }
 +
    // Make sure notification settings has the required info
    const checkNotificationSettings = () => {
      if (!notificationSettings.length) {
@@@ -1839,22 -1768,6 +1900,23 @@@
                    placeholder={t('Select a tab')}
                  />
                </>
 +              <div style={{marginTop: '10px', display: 'flex', flexDirection: 
'column'}}>
 +              <div className="control-label">{t('Select Dashboard 
Filter')}</div>
 +                <Select 
 +                  disabled={nativeFilterOptions?.length < 1}
 +                  ariaLabel={t('Select Filter')}
-                   value={"value"}
++                  value={nativeFilter.nativeFilter}
 +                  options={nativeFilterOptions}
++                  onChange={onChangeDashboardFilter}
 +                />
 +                <div className="control-label">{t('Select Dashboard 
Value')}</div>
 +                <Select 
 +                  ariaLabel={t('Value')}
-                   value={"value"}
++                  value={nativeFilter.nativeFilterValue}
 +                  options={nativeFilterValues}
-                   onChange={onChangeDashboardFilter}
++                  onChange={onChangeDashboardFilterValue}
 +                />
 +              </div>
              </StyledInputContainer>
            )}
            {isScreenshot && (
diff --cc superset/commands/report/execute.py
index 9e69258650,0c57d55bb5..4345a7160b
--- a/superset/commands/report/execute.py
+++ b/superset/commands/report/execute.py
@@@ -282,7 -282,7 +282,7 @@@ class BaseReportState
                      "anchor": tab_anchor,
                      "dataMask": None,
                      "activeTabs": None,
--                    "urlParams": None,
++                    "urlParams": None, # could potentially back the 
native_filters here?
                  },
                  user_friendly=user_friendly,
              )
diff --cc superset/reports/models.py
index e4cdd7c9b4,e4cdd7c9b4..932c4d6077
--- a/superset/reports/models.py
+++ b/superset/reports/models.py
@@@ -15,6 -15,6 +15,7 @@@
  # specific language governing permissions and limitations
  # under the License.
  """A collection of ORM sqlalchemy models for Superset"""
++import prison
  
  from cron_descriptor import get_description
  from flask_appbuilder import Model
@@@ -34,6 -34,6 +35,7 @@@ from sqlalchemy import 
  from sqlalchemy.orm import backref, relationship
  from sqlalchemy.schema import UniqueConstraint
  from sqlalchemy_utils import UUIDType
++from typing import Optional
  
  from superset.extensions import security_manager
  from superset.models.core import Database
@@@ -44,6 -44,6 +46,7 @@@ from superset.reports.types import Repo
  from superset.utils.backports import StrEnum
  from superset.utils.core import MediumText
  
++
  metadata = Model.metadata  # pylint: disable=no-member
  
  
@@@ -182,6 -182,6 +185,37 @@@ class ReportSchedule(AuditMixinNullable
      @renders("crontab")
      def crontab_humanized(self) -> str:
          return get_description(self.crontab)
++    
++    def get_native_filters_params(self) -> Optional[str]:
++        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)
++    
++    def _generate_native_filter(native_filter_id: str, column: 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": {}
++                }
++            }
++        }        
  
  
  class ReportRecipients(Model, AuditMixinNullable):

Reply via email to