mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 12:18:58 +08:00
feat: added logarithmic scale option for panels (#7413)
This commit is contained in:
parent
694c185373
commit
bc17a10550
@ -159,6 +159,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.log-scale {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-time-text {
|
.panel-time-text {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
color: var(--bg-vanilla-400);
|
color: var(--bg-vanilla-400);
|
||||||
|
@ -61,6 +61,18 @@ export const panelTypeVsFillSpan: { [key in PANEL_TYPES]: boolean } = {
|
|||||||
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const panelTypeVsLogScale: { [key in PANEL_TYPES]: boolean } = {
|
||||||
|
[PANEL_TYPES.TIME_SERIES]: true,
|
||||||
|
[PANEL_TYPES.VALUE]: false,
|
||||||
|
[PANEL_TYPES.TABLE]: false,
|
||||||
|
[PANEL_TYPES.LIST]: false,
|
||||||
|
[PANEL_TYPES.PIE]: false,
|
||||||
|
[PANEL_TYPES.BAR]: true,
|
||||||
|
[PANEL_TYPES.HISTOGRAM]: false,
|
||||||
|
[PANEL_TYPES.TRACE]: false,
|
||||||
|
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const panelTypeVsYAxisUnit: { [key in PANEL_TYPES]: boolean } = {
|
export const panelTypeVsYAxisUnit: { [key in PANEL_TYPES]: boolean } = {
|
||||||
[PANEL_TYPES.TIME_SERIES]: true,
|
[PANEL_TYPES.TIME_SERIES]: true,
|
||||||
[PANEL_TYPES.VALUE]: true,
|
[PANEL_TYPES.VALUE]: true,
|
||||||
|
@ -10,7 +10,7 @@ import GraphTypes, {
|
|||||||
} from 'container/NewDashboard/ComponentsSlider/menuItems';
|
} from 'container/NewDashboard/ComponentsSlider/menuItems';
|
||||||
import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts';
|
import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { ConciergeBell, Plus } from 'lucide-react';
|
import { ConciergeBell, LineChart, Plus, Spline } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
@ -27,6 +27,7 @@ import {
|
|||||||
panelTypeVsColumnUnitPreferences,
|
panelTypeVsColumnUnitPreferences,
|
||||||
panelTypeVsCreateAlert,
|
panelTypeVsCreateAlert,
|
||||||
panelTypeVsFillSpan,
|
panelTypeVsFillSpan,
|
||||||
|
panelTypeVsLogScale,
|
||||||
panelTypeVsPanelTimePreferences,
|
panelTypeVsPanelTimePreferences,
|
||||||
panelTypeVsSoftMinMax,
|
panelTypeVsSoftMinMax,
|
||||||
panelTypeVsStackingChartPreferences,
|
panelTypeVsStackingChartPreferences,
|
||||||
@ -41,6 +42,12 @@ import YAxisUnitSelector from './YAxisUnitSelector';
|
|||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
|
enum LogScale {
|
||||||
|
LINEAR = 'linear',
|
||||||
|
LOGARITHMIC = 'logarithmic',
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
function RightContainer({
|
function RightContainer({
|
||||||
description,
|
description,
|
||||||
setDescription,
|
setDescription,
|
||||||
@ -71,6 +78,8 @@ function RightContainer({
|
|||||||
setSoftMin,
|
setSoftMin,
|
||||||
columnUnits,
|
columnUnits,
|
||||||
setColumnUnits,
|
setColumnUnits,
|
||||||
|
isLogScale,
|
||||||
|
setIsLogScale,
|
||||||
}: RightContainerProps): JSX.Element {
|
}: RightContainerProps): JSX.Element {
|
||||||
const onChangeHandler = useCallback(
|
const onChangeHandler = useCallback(
|
||||||
(setFunc: Dispatch<SetStateAction<string>>, value: string) => {
|
(setFunc: Dispatch<SetStateAction<string>>, value: string) => {
|
||||||
@ -87,6 +96,7 @@ function RightContainer({
|
|||||||
const allowThreshold = panelTypeVsThreshold[selectedGraph];
|
const allowThreshold = panelTypeVsThreshold[selectedGraph];
|
||||||
const allowSoftMinMax = panelTypeVsSoftMinMax[selectedGraph];
|
const allowSoftMinMax = panelTypeVsSoftMinMax[selectedGraph];
|
||||||
const allowFillSpans = panelTypeVsFillSpan[selectedGraph];
|
const allowFillSpans = panelTypeVsFillSpan[selectedGraph];
|
||||||
|
const allowLogScale = panelTypeVsLogScale[selectedGraph];
|
||||||
const allowYAxisUnit = panelTypeVsYAxisUnit[selectedGraph];
|
const allowYAxisUnit = panelTypeVsYAxisUnit[selectedGraph];
|
||||||
const allowCreateAlerts = panelTypeVsCreateAlert[selectedGraph];
|
const allowCreateAlerts = panelTypeVsCreateAlert[selectedGraph];
|
||||||
const allowBucketConfig = panelTypeVsBucketConfig[selectedGraph];
|
const allowBucketConfig = panelTypeVsBucketConfig[selectedGraph];
|
||||||
@ -293,6 +303,36 @@ function RightContainer({
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{allowLogScale && (
|
||||||
|
<section className="log-scale">
|
||||||
|
<Typography.Text className="typography">Y Axis Scale</Typography.Text>
|
||||||
|
<Select
|
||||||
|
onChange={(value): void => setIsLogScale(value === LogScale.LOGARITHMIC)}
|
||||||
|
value={isLogScale ? LogScale.LOGARITHMIC : LogScale.LINEAR}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
className="panel-type-select"
|
||||||
|
defaultValue={LogScale.LINEAR}
|
||||||
|
>
|
||||||
|
<Option value={LogScale.LINEAR}>
|
||||||
|
<div className="select-option">
|
||||||
|
<div className="icon">
|
||||||
|
<LineChart size={16} />
|
||||||
|
</div>
|
||||||
|
<Typography.Text className="display">Linear</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
<Option value={LogScale.LOGARITHMIC}>
|
||||||
|
<div className="select-option">
|
||||||
|
<div className="icon">
|
||||||
|
<Spline size={16} />
|
||||||
|
</div>
|
||||||
|
<Typography.Text className="display">Logarithmic</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
</Select>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{allowCreateAlerts && (
|
{allowCreateAlerts && (
|
||||||
@ -356,6 +396,8 @@ interface RightContainerProps {
|
|||||||
setColumnUnits: Dispatch<SetStateAction<ColumnUnit>>;
|
setColumnUnits: Dispatch<SetStateAction<ColumnUnit>>;
|
||||||
setSoftMin: Dispatch<SetStateAction<number | null>>;
|
setSoftMin: Dispatch<SetStateAction<number | null>>;
|
||||||
setSoftMax: Dispatch<SetStateAction<number | null>>;
|
setSoftMax: Dispatch<SetStateAction<number | null>>;
|
||||||
|
isLogScale: boolean;
|
||||||
|
setIsLogScale: Dispatch<SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
RightContainer.defaultProps = {
|
RightContainer.defaultProps = {
|
||||||
|
@ -170,6 +170,9 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
const [isFillSpans, setIsFillSpans] = useState<boolean>(
|
const [isFillSpans, setIsFillSpans] = useState<boolean>(
|
||||||
selectedWidget?.fillSpans || false,
|
selectedWidget?.fillSpans || false,
|
||||||
);
|
);
|
||||||
|
const [isLogScale, setIsLogScale] = useState<boolean>(
|
||||||
|
selectedWidget?.isLogScale || false,
|
||||||
|
);
|
||||||
const [saveModal, setSaveModal] = useState(false);
|
const [saveModal, setSaveModal] = useState(false);
|
||||||
const [discardModal, setDiscardModal] = useState(false);
|
const [discardModal, setDiscardModal] = useState(false);
|
||||||
|
|
||||||
@ -234,6 +237,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
mergeAllActiveQueries: combineHistogram,
|
mergeAllActiveQueries: combineHistogram,
|
||||||
selectedLogFields,
|
selectedLogFields,
|
||||||
selectedTracesFields,
|
selectedTracesFields,
|
||||||
|
isLogScale,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
@ -255,6 +259,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
bucketCount,
|
bucketCount,
|
||||||
combineHistogram,
|
combineHistogram,
|
||||||
stackedBarChart,
|
stackedBarChart,
|
||||||
|
isLogScale,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const closeModal = (): void => {
|
const closeModal = (): void => {
|
||||||
@ -369,6 +374,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
|
graphType: getGraphType(selectedGraph || selectedWidget.panelTypes),
|
||||||
query: stagedQuery,
|
query: stagedQuery,
|
||||||
fillGaps: selectedWidget.fillSpans || false,
|
fillGaps: selectedWidget.fillSpans || false,
|
||||||
|
isLogScale: selectedWidget.isLogScale || false,
|
||||||
formatForWeb:
|
formatForWeb:
|
||||||
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
|
getGraphTypeForFormat(selectedGraph || selectedWidget.panelTypes) ===
|
||||||
PANEL_TYPES.TABLE,
|
PANEL_TYPES.TABLE,
|
||||||
@ -379,6 +385,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
stagedQuery,
|
stagedQuery,
|
||||||
selectedTime,
|
selectedTime,
|
||||||
selectedWidget.fillSpans,
|
selectedWidget.fillSpans,
|
||||||
|
selectedWidget.isLogScale,
|
||||||
globalSelectedInterval,
|
globalSelectedInterval,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -442,6 +449,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
softMin: selectedWidget?.softMin || 0,
|
softMin: selectedWidget?.softMin || 0,
|
||||||
softMax: selectedWidget?.softMax || 0,
|
softMax: selectedWidget?.softMax || 0,
|
||||||
fillSpans: selectedWidget?.fillSpans,
|
fillSpans: selectedWidget?.fillSpans,
|
||||||
|
isLogScale: selectedWidget?.isLogScale || false,
|
||||||
bucketWidth: selectedWidget?.bucketWidth || 0,
|
bucketWidth: selectedWidget?.bucketWidth || 0,
|
||||||
bucketCount: selectedWidget?.bucketCount || 0,
|
bucketCount: selectedWidget?.bucketCount || 0,
|
||||||
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
||||||
@ -468,6 +476,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
softMin: selectedWidget?.softMin || 0,
|
softMin: selectedWidget?.softMin || 0,
|
||||||
softMax: selectedWidget?.softMax || 0,
|
softMax: selectedWidget?.softMax || 0,
|
||||||
fillSpans: selectedWidget?.fillSpans,
|
fillSpans: selectedWidget?.fillSpans,
|
||||||
|
isLogScale: selectedWidget?.isLogScale || false,
|
||||||
bucketWidth: selectedWidget?.bucketWidth || 0,
|
bucketWidth: selectedWidget?.bucketWidth || 0,
|
||||||
bucketCount: selectedWidget?.bucketCount || 0,
|
bucketCount: selectedWidget?.bucketCount || 0,
|
||||||
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
mergeAllActiveQueries: selectedWidget?.mergeAllActiveQueries || false,
|
||||||
@ -730,6 +739,8 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
selectedWidget={selectedWidget}
|
selectedWidget={selectedWidget}
|
||||||
isFillSpans={isFillSpans}
|
isFillSpans={isFillSpans}
|
||||||
setIsFillSpans={setIsFillSpans}
|
setIsFillSpans={setIsFillSpans}
|
||||||
|
isLogScale={isLogScale}
|
||||||
|
setIsLogScale={setIsLogScale}
|
||||||
softMin={softMin}
|
softMin={softMin}
|
||||||
setSoftMin={setSoftMin}
|
setSoftMin={setSoftMin}
|
||||||
softMax={softMax}
|
softMax={softMax}
|
||||||
|
@ -137,6 +137,7 @@ function UplotPanelWrapper({
|
|||||||
uPlot.tzDate(new Date(timestamp * 1e3), timezone.value),
|
uPlot.tzDate(new Date(timestamp * 1e3), timezone.value),
|
||||||
timezone: timezone.value,
|
timezone: timezone.value,
|
||||||
customSeries,
|
customSeries,
|
||||||
|
isLogScale: widget?.isLogScale,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
widget?.id,
|
widget?.id,
|
||||||
@ -161,6 +162,7 @@ function UplotPanelWrapper({
|
|||||||
customTooltipElement,
|
customTooltipElement,
|
||||||
timezone.value,
|
timezone.value,
|
||||||
customSeries,
|
customSeries,
|
||||||
|
widget?.isLogScale,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ export interface GetUPlotChartOptions {
|
|||||||
tzDate?: (timestamp: number) => Date;
|
tzDate?: (timestamp: number) => Date;
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
customSeries?: (data: QueryData[]) => uPlot.Series[];
|
||||||
|
isLogScale?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** the function converts series A , series B , series C to
|
/** the function converts series A , series B , series C to
|
||||||
@ -164,6 +165,7 @@ export const getUPlotChartOptions = ({
|
|||||||
tzDate,
|
tzDate,
|
||||||
timezone,
|
timezone,
|
||||||
customSeries,
|
customSeries,
|
||||||
|
isLogScale,
|
||||||
}: GetUPlotChartOptions): uPlot.Options => {
|
}: GetUPlotChartOptions): uPlot.Options => {
|
||||||
const timeScaleProps = getXAxisScale(minTimeScale, maxTimeScale);
|
const timeScaleProps = getXAxisScale(minTimeScale, maxTimeScale);
|
||||||
|
|
||||||
@ -220,6 +222,7 @@ export const getUPlotChartOptions = ({
|
|||||||
softMax,
|
softMax,
|
||||||
softMin,
|
softMin,
|
||||||
}),
|
}),
|
||||||
|
distr: isLogScale ? 3 : 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -387,6 +390,6 @@ export const getUPlotChartOptions = ({
|
|||||||
hiddenGraph,
|
hiddenGraph,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
}),
|
}),
|
||||||
axes: getAxes({ isDarkMode, yAxisUnit, panelType }),
|
axes: getAxes({ isDarkMode, yAxisUnit, panelType, isLogScale }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -17,16 +17,19 @@ const getAxes = ({
|
|||||||
isDarkMode,
|
isDarkMode,
|
||||||
yAxisUnit,
|
yAxisUnit,
|
||||||
panelType,
|
panelType,
|
||||||
|
isLogScale,
|
||||||
}: {
|
}: {
|
||||||
isDarkMode: boolean;
|
isDarkMode: boolean;
|
||||||
yAxisUnit?: string;
|
yAxisUnit?: string;
|
||||||
panelType?: PANEL_TYPES;
|
panelType?: PANEL_TYPES;
|
||||||
|
isLogScale?: boolean;
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
}): any => [
|
}): any => [
|
||||||
{
|
{
|
||||||
stroke: isDarkMode ? 'white' : 'black', // Color of the axis line
|
stroke: isDarkMode ? 'white' : 'black', // Color of the axis line
|
||||||
grid: {
|
grid: {
|
||||||
stroke: getGridColor(isDarkMode), // Color of the grid lines
|
stroke: getGridColor(isDarkMode), // Color of the grid lines
|
||||||
width: 0.2, // Width of the grid lines,
|
width: isLogScale ? 0.1 : 0.2, // Width of the grid lines,
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
@ -45,17 +48,20 @@ const getAxes = ({
|
|||||||
stroke: isDarkMode ? 'white' : 'black', // Color of the axis line
|
stroke: isDarkMode ? 'white' : 'black', // Color of the axis line
|
||||||
grid: {
|
grid: {
|
||||||
stroke: getGridColor(isDarkMode), // Color of the grid lines
|
stroke: getGridColor(isDarkMode), // Color of the grid lines
|
||||||
width: 0.2, // Width of the grid lines
|
width: isLogScale ? 0.1 : 0.2, // Width of the grid lines
|
||||||
},
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
// stroke: isDarkMode ? 'white' : 'black', // Color of the tick lines
|
// stroke: isDarkMode ? 'white' : 'black', // Color of the tick lines
|
||||||
width: 0.3, // Width of the tick lines
|
width: 0.3, // Width of the tick lines
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
|
...(isLogScale ? { space: 20 } : {}),
|
||||||
values: (_, t): string[] =>
|
values: (_, t): string[] =>
|
||||||
t.map((v) => {
|
t.map((v) => {
|
||||||
|
if (v === null || v === undefined || Number.isNaN(v)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
const value = getToolTipValue(v.toString(), yAxisUnit);
|
const value = getToolTipValue(v.toString(), yAxisUnit);
|
||||||
|
|
||||||
return `${value}`;
|
return `${value}`;
|
||||||
}),
|
}),
|
||||||
gap: 5,
|
gap: 5,
|
||||||
|
@ -108,6 +108,7 @@ export interface IBaseWidget {
|
|||||||
columnUnits?: ColumnUnit;
|
columnUnits?: ColumnUnit;
|
||||||
selectedLogFields: IField[] | null;
|
selectedLogFields: IField[] | null;
|
||||||
selectedTracesFields: BaseAutocompleteData[] | null;
|
selectedTracesFields: BaseAutocompleteData[] | null;
|
||||||
|
isLogScale?: boolean;
|
||||||
}
|
}
|
||||||
export interface Widgets extends IBaseWidget {
|
export interface Widgets extends IBaseWidget {
|
||||||
query: Query;
|
query: Query;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user