diff --git a/.github/workflows/superset-app-cli.yml b/.github/workflows/superset-app-cli.yml index ea41e5da412c..3cc839eb285a 100644 --- a/.github/workflows/superset-app-cli.yml +++ b/.github/workflows/superset-app-cli.yml @@ -23,7 +23,7 @@ jobs: SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset diff --git a/.github/workflows/superset-docs-deploy.yml b/.github/workflows/superset-docs-deploy.yml index 85dd4bae21f9..e4998a074a55 100644 --- a/.github/workflows/superset-docs-deploy.yml +++ b/.github/workflows/superset-docs-deploy.yml @@ -68,7 +68,7 @@ jobs: yarn install --check-cache - name: Download database diagnostics (if triggered by integration tests) if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' - uses: dawidd6/action-download-artifact@v14 + uses: dawidd6/action-download-artifact@v15 continue-on-error: true with: workflow: superset-python-integrationtest.yml @@ -77,7 +77,7 @@ jobs: path: docs/src/data/ - name: Try to download latest diagnostics (for push/dispatch triggers) if: github.event_name != 'workflow_run' - uses: dawidd6/action-download-artifact@v14 + uses: dawidd6/action-download-artifact@v15 continue-on-error: true with: workflow: superset-python-integrationtest.yml diff --git a/.github/workflows/superset-docs-verify.yml b/.github/workflows/superset-docs-verify.yml index e745dfcfd7c9..4ef6f6274216 100644 --- a/.github/workflows/superset-docs-verify.yml +++ b/.github/workflows/superset-docs-verify.yml @@ -111,7 +111,7 @@ jobs: run: | yarn install --check-cache - name: Download database diagnostics from integration tests - uses: dawidd6/action-download-artifact@v14 + uses: dawidd6/action-download-artifact@v15 with: workflow: superset-python-integrationtest.yml run_id: ${{ github.event.workflow_run.id }} diff --git a/.github/workflows/superset-e2e.yml b/.github/workflows/superset-e2e.yml index 655a3da7e278..e3046a973d24 100644 --- a/.github/workflows/superset-e2e.yml +++ b/.github/workflows/superset-e2e.yml @@ -54,7 +54,7 @@ jobs: USE_DASHBOARD: ${{ github.event.inputs.use_dashboard == 'true' || 'false' }} services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset @@ -171,7 +171,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset diff --git a/.github/workflows/superset-playwright.yml b/.github/workflows/superset-playwright.yml index b2e2dbf6a9b5..910b61c9c203 100644 --- a/.github/workflows/superset-playwright.yml +++ b/.github/workflows/superset-playwright.yml @@ -45,7 +45,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset diff --git a/.github/workflows/superset-python-integrationtest.yml b/.github/workflows/superset-python-integrationtest.yml index d8e73d066ae0..bb0dce85bbaf 100644 --- a/.github/workflows/superset-python-integrationtest.yml +++ b/.github/workflows/superset-python-integrationtest.yml @@ -115,7 +115,7 @@ jobs: SUPERSET__SQLALCHEMY_DATABASE_URI: postgresql+psycopg2://superset:superset@127.0.0.1:15432/superset services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset diff --git a/.github/workflows/superset-python-presto-hive.yml b/.github/workflows/superset-python-presto-hive.yml index b4bb9d5432b1..762c1a19d45d 100644 --- a/.github/workflows/superset-python-presto-hive.yml +++ b/.github/workflows/superset-python-presto-hive.yml @@ -25,7 +25,7 @@ jobs: SUPERSET__SQLALCHEMY_EXAMPLES_URI: presto://localhost:15433/memory/default services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset @@ -94,7 +94,7 @@ jobs: UPLOAD_FOLDER: /tmp/.superset/uploads/ services: postgres: - image: postgres:16-alpine + image: postgres:17-alpine env: POSTGRES_USER: superset POSTGRES_PASSWORD: superset diff --git a/docker-compose-image-tag.yml b/docker-compose-image-tag.yml index f9c486869a62..fd76e68abcd7 100644 --- a/docker-compose-image-tag.yml +++ b/docker-compose-image-tag.yml @@ -45,7 +45,7 @@ services: required: true - path: docker/.env-local # optional override required: false - image: postgres:16 + image: postgres:17 container_name: superset_db restart: unless-stopped volumes: diff --git a/docker-compose-light.yml b/docker-compose-light.yml index b3b6f41fdd1d..1d0a4a90be7b 100644 --- a/docker-compose-light.yml +++ b/docker-compose-light.yml @@ -85,7 +85,7 @@ services: required: true - path: docker/.env-local # optional override required: false - image: postgres:16 + image: postgres:17 restart: unless-stopped volumes: - db_home_light:/var/lib/postgresql/data diff --git a/docker-compose-non-dev.yml b/docker-compose-non-dev.yml index 5d221ab602c1..cc80aea9d19a 100644 --- a/docker-compose-non-dev.yml +++ b/docker-compose-non-dev.yml @@ -49,7 +49,7 @@ services: required: true - path: docker/.env-local # optional override required: false - image: postgres:16 + image: postgres:17 container_name: superset_db restart: unless-stopped volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 8ab4b117f239..bd474a83ef47 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,7 +76,7 @@ services: required: true - path: docker/.env-local # optional override required: false - image: postgres:16 + image: postgres:17 restart: unless-stopped ports: - "127.0.0.1:${DATABASE_PORT:-5432}:5432" diff --git a/docs/docs/configuration/configuring-superset.mdx b/docs/docs/configuration/configuring-superset.mdx index e44b533fa992..c0032f1727fb 100644 --- a/docs/docs/configuration/configuring-superset.mdx +++ b/docs/docs/configuration/configuring-superset.mdx @@ -141,10 +141,10 @@ database engine on a separate host or container. Superset supports the following database engines/versions: -| Database Engine | Supported Versions | -| ----------------------------------------- | ---------------------------------------- | -| [PostgreSQL](https://www.postgresql.org/) | 10.X, 11.X, 12.X, 13.X, 14.X, 15.X, 16.X | -| [MySQL](https://www.mysql.com/) | 5.7, 8.X | +| Database Engine | Supported Versions | +| ----------------------------------------- | ---------------------------------------------- | +| [PostgreSQL](https://www.postgresql.org/) | 10.X, 11.X, 12.X, 13.X, 14.X, 15.X, 16.X, 17.X | +| [MySQL](https://www.mysql.com/) | 5.7, 8.X | Use the following database drivers and connection strings: diff --git a/helm/superset/Chart.lock b/helm/superset/Chart.lock index cb82f4cd84b9..3b59d04183d3 100644 --- a/helm/superset/Chart.lock +++ b/helm/superset/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: postgresql repository: oci://registry-1.docker.io/bitnamicharts - version: 13.4.4 + version: 16.7.27 - name: redis repository: oci://registry-1.docker.io/bitnamicharts version: 17.9.4 -digest: sha256:c6290bb7e8ce9c694c06b3f5e9b9d01401943b0943c515d3a7a3a8dc1e6492ea -generated: "2025-03-16T00:52:41.47139769+09:00" +digest: sha256:fcae507ca24a20b9cc08b8bf0fcb0eba8ffa33126ab6f71cc3a6e1d5e997e9e3 +generated: "2026-02-08T14:11:58.8058368+01:00" diff --git a/helm/superset/Chart.yaml b/helm/superset/Chart.yaml index 0cab38e8fc8d..5ef4fb2e00f1 100644 --- a/helm/superset/Chart.yaml +++ b/helm/superset/Chart.yaml @@ -29,10 +29,10 @@ maintainers: - name: craig-rueda email: craig@craigrueda.com url: https://github.com/craig-rueda -version: 0.15.3 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details. +version: 0.15.4 # See [README](https://github.com/apache/superset/blob/master/helm/superset/README.md#versioning) for version details. dependencies: - name: postgresql - version: 13.4.4 + version: 16.7.27 repository: oci://registry-1.docker.io/bitnamicharts condition: postgresql.enabled - name: redis diff --git a/helm/superset/README.md b/helm/superset/README.md index e9b372c72c0c..29dbdeea8a6a 100644 --- a/helm/superset/README.md +++ b/helm/superset/README.md @@ -23,7 +23,7 @@ NOTE: This file is generated by helm-docs: https://github.com/norwoodj/helm-docs # superset -![Version: 0.15.3](https://img.shields.io/badge/Version-0.15.3-informational?style=flat-square) +![Version: 0.15.4](https://img.shields.io/badge/Version-0.15.4-informational?style=flat-square) Apache Superset is a modern, enterprise-ready business intelligence web application @@ -50,7 +50,7 @@ On helm this can be set on `extraSecretEnv.SUPERSET_SECRET_KEY` or `configOverri | Repository | Name | Version | |------------|------|---------| -| oci://registry-1.docker.io/bitnamicharts | postgresql | 13.4.4 | +| oci://registry-1.docker.io/bitnamicharts | postgresql | 16.7.27 | | oci://registry-1.docker.io/bitnamicharts | redis | 17.9.4 | ## Values diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js index a2c9b3ae5d73..bf6cb9b6fd61 100644 --- a/superset-frontend/.eslintrc.js +++ b/superset-frontend/.eslintrc.js @@ -245,6 +245,16 @@ module.exports = { // Lodash 'lodash/import-scope': [2, 'member'], + // React effect best practices + 'react-you-might-not-need-an-effect/no-reset-all-state-on-prop-change': + 'error', + 'react-you-might-not-need-an-effect/no-chain-state-updates': 'error', + 'react-you-might-not-need-an-effect/no-event-handler': 'error', + 'react-you-might-not-need-an-effect/no-derived-state': 'error', + + // Storybook + 'storybook/prefer-pascal-case': 'error', + // File progress 'file-progress/activate': 1, diff --git a/superset-frontend/oxlint.json b/superset-frontend/oxlint.json index 50e482ecedd4..942965a865df 100644 --- a/superset-frontend/oxlint.json +++ b/superset-frontend/oxlint.json @@ -34,7 +34,8 @@ "no-unused-vars": "off", "no-undef": "error", "no-prototype-builtins": "off", - "no-unsafe-optional-chaining": "off", + "no-unsafe-optional-chaining": "error", + "no-constant-binary-expression": "error", "no-import-assign": "off", "no-promise-executor-return": "off", @@ -254,6 +255,7 @@ // === Unicorn rules (bonus coverage) === "unicorn/no-new-array": "error", "unicorn/no-invalid-remove-event-listener": "error", + "unicorn/no-useless-length-check": "error", "unicorn/filename-case": "off", "unicorn/prevent-abbreviations": "off", "unicorn/no-null": "off", diff --git a/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx b/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx index 88a70ff9e6e9..0b24bdbc3767 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/Layout/Layout.test.tsx @@ -47,9 +47,10 @@ describe('Layout Component', () => { }); test('hides Header when headerVisible is false', () => { + const headerVisible = false; render( - {false && Header} + {headerVisible && Header} Content Area Ant Design Layout Footer , @@ -59,11 +60,14 @@ describe('Layout Component', () => { }); test('hides Footer when footerVisible is false', () => { + const footerVisible = false; render( Header Content Area - {false && Ant Design Layout Footer} + {footerVisible && ( + Ant Design Layout Footer + )} , ); diff --git a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx index 021341808e07..173ab6f83a23 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx @@ -280,7 +280,7 @@ const CustomModal = ({ const shouldShowMask = !(resizable || draggable); const onDragStart = (_: DraggableEvent, uiData: DraggableData) => { - const { clientWidth, clientHeight } = window?.document?.documentElement; + const { clientWidth, clientHeight } = document.documentElement; const targetRect = draggableRef?.current?.getBoundingClientRect(); if (targetRect) { diff --git a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts index 9212936686b6..8122c86f825c 100644 --- a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts @@ -606,7 +606,7 @@ const buildQuery: BuildQuery = ( { ...queryObject, time_offsets: [], - row_limit: Number(formData?.row_limit) ?? 0, + row_limit: Number(formData?.row_limit ?? 0), row_offset: 0, post_processing: [], is_rowcount: true, diff --git a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts index 3c681f281b09..66933c4f8137 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/test/BigNumber/transformProps.test.ts @@ -196,7 +196,9 @@ describe('BigNumberWithTrendline', () => { showXAxis: true, }, }); - expect((transformed.echartOptions?.xAxis as any).show).toBe(true); + expect((transformed.echartOptions!.xAxis as { show: boolean }).show).toBe( + true, + ); }); test('should not show X axis when showXAxis is false', () => { @@ -207,7 +209,9 @@ describe('BigNumberWithTrendline', () => { showXAxis: false, }, }); - expect((transformed.echartOptions?.xAxis as any).show).toBe(false); + expect((transformed.echartOptions!.xAxis as { show: boolean }).show).toBe( + false, + ); }); test('should show Y axis when showYAxis is true', () => { @@ -218,7 +222,9 @@ describe('BigNumberWithTrendline', () => { showYAxis: true, }, }); - expect((transformed.echartOptions?.yAxis as any).show).toBe(true); + expect((transformed.echartOptions!.yAxis as { show: boolean }).show).toBe( + true, + ); }); test('should not show Y axis when showYAxis is false', () => { @@ -229,7 +235,9 @@ describe('BigNumberWithTrendline', () => { showYAxis: false, }, }); - expect((transformed.echartOptions?.yAxis as any).show).toBe(false); + expect((transformed.echartOptions!.yAxis as { show: boolean }).show).toBe( + false, + ); }); }); diff --git a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts index 7b3a952d8915..c23a8a49c565 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts @@ -347,7 +347,7 @@ const buildQuery: BuildQuery = ( { ...queryObject, time_offsets: [], - row_limit: Number(formData?.row_limit) ?? 0, + row_limit: Number(formData?.row_limit ?? 0), row_offset: 0, post_processing: [], is_rowcount: true, diff --git a/superset-frontend/src/dashboard/components/nativeFilters/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/state.ts index f95c1bae4efa..ecbb56e47a06 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/state.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/state.ts @@ -210,10 +210,9 @@ export function useIsFilterInScope() { if (hasChartsInScope) { isChartInScope = filter.chartsInScope!.some((chartId: number) => { const tabParents = selectChartTabParents(chartId); + // Note: every() returns true for empty arrays, so length check is unnecessary return ( - !tabParents || - tabParents.length === 0 || - tabParents.every(tab => activeTabs.includes(tab)) + !tabParents || tabParents.every(tab => activeTabs.includes(tab)) ); }); } @@ -276,10 +275,9 @@ export function useIsCustomizationInScope() { customization.chartsInScope.length > 0 && customization.chartsInScope.some((chartId: number) => { const tabParents = selectChartTabParents(chartId); + // Note: every() returns true for empty arrays, so length check is unnecessary return ( - !tabParents || - tabParents.length === 0 || - tabParents.every(tab => activeTabs.includes(tab)) + !tabParents || tabParents.every(tab => activeTabs.includes(tab)) ); });