diff --git a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx
index a8010f1c6a8..a1969c99612 100644
--- a/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx
+++ b/superset-frontend/src/explore/components/ExploreChartHeader/ExploreChartHeader.test.tsx
@@ -383,6 +383,34 @@ 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(, { useRedux: true });
+
+ const matrixifyTag = await screen.findByText('Matrixify');
+ expect(matrixifyTag).toBeInTheDocument();
+ });
+
+ test('does not render Matrixify tag when matrixify is disabled', async () => {
+ const props = createProps({
+ formData: {
+ ...createProps().chart.latestQueryFormData,
+ },
+ });
+ render(, { 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 8be2bea51bc..857e5032f26 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) && (
+
+ )}
{metadataBar}
}
diff --git a/superset-frontend/src/pages/ChartList/ChartList.test.tsx b/superset-frontend/src/pages/ChartList/ChartList.test.tsx
index 214f887c7aa..107a7e2d022 100644
--- a/superset-frontend/src/pages/ChartList/ChartList.test.tsx
+++ b/superset-frontend/src/pages/ChartList/ChartList.test.tsx
@@ -17,7 +17,12 @@
* 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 +250,34 @@ 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();
+
+ // 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 1e600cf41b7..a6578935466 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 b0abfe0c8ec..f0ff7fb5475 100644
--- a/superset-frontend/src/pages/ChartList/index.tsx
+++ b/superset-frontend/src/pages/ChartList/index.tsx
@@ -16,15 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { t } from '@apache-superset/core';
+import { t, SupersetTheme } from '@apache-superset/core';
import {
isFeatureEnabled,
FeatureFlag,
getChartMetadataRegistry,
JsonResponse,
SupersetClient,
+ isMatrixifyEnabled,
} from '@superset-ui/core';
-import { styled } from '@apache-superset/core/ui';
+import { css, styled } from '@apache-superset/core/ui';
import { useState, useMemo, useCallback } from 'react';
import rison from 'rison';
import { uniqBy } from 'lodash';
@@ -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,22 @@ 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) && (
+ css`
+ margin-left: ${theme.marginXS}px;
+ `}
+ >
+
+
+ )}
+ >
+ ),
Header: t('Type'),
accessor: 'viz_type',
id: 'viz_type',