This is an automated email from the ASF dual-hosted git repository. msyavuz pushed a commit to branch msyavuz/feat/matrixify-tag-for-charts in repository https://gitbox.apache.org/repos/asf/superset.git
commit 57c35daf87f06a95b99ebfef7f86eaa344d90887 Author: Mehmet Salih Yavuz <[email protected]> AuthorDate: Mon Jan 19 14:33:57 2026 +0300 feat(Matrixify): add matrixify tag to list view and explore --- .../ExploreChartHeader/ExploreChartHeader.test.tsx | 29 ++++++++++++++++++++++ .../components/ExploreChartHeader/index.jsx | 6 ++++- .../src/pages/ChartList/ChartList.test.tsx | 29 +++++++++++++++++++++- .../src/pages/ChartList/ChartList.testHelpers.tsx | 13 ++++++++++ superset-frontend/src/pages/ChartList/index.tsx | 17 +++++++++++-- 5 files changed, 90 insertions(+), 4 deletions(-) diff --git a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx index a8010f1c6a..1f3183845f 100644 --- a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx +++ b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx @@ -383,6 +383,35 @@ describe('ExploreChartHeader', () => { expect(setShowModal).toHaveBeenCalledWith(false); }); + + test('renders Matrixify tag when matrixify is enabled', async () => { + const props = createProps({ + formData: { + ...createProps().chart.latestQueryFormData, + matrixify_enable_vertical_layout: true, + matrixify_mode_rows: 'metrics', + matrixify_rows: [{ label: 'COUNT(*)', expressionType: 'SIMPLE' }], + }, + }); + render(<ExploreHeader {...props} />, { useRedux: true }); + + const matrixifyTag = await screen.findByText('Matrixify'); + expect(matrixifyTag).toBeInTheDocument(); + expect(matrixifyTag.closest('[color="purple"]')).toBeInTheDocument(); + }); + + test('does not render Matrixify tag when matrixify is disabled', async () => { + const props = createProps({ + formData: { + ...createProps().chart.latestQueryFormData, + }, + }); + render(<ExploreHeader {...props} />, { useRedux: true }); + + await waitFor(() => { + expect(screen.queryByText('Matrixify')).not.toBeInTheDocument(); + }); + }); }); // eslint-disable-next-line no-restricted-globals -- TODO: Migrate from describe blocks diff --git a/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx b/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx index 8be2bea51b..857e5032f2 100644 --- a/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx +++ b/superset-frontend/src/explore/components/ExploreChartHeader/index.jsx @@ -27,7 +27,7 @@ import { UnsavedChangesModal, } from '@superset-ui/core/components'; import { AlteredSliceTag } from 'src/components'; -import { SupersetClient } from '@superset-ui/core'; +import { SupersetClient, isMatrixifyEnabled } from '@superset-ui/core'; import { logging } from '@apache-superset/core'; import { css, t } from '@apache-superset/core/ui'; import { chartPropShape } from 'src/dashboard/util/propShapes'; @@ -42,6 +42,7 @@ import { deleteActiveReport } from 'src/features/reports/ReportModal/actions'; import { useUnsavedChangesPrompt } from 'src/hooks/useUnsavedChangesPrompt'; import { getChartFormDiffs } from 'src/utils/getChartFormDiffs'; import { StreamingExportModal } from 'src/components/StreamingExportModal'; +import { Tag } from 'src/components/Tag'; import { useExploreAdditionalActionsMenu } from '../useExploreAdditionalActionsMenu'; import { useExploreMetadataBar } from './useExploreMetadataBar'; @@ -272,6 +273,9 @@ export const ExploreChartHeader = ({ currentFormData={currentFormData} /> ) : null} + {formData && isMatrixifyEnabled(formData) && ( + <Tag name="Matrixify" color="purple" /> + )} {metadataBar} </div> } diff --git a/superset-frontend/src/pages/ChartList/ChartList.test.tsx b/superset-frontend/src/pages/ChartList/ChartList.test.tsx index 214f887c7a..180a023763 100644 --- a/superset-frontend/src/pages/ChartList/ChartList.test.tsx +++ b/superset-frontend/src/pages/ChartList/ChartList.test.tsx @@ -17,7 +17,7 @@ * under the License. */ import fetchMock from 'fetch-mock'; -import { screen, waitFor, fireEvent } from 'spec/helpers/testing-library'; +import { screen, waitFor, fireEvent, within } from 'spec/helpers/testing-library'; import { isFeatureEnabled } from '@superset-ui/core'; import { API_ENDPOINTS, @@ -245,6 +245,33 @@ describe('ChartList', () => { ); }); + test('displays Matrixify tag for charts with matrixify enabled', async () => { + renderChartList(mockUser); + + // Wait for the chart list to load + await waitFor(() => { + expect(screen.getByText('Test Chart 0')).toBeInTheDocument(); + }); + + // Find the row containing Test Chart 0 (which has matrixify enabled) + const chart0Row = screen.getByText('Test Chart 0').closest('tr'); + expect(chart0Row).toBeInTheDocument(); + + // Check that the Matrixify tag is present in this row + const matrixifyTag = within(chart0Row as HTMLElement).getByText('Matrixify'); + expect(matrixifyTag).toBeInTheDocument(); + + // Verify it's styled as purple (check for the color attribute or class) + expect(matrixifyTag.closest('[color="purple"]')).toBeInTheDocument(); + + // Find the row containing Test Chart 1 (which doesn't have matrixify) + const chart1Row = screen.getByText('Test Chart 1').closest('tr'); + expect(chart1Row).toBeInTheDocument(); + + // Check that the Matrixify tag is NOT present in this row + expect(within(chart1Row as HTMLElement).queryByText('Matrixify')).not.toBeInTheDocument(); + }); + test('handles API errors gracefully', async () => { // Mock API failure fetchMock.get( diff --git a/superset-frontend/src/pages/ChartList/ChartList.testHelpers.tsx b/superset-frontend/src/pages/ChartList/ChartList.testHelpers.tsx index 1e600cf41b..b22462ce95 100644 --- a/superset-frontend/src/pages/ChartList/ChartList.testHelpers.tsx +++ b/superset-frontend/src/pages/ChartList/ChartList.testHelpers.tsx @@ -60,6 +60,14 @@ export const mockCharts = [ thumbnail_url: '/api/v1/chart/0/thumbnail/', certified_by: null, certification_details: null, + + // Add form_data with matrixify enabled + form_data: { + viz_type: 'table', + matrixify_enable_vertical_layout: true, + matrixify_mode_rows: 'metrics', + matrixify_rows: [{ label: 'COUNT(*)', expressionType: 'SIMPLE' }], + }, }, { id: 1, @@ -102,6 +110,11 @@ export const mockCharts = [ thumbnail_url: '/api/v1/chart/1/thumbnail/', certified_by: 'Data Team', certification_details: 'Approved for production use', + + // Add form_data without matrixify + form_data: { + viz_type: 'bar', + }, }, { id: 2, diff --git a/superset-frontend/src/pages/ChartList/index.tsx b/superset-frontend/src/pages/ChartList/index.tsx index b0abfe0c8e..0b51c2452b 100644 --- a/superset-frontend/src/pages/ChartList/index.tsx +++ b/superset-frontend/src/pages/ChartList/index.tsx @@ -23,6 +23,7 @@ import { getChartMetadataRegistry, JsonResponse, SupersetClient, + isMatrixifyEnabled, } from '@superset-ui/core'; import { styled } from '@apache-superset/core/ui'; import { useState, useMemo, useCallback } from 'react'; @@ -78,6 +79,7 @@ import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; import { findPermission } from 'src/utils/findPermission'; import { QueryObjectColumns } from 'src/views/CRUD/types'; import { WIDER_DROPDOWN_WIDTH } from 'src/components/ListView/utils'; +import { Tag } from 'src/components/Tag'; const FlexRowContainer = styled.div` align-items: center; @@ -375,9 +377,20 @@ function ChartList(props: ChartListProps) { { Cell: ({ row: { - original: { viz_type: vizType }, + original: { viz_type: vizType, form_data: formData }, }, - }: any) => registry.get(vizType)?.name || vizType, + }: any) => ( + <> + {registry.get(vizType)?.name || vizType} + {formData && isMatrixifyEnabled(formData) && ( + <Tag + name="Matrixify" + color="purple" + style={{ marginLeft: 8 }} + /> + )} + </> + ), Header: t('Type'), accessor: 'viz_type', id: 'viz_type',
