mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-30 01:59:23 +00:00
Sort data in total data assets widget by count (#23490)
(cherry picked from commit d8f8d6beb4a39df5021410d4811102a721924ceb)
This commit is contained in:
parent
7e6291697f
commit
1cf3649bcc
@ -13,7 +13,15 @@
|
||||
import { Typography } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { groupBy, isEmpty, omit, reduce, sortBy, startCase } from 'lodash';
|
||||
import {
|
||||
groupBy,
|
||||
isEmpty,
|
||||
omit,
|
||||
orderBy,
|
||||
reduce,
|
||||
sortBy,
|
||||
startCase,
|
||||
} from 'lodash';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@ -75,13 +83,11 @@ const TotalDataAssetsWidget = ({
|
||||
applicationConfig?.customTheme?.primaryColor ??
|
||||
DEFAULT_THEME.primaryColor;
|
||||
|
||||
// Generate palette and arrange from dark to light for high-to-low data
|
||||
const fullPalette = generatePalette(primaryColor);
|
||||
const reversed = fullPalette.slice().reverse();
|
||||
|
||||
const firstTwo = reversed.slice(0, 2);
|
||||
const remaining = reversed.slice(2);
|
||||
|
||||
return [...remaining, ...firstTwo];
|
||||
// Reverse the palette to ensure dark-to-light order for high-to-low data
|
||||
return fullPalette.slice().reverse();
|
||||
}, [applicationConfig?.customTheme?.primaryColor]);
|
||||
|
||||
const widgetData = useMemo(() => {
|
||||
@ -92,15 +98,13 @@ const TotalDataAssetsWidget = ({
|
||||
return currentLayout?.find((item) => item.i === widgetKey)?.w === 2;
|
||||
}, [currentLayout, widgetKey]);
|
||||
|
||||
const { graphData, rightSideEntityList, dataByDate, availableDates } =
|
||||
useMemo(() => {
|
||||
const { graphData, dataByDate, availableDates } = useMemo(() => {
|
||||
const results = chartData?.results ?? [];
|
||||
|
||||
const groupedByDay = groupBy(results, 'day');
|
||||
const labels: string[] = [];
|
||||
|
||||
const graphData = Object.entries(groupedByDay).map(
|
||||
([dayKey, entries]) => {
|
||||
const graphData = Object.entries(groupedByDay).map(([dayKey, entries]) => {
|
||||
const day = Number(dayKey);
|
||||
const values = entries.reduce((acc, curr) => {
|
||||
if (curr.group) {
|
||||
@ -118,11 +122,9 @@ const TotalDataAssetsWidget = ({
|
||||
dayString: customFormatDateTime(day, 'dd MMM'),
|
||||
...values,
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const sortedData = sortBy(graphData, 'day');
|
||||
const uniqueLabels = Array.from(new Set(labels));
|
||||
|
||||
const dataByDate: Record<number, Record<string, number>> = {};
|
||||
sortedData.forEach((item) => {
|
||||
@ -136,23 +138,34 @@ const TotalDataAssetsWidget = ({
|
||||
|
||||
return {
|
||||
graphData: sortedData,
|
||||
rightSideEntityList: uniqueLabels,
|
||||
dataByDate,
|
||||
availableDates,
|
||||
};
|
||||
}, [chartData?.results]);
|
||||
|
||||
const selectedDateData = useMemo(() => {
|
||||
const { selectedDateData, sortedEntityList, totalDatAssets } = useMemo(() => {
|
||||
if (!selectedDate) {
|
||||
return {};
|
||||
return { selectedDateData: {}, sortedEntityList: [], totalDatAssets: 0 };
|
||||
}
|
||||
|
||||
return dataByDate[selectedDate] ?? {};
|
||||
}, [selectedDate, dataByDate]);
|
||||
const rawData = dataByDate[selectedDate] ?? {};
|
||||
|
||||
const totalDatAssets = useMemo(() => {
|
||||
return reduce(selectedDateData, (acc, value) => acc + value, 0);
|
||||
}, [selectedDateData]);
|
||||
// Sort data by count (high to low) and create sorted structures
|
||||
const sortedEntries = orderBy(
|
||||
Object.entries(rawData),
|
||||
([, value]) => value,
|
||||
'desc'
|
||||
);
|
||||
const sortedData = Object.fromEntries(sortedEntries);
|
||||
const entityList = Object.keys(sortedData);
|
||||
const total = reduce(sortedData, (acc, value) => acc + value, 0);
|
||||
|
||||
return {
|
||||
selectedDateData: sortedData,
|
||||
sortedEntityList: entityList,
|
||||
totalDatAssets: total,
|
||||
};
|
||||
}, [selectedDate, dataByDate]);
|
||||
|
||||
const fetchData = async () => {
|
||||
setIsLoading(true);
|
||||
@ -222,7 +235,7 @@ const TotalDataAssetsWidget = ({
|
||||
nameKey="name"
|
||||
outerRadius={117}
|
||||
paddingAngle={1}>
|
||||
{rightSideEntityList.map((label, index) => (
|
||||
{sortedEntityList.map((label, index) => (
|
||||
<Cell
|
||||
fill={pieChartColors[index % pieChartColors.length]}
|
||||
key={label}
|
||||
@ -252,11 +265,17 @@ const TotalDataAssetsWidget = ({
|
||||
|
||||
{/* Right-side Legend */}
|
||||
{isFullSizeWidget && (
|
||||
<div className="flex-1 legend-list p-md">
|
||||
{rightSideEntityList.map((label, index) => (
|
||||
<div className="d-flex items-center gap-3 text-sm" key={label}>
|
||||
<div
|
||||
className="flex-1 legend-list p-md"
|
||||
data-testid="assets-legend">
|
||||
{sortedEntityList.map((label, index) => (
|
||||
<div
|
||||
className="d-flex items-center gap-3 text-sm"
|
||||
data-testid={`legend-item-${label}`}
|
||||
key={label}>
|
||||
<span
|
||||
className="h-3 w-3"
|
||||
data-testid={`legend-color-${label}`}
|
||||
style={{
|
||||
borderRadius: '50%',
|
||||
backgroundColor:
|
||||
@ -266,7 +285,9 @@ const TotalDataAssetsWidget = ({
|
||||
<Typography.Text ellipsis={{ tooltip: true }}>
|
||||
{startCase(label)}
|
||||
</Typography.Text>
|
||||
<span className="text-xs font-medium p-y-xss p-x-xs data-value">
|
||||
<span
|
||||
className="text-xs font-medium p-y-xss p-x-xs data-value"
|
||||
data-testid={`legend-count-${label}`}>
|
||||
{selectedDateData[label] ?? 0}
|
||||
</span>
|
||||
</div>
|
||||
@ -298,8 +319,9 @@ const TotalDataAssetsWidget = ({
|
||||
selectedDate,
|
||||
selectedDateData,
|
||||
totalDatAssets,
|
||||
rightSideEntityList,
|
||||
sortedEntityList,
|
||||
isFullSizeWidget,
|
||||
pieChartColors,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -547,6 +547,79 @@ describe('TotalDataAssetsWidget', () => {
|
||||
});
|
||||
|
||||
describe('Data Processing', () => {
|
||||
it('should sort data by count in descending order', async () => {
|
||||
const sortedTestData: DataInsightCustomChartResult = {
|
||||
results: [
|
||||
{
|
||||
count: 50,
|
||||
day: 1640995200000,
|
||||
group: 'dashboard',
|
||||
term: 'dashboard',
|
||||
},
|
||||
{
|
||||
count: 200,
|
||||
day: 1640995200000,
|
||||
group: 'table',
|
||||
term: 'table',
|
||||
},
|
||||
{
|
||||
count: 100,
|
||||
day: 1640995200000,
|
||||
group: 'topic',
|
||||
term: 'topic',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
(getChartPreviewByName as jest.Mock).mockResolvedValueOnce(
|
||||
sortedTestData
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
renderTotalDataAssetsWidget();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('350')).toBeInTheDocument(); // Total count
|
||||
});
|
||||
|
||||
// Verify legend items are sorted by count (high to low)
|
||||
await waitFor(() => {
|
||||
// Verify specific legend items exist with correct counts using data-testid
|
||||
expect(screen.getByTestId('legend-count-table')).toHaveTextContent(
|
||||
'200'
|
||||
);
|
||||
expect(screen.getByTestId('legend-count-topic')).toHaveTextContent(
|
||||
'100'
|
||||
);
|
||||
expect(screen.getByTestId('legend-count-dashboard')).toHaveTextContent(
|
||||
'50'
|
||||
);
|
||||
|
||||
// Verify legend items appear in sorted order (highest count first)
|
||||
const legendContainer = screen.getByTestId('assets-legend');
|
||||
const legendItems = legendContainer.querySelectorAll(
|
||||
'[data-testid^="legend-item-"]'
|
||||
);
|
||||
|
||||
// First item should be table (highest count)
|
||||
expect(legendItems[0]).toHaveAttribute(
|
||||
'data-testid',
|
||||
'legend-item-table'
|
||||
);
|
||||
// Second item should be topic (medium count)
|
||||
expect(legendItems[1]).toHaveAttribute(
|
||||
'data-testid',
|
||||
'legend-item-topic'
|
||||
);
|
||||
// Third item should be dashboard (lowest count)
|
||||
expect(legendItems[2]).toHaveAttribute(
|
||||
'data-testid',
|
||||
'legend-item-dashboard'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should correctly group data by date', async () => {
|
||||
await act(async () => {
|
||||
renderTotalDataAssetsWidget();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user