feat: change Bar color opacity and make stacking as default (#9026)

This commit is contained in:
SagarRajput-7 2025-09-10 20:26:40 +05:30 committed by GitHub
parent 0658c561b9
commit 9d999feabb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 97 additions and 26 deletions

View File

@ -3168,7 +3168,6 @@ export const getStatusCodeBarChartWidgetData = (
},
description: '',
id: '315b15fa-ff0c-442f-89f8-2bf4fb1af2f2',
isStacked: false,
panelTypes: PANEL_TYPES.BAR,
title: '',
opacity: '',

View File

@ -53,7 +53,6 @@ const mockProps: WidgetGraphComponentProps = {
description: '',
fillSpans: false,
id: '17f905f6-d355-46bd-a78e-cbc87e6f58cc',
isStacked: false,
mergeAllActiveQueries: false,
nullZeroValues: 'zero',
opacity: '1',

View File

@ -38,7 +38,6 @@ export const getWidgetQueryBuilder = ({
}: GetWidgetQueryPropsReturn): Widgets => ({
description: description || '',
id: id || uuid(),
isStacked: false,
nullZeroValues: nullZeroValues || '',
opacity: '1',
panelTypes,

View File

@ -14,7 +14,6 @@ export const getWidgetQueryBuilder = ({
}: GetWidgetQueryBuilderProps): Widgets => ({
description: '',
id: id || v4(),
isStacked: false,
nullZeroValues: '',
opacity: '0',
panelTypes,

View File

@ -535,8 +535,6 @@ interface RightContainerProps {
setTitle: Dispatch<SetStateAction<string>>;
description: string;
setDescription: Dispatch<SetStateAction<string>>;
stacked: boolean;
setStacked: Dispatch<SetStateAction<boolean>>;
opacity: string;
setOpacity: Dispatch<SetStateAction<string>>;
selectedNullZeroValue: string;

View File

@ -6,7 +6,48 @@
// - Handling multiple rows correctly
// - Handling widgets with different heights
import { placeWidgetAtBottom, placeWidgetBetweenRows } from '../utils';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
import { PreferenceContextProvider } from 'providers/preferences/context/PreferenceContextProvider';
import { I18nextProvider } from 'react-i18next';
import { useSearchParams } from 'react-router-dom-v5-compat';
import i18n from 'ReactI18';
import { render } from 'tests/test-utils';
import NewWidget from '..';
import {
getDefaultWidgetData,
placeWidgetAtBottom,
placeWidgetBetweenRows,
} from '../utils';
const MOCK_SEARCH_PARAMS =
'?graphType=bar&widgetId=b473eef0-8eb5-4dd3-8089-c1817734084f&compositeQuery=%7B"id"%3A"f026c678-9abf-42af-a3dc-f73dc8cbb810"%2C"builder"%3A%7B"queryData"%3A%5B%7B"dataSource"%3A"metrics"%2C"queryName"%3A"A"%2C"aggregateOperator"%3A"count"%2C"aggregateAttribute"%3A%7B"id"%3A"----"%2C"dataType"%3A""%2C"key"%3A""%2C"type"%3A""%7D%2C"timeAggregation"%3A"rate"%2C"spaceAggregation"%3A"sum"%2C"filter"%3A%7B"expression"%3A""%7D%2C"aggregations"%3A%5B%7B"metricName"%3A""%2C"temporality"%3A""%2C"timeAggregation"%3A"count"%2C"spaceAggregation"%3A"sum"%2C"reduceTo"%3A"avg"%7D%5D%2C"functions"%3A%5B%5D%2C"filters"%3A%7B"items"%3A%5B%5D%2C"op"%3A"AND"%7D%2C"expression"%3A"A"%2C"disabled"%3Afalse%2C"stepInterval"%3Anull%2C"having"%3A%5B%5D%2C"limit"%3Anull%2C"orderBy"%3A%5B%5D%2C"groupBy"%3A%5B%5D%2C"legend"%3A""%2C"reduceTo"%3A"avg"%2C"source"%3A""%7D%5D%2C"queryFormulas"%3A%5B%5D%2C"queryTraceOperator"%3A%5B%5D%7D%2C"clickhouse_sql"%3A%5B%7B"name"%3A"A"%2C"legend"%3A""%2C"disabled"%3Afalse%2C"query"%3A""%7D%5D%2C"promql"%3A%5B%7B"name"%3A"A"%2C"query"%3A""%2C"legend"%3A""%2C"disabled"%3Afalse%7D%5D%2C"queryType"%3A"builder"%7D&relativeTime=30m';
// Mocks
jest.mock('uplot', () => ({
paths: { spline: jest.fn(), bars: jest.fn() },
default: jest.fn(() => ({ paths: { spline: jest.fn(), bars: jest.fn() } })),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string; search: string } => ({
pathname: '',
search: MOCK_SEARCH_PARAMS,
}),
}));
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): { safeNavigate: jest.Mock } => ({
safeNavigate: jest.fn(),
}),
}));
jest.mock('react-router-dom-v5-compat', () => ({
...jest.requireActual('react-router-dom-v5-compat'),
useSearchParams: jest.fn(),
useNavigationType: jest.fn(() => 'PUSH'),
}));
describe('placeWidgetAtBottom', () => {
it('should place widget at (0,0) when layout is empty', () => {
@ -216,3 +257,55 @@ describe('placeWidgetBetweenRows', () => {
]);
});
});
describe('getDefaultWidgetData', () => {
it('should set stackedBarChart to true by default for new panel creation', () => {
const widgetId = 'test-widget-123';
const panelType = PANEL_TYPES.BAR;
const result = getDefaultWidgetData(widgetId, panelType);
expect(result.stackedBarChart).toBe(true);
expect(result.id).toBe(widgetId);
expect(result.panelTypes).toBe(panelType);
});
});
describe('Stacking bar in new panel', () => {
it('New panel should have stack bar - true by default', () => {
// Mock useSearchParams to return the expected values
(useSearchParams as jest.Mock).mockReturnValue([
new URLSearchParams(MOCK_SEARCH_PARAMS),
jest.fn(),
]);
const { container, getByText, getByRole } = render(
<I18nextProvider i18n={i18n}>
<DashboardProvider>
<PreferenceContextProvider>
<NewWidget
selectedGraph={PANEL_TYPES.BAR}
fillSpans={undefined}
yAxisUnit={undefined}
/>
</PreferenceContextProvider>
</DashboardProvider>
</I18nextProvider>,
);
// Verify label is present
expect(getByText('Stack series')).toBeInTheDocument();
// Verify section exists
const section = container.querySelector('section > .stack-chart');
expect(section).toBeInTheDocument();
// Verify switch is present and enabled (ant-switch-checked)
const switchBtn = section?.querySelector('.ant-switch');
expect(switchBtn).toBeInTheDocument();
expect(switchBtn).toHaveClass('ant-switch-checked');
// (Optional) More semantic: verify by role
expect(getByRole('switch')).toBeChecked();
});
});

View File

@ -178,10 +178,6 @@ function NewWidget({
selectedWidget?.yAxisUnit || 'none',
);
const [stacked, setStacked] = useState<boolean>(
selectedWidget?.isStacked || false,
);
const [stackedBarChart, setStackedBarChart] = useState<boolean>(
selectedWidget?.stackedBarChart || false,
);
@ -258,7 +254,6 @@ function NewWidget({
query: currentQuery,
title,
description,
isStacked: stacked,
opacity,
nullZeroValues: selectedNullZeroValue,
yAxisUnit,
@ -292,7 +287,6 @@ function NewWidget({
selectedTracesFields,
softMax,
softMin,
stacked,
thresholds,
title,
yAxisUnit,
@ -494,7 +488,6 @@ function NewWidget({
...(selectedWidget || ({} as Widgets)),
description: selectedWidget?.description || '',
timePreferance: selectedTime.enum,
isStacked: selectedWidget?.isStacked || false,
opacity: selectedWidget?.opacity || '1',
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
title: selectedWidget?.title,
@ -524,7 +517,6 @@ function NewWidget({
...(selectedWidget || ({} as Widgets)),
description: selectedWidget?.description || '',
timePreferance: selectedTime.enum,
isStacked: selectedWidget?.isStacked || false,
opacity: selectedWidget?.opacity || '1',
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
title: selectedWidget?.title,
@ -818,8 +810,6 @@ function NewWidget({
setTitle={setTitle}
description={description}
setDescription={setDescription}
stacked={stacked}
setStacked={setStacked}
stackedBarChart={stackedBarChart}
setStackedBarChart={setStackedBarChart}
opacity={opacity}

View File

@ -543,7 +543,6 @@ export const getDefaultWidgetData = (
id,
title: '',
description: '',
isStacked: false,
nullZeroValues: '',
opacity: '',
panelTypes: name,
@ -554,6 +553,7 @@ export const getDefaultWidgetData = (
timePreferance: 'GLOBAL_TIME',
softMax: null,
softMin: null,
stackedBarChart: true,
selectedLogFields: defaultLogsSelectedColumns.map((field) => ({
...field,
type: field.fieldContext ?? '',

View File

@ -2,7 +2,6 @@ export const tablePanelWidgetQuery = {
id: '727533b0-7718-4f99-a1db-a1875649325c',
title: '',
description: '',
isStacked: false,
nullZeroValues: 'zero',
opacity: '1',
panelTypes: 'table',

View File

@ -2,7 +2,6 @@ export const valuePanelWidget = {
id: 'b8b93086-ef01-47bf-9044-1e7abd583be4',
title: 'signoz latency in ms',
description: '',
isStacked: false,
nullZeroValues: 'zero',
opacity: '1',
panelTypes: 'value',

View File

@ -236,7 +236,6 @@ export const WidgetHeaderProps: any = {
description: '',
fillSpans: false,
id: 'add65f0d-7662-4024-af51-da567759235d',
isStacked: false,
mergeAllActiveQueries: false,
nullZeroValues: 'zero',
opacity: '1',

View File

@ -52,7 +52,6 @@ export const addEmptyWidgetInDashboardJSONWithQuery = (
id: widgetId,
query,
description: '',
isStacked: false,
nullZeroValues: '',
opacity: '',
title: '',

View File

@ -86,7 +86,7 @@ const getSeries = ({
? hiddenGraph[i]
: true,
label,
fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}40` : undefined,
fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}` : undefined,
stroke: color,
width: 2,
spanGaps: true,

View File

@ -14,7 +14,7 @@ describe('Get Series Data', () => {
expect(seriesData.length).toBe(5);
expect(seriesData[1].label).toBe('firstLegend');
expect(seriesData[1].show).toBe(true);
expect(seriesData[1].fill).toBe('#C7158540');
expect(seriesData[1].fill).toBe('#C71585');
expect(seriesData[1].width).toBe(2);
});

View File

@ -39,7 +39,6 @@ export const getWidgetQueryBuilder = ({
}: GetWidgetQueryPropsReturn): Widgets => ({
description: description || '',
id: id || uuid(),
isStacked: false,
nullZeroValues: nullZeroValues || '',
opacity: '1',
panelTypes,

View File

@ -104,7 +104,6 @@ export interface ColumnUnit {
[key: string]: string;
}
export interface IBaseWidget {
isStacked: boolean;
id: string;
panelTypes: PANEL_TYPES;
title: ReactNode;