mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 01:15:54 +08:00
feat: per column unit option for table type (#5134)
* feat: base setup for individual column type units * feat: added logic for y axis unit selection * fix: light mode design * feat: fix the mutation of original datasource array
This commit is contained in:
parent
be9c3f0697
commit
2145e353c8
@ -1,12 +1,13 @@
|
|||||||
import { ExclamationCircleFilled } from '@ant-design/icons';
|
import { ExclamationCircleFilled } from '@ant-design/icons';
|
||||||
import { Space, Tooltip } from 'antd';
|
import { Space, Tooltip } from 'antd';
|
||||||
|
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||||
import { Events } from 'constants/events';
|
import { Events } from 'constants/events';
|
||||||
import { QueryTable } from 'container/QueryTable';
|
import { QueryTable } from 'container/QueryTable';
|
||||||
import {
|
import {
|
||||||
createTableColumnsFromQuery,
|
createTableColumnsFromQuery,
|
||||||
RowData,
|
RowData,
|
||||||
} from 'lib/query/createTableColumnsFromQuery';
|
} from 'lib/query/createTableColumnsFromQuery';
|
||||||
import { get, set } from 'lodash-es';
|
import { cloneDeep, get, isEmpty, set } from 'lodash-es';
|
||||||
import { memo, ReactNode, useCallback, useEffect, useMemo } from 'react';
|
import { memo, ReactNode, useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { eventEmitter } from 'utils/getEventEmitter';
|
import { eventEmitter } from 'utils/getEventEmitter';
|
||||||
@ -19,11 +20,12 @@ function GridTableComponent({
|
|||||||
data,
|
data,
|
||||||
query,
|
query,
|
||||||
thresholds,
|
thresholds,
|
||||||
|
columnUnits,
|
||||||
tableProcessedDataRef,
|
tableProcessedDataRef,
|
||||||
...props
|
...props
|
||||||
}: GridTableComponentProps): JSX.Element {
|
}: GridTableComponentProps): JSX.Element {
|
||||||
const { t } = useTranslation(['valueGraph']);
|
const { t } = useTranslation(['valueGraph']);
|
||||||
const { columns, dataSource } = useMemo(
|
const { columns, dataSource: originalDataSource } = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createTableColumnsFromQuery({
|
createTableColumnsFromQuery({
|
||||||
query,
|
query,
|
||||||
@ -31,7 +33,6 @@ function GridTableComponent({
|
|||||||
}),
|
}),
|
||||||
[data, query],
|
[data, query],
|
||||||
);
|
);
|
||||||
|
|
||||||
const createDataInCorrectFormat = useCallback(
|
const createDataInCorrectFormat = useCallback(
|
||||||
(dataSource: RowData[]): RowData[] =>
|
(dataSource: RowData[]): RowData[] =>
|
||||||
dataSource.map((d) => {
|
dataSource.map((d) => {
|
||||||
@ -52,6 +53,35 @@ function GridTableComponent({
|
|||||||
[columns],
|
[columns],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const applyColumnUnits = useCallback(
|
||||||
|
(dataSource: RowData[]): RowData[] => {
|
||||||
|
let mutateDataSource = cloneDeep(dataSource);
|
||||||
|
if (isEmpty(columnUnits)) {
|
||||||
|
return mutateDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutateDataSource = mutateDataSource.map(
|
||||||
|
(val): RowData => {
|
||||||
|
const newValue = val;
|
||||||
|
Object.keys(val).forEach((k) => {
|
||||||
|
if (columnUnits[k]) {
|
||||||
|
newValue[k] = getYAxisFormattedValue(String(val[k]), columnUnits[k]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newValue;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return mutateDataSource;
|
||||||
|
},
|
||||||
|
[columnUnits],
|
||||||
|
);
|
||||||
|
|
||||||
|
const dataSource = useMemo(() => applyColumnUnits(originalDataSource), [
|
||||||
|
applyColumnUnits,
|
||||||
|
originalDataSource,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tableProcessedDataRef) {
|
if (tableProcessedDataRef) {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
@ -5,11 +5,13 @@ import {
|
|||||||
ThresholdProps,
|
ThresholdProps,
|
||||||
} from 'container/NewWidget/RightContainer/Threshold/types';
|
} from 'container/NewWidget/RightContainer/Threshold/types';
|
||||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { ColumnUnit } from 'types/api/dashboard/getAll';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
|
|
||||||
export type GridTableComponentProps = {
|
export type GridTableComponentProps = {
|
||||||
query: Query;
|
query: Query;
|
||||||
thresholds?: ThresholdProps[];
|
thresholds?: ThresholdProps[];
|
||||||
|
columnUnits?: ColumnUnit;
|
||||||
tableProcessedDataRef?: React.MutableRefObject<RowData[]>;
|
tableProcessedDataRef?: React.MutableRefObject<RowData[]>;
|
||||||
} & Pick<LogsExplorerTableProps, 'data'> &
|
} & Pick<LogsExplorerTableProps, 'data'> &
|
||||||
Omit<TableProps<RowData>, 'columns' | 'dataSource'>;
|
Omit<TableProps<RowData>, 'columns' | 'dataSource'>;
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
.column-unit-selector {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-axis-unit-selector {
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.column-unit-selector {
|
||||||
|
.heading {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
import './ColumnUnitSelector.styles.scss';
|
||||||
|
|
||||||
|
import { Typography } from 'antd';
|
||||||
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { ColumnUnit } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
import YAxisUnitSelector from '../YAxisUnitSelector';
|
||||||
|
|
||||||
|
interface ColumnUnitSelectorProps {
|
||||||
|
columnUnits: ColumnUnit;
|
||||||
|
setColumnUnits: Dispatch<SetStateAction<ColumnUnit>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ColumnUnitSelector(
|
||||||
|
props: ColumnUnitSelectorProps,
|
||||||
|
): JSX.Element {
|
||||||
|
const { currentQuery } = useQueryBuilder();
|
||||||
|
|
||||||
|
function getAggregateColumnsNamesAndLabels(): string[] {
|
||||||
|
return currentQuery.builder.queryData.map((q) => q.queryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { columnUnits, setColumnUnits } = props;
|
||||||
|
const aggregationQueries = getAggregateColumnsNamesAndLabels();
|
||||||
|
|
||||||
|
function handleColumnUnitSelect(queryName: string, value: string): void {
|
||||||
|
setColumnUnits((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[queryName]: value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<section className="column-unit-selector">
|
||||||
|
<Typography.Text className="heading">Column Units</Typography.Text>
|
||||||
|
{aggregationQueries.map((query) => (
|
||||||
|
<YAxisUnitSelector
|
||||||
|
defaultValue={columnUnits[query]}
|
||||||
|
onSelect={(value: string): void => handleColumnUnitSelect(query, value)}
|
||||||
|
fieldLabel={query}
|
||||||
|
key={query}
|
||||||
|
handleClear={(): void => {
|
||||||
|
handleColumnUnitSelect(query, '');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
@ -13,14 +13,17 @@ const findCategoryByName = (
|
|||||||
): Record<string, string> | undefined =>
|
): Record<string, string> | undefined =>
|
||||||
find(flattenedCategories, (option) => option.name === searchValue);
|
find(flattenedCategories, (option) => option.name === searchValue);
|
||||||
|
|
||||||
|
type OnSelectType = Dispatch<SetStateAction<string>> | ((val: string) => void);
|
||||||
function YAxisUnitSelector({
|
function YAxisUnitSelector({
|
||||||
defaultValue,
|
defaultValue,
|
||||||
onSelect,
|
onSelect,
|
||||||
fieldLabel,
|
fieldLabel,
|
||||||
|
handleClear,
|
||||||
}: {
|
}: {
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
onSelect: Dispatch<SetStateAction<string>>;
|
onSelect: OnSelectType;
|
||||||
fieldLabel: string;
|
fieldLabel: string;
|
||||||
|
handleClear?: () => void;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const onSelectHandler = (selectedValue: string): void => {
|
const onSelectHandler = (selectedValue: string): void => {
|
||||||
onSelect(findCategoryByName(selectedValue)?.id || '');
|
onSelect(findCategoryByName(selectedValue)?.id || '');
|
||||||
@ -35,7 +38,9 @@ function YAxisUnitSelector({
|
|||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
rootClassName="y-axis-root-popover"
|
rootClassName="y-axis-root-popover"
|
||||||
options={options}
|
options={options}
|
||||||
|
allowClear
|
||||||
defaultValue={findCategoryById(defaultValue)?.name}
|
defaultValue={findCategoryById(defaultValue)?.name}
|
||||||
|
onClear={handleClear}
|
||||||
onSelect={onSelectHandler}
|
onSelect={onSelectHandler}
|
||||||
filterOption={(inputValue, option): boolean => {
|
filterOption={(inputValue, option): boolean => {
|
||||||
if (option) {
|
if (option) {
|
||||||
@ -46,10 +51,14 @@ function YAxisUnitSelector({
|
|||||||
return false;
|
return false;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Input placeholder="Unit" allowClear rootClassName="input" />
|
<Input placeholder="Unit" rootClassName="input" />
|
||||||
</AutoComplete>
|
</AutoComplete>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default YAxisUnitSelector;
|
export default YAxisUnitSelector;
|
||||||
|
|
||||||
|
YAxisUnitSelector.defaultProps = {
|
||||||
|
handleClear: (): void => {},
|
||||||
|
};
|
||||||
|
@ -68,7 +68,7 @@ export const panelTypeVsFillSpan: { [key in PANEL_TYPES]: boolean } = {
|
|||||||
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,
|
||||||
[PANEL_TYPES.TABLE]: true,
|
[PANEL_TYPES.TABLE]: false,
|
||||||
[PANEL_TYPES.LIST]: false,
|
[PANEL_TYPES.LIST]: false,
|
||||||
[PANEL_TYPES.PIE]: false,
|
[PANEL_TYPES.PIE]: false,
|
||||||
[PANEL_TYPES.BAR]: true,
|
[PANEL_TYPES.BAR]: true,
|
||||||
@ -99,3 +99,16 @@ export const panelTypeVsPanelTimePreferences: {
|
|||||||
[PANEL_TYPES.TRACE]: false,
|
[PANEL_TYPES.TRACE]: false,
|
||||||
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const panelTypeVsColumnUnitPreferences: {
|
||||||
|
[key in PANEL_TYPES]: boolean;
|
||||||
|
} = {
|
||||||
|
[PANEL_TYPES.TIME_SERIES]: false,
|
||||||
|
[PANEL_TYPES.VALUE]: false,
|
||||||
|
[PANEL_TYPES.TABLE]: true,
|
||||||
|
[PANEL_TYPES.LIST]: false,
|
||||||
|
[PANEL_TYPES.PIE]: false,
|
||||||
|
[PANEL_TYPES.BAR]: false,
|
||||||
|
[PANEL_TYPES.TRACE]: false,
|
||||||
|
[PANEL_TYPES.EMPTY_WIDGET]: false,
|
||||||
|
} as const;
|
||||||
|
@ -18,10 +18,12 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { Widgets } from 'types/api/dashboard/getAll';
|
import { ColumnUnit, Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
|
import { ColumnUnitSelector } from './ColumnUnitSelector/ColumnUnitSelector';
|
||||||
import {
|
import {
|
||||||
|
panelTypeVsColumnUnitPreferences,
|
||||||
panelTypeVsCreateAlert,
|
panelTypeVsCreateAlert,
|
||||||
panelTypeVsFillSpan,
|
panelTypeVsFillSpan,
|
||||||
panelTypeVsPanelTimePreferences,
|
panelTypeVsPanelTimePreferences,
|
||||||
@ -57,6 +59,8 @@ function RightContainer({
|
|||||||
softMin,
|
softMin,
|
||||||
setSoftMax,
|
setSoftMax,
|
||||||
setSoftMin,
|
setSoftMin,
|
||||||
|
columnUnits,
|
||||||
|
setColumnUnits,
|
||||||
}: RightContainerProps): JSX.Element {
|
}: RightContainerProps): JSX.Element {
|
||||||
const onChangeHandler = useCallback(
|
const onChangeHandler = useCallback(
|
||||||
(setFunc: Dispatch<SetStateAction<string>>, value: string) => {
|
(setFunc: Dispatch<SetStateAction<string>>, value: string) => {
|
||||||
@ -78,6 +82,9 @@ function RightContainer({
|
|||||||
const allowPanelTimePreference =
|
const allowPanelTimePreference =
|
||||||
panelTypeVsPanelTimePreferences[selectedGraph];
|
panelTypeVsPanelTimePreferences[selectedGraph];
|
||||||
|
|
||||||
|
const allowPanelColumnPreference =
|
||||||
|
panelTypeVsColumnUnitPreferences[selectedGraph];
|
||||||
|
|
||||||
const { currentQuery } = useQueryBuilder();
|
const { currentQuery } = useQueryBuilder();
|
||||||
|
|
||||||
const [graphTypes, setGraphTypes] = useState<ItemsProps[]>(GraphTypes);
|
const [graphTypes, setGraphTypes] = useState<ItemsProps[]>(GraphTypes);
|
||||||
@ -179,6 +186,13 @@ function RightContainer({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{allowPanelColumnPreference && (
|
||||||
|
<ColumnUnitSelector
|
||||||
|
columnUnits={columnUnits}
|
||||||
|
setColumnUnits={setColumnUnits}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{allowYAxisUnit && (
|
{allowYAxisUnit && (
|
||||||
<YAxisUnitSelector
|
<YAxisUnitSelector
|
||||||
defaultValue={yAxisUnit}
|
defaultValue={yAxisUnit}
|
||||||
@ -258,6 +272,8 @@ interface RightContainerProps {
|
|||||||
setIsFillSpans: Dispatch<SetStateAction<boolean>>;
|
setIsFillSpans: Dispatch<SetStateAction<boolean>>;
|
||||||
softMin: number | null;
|
softMin: number | null;
|
||||||
softMax: number | null;
|
softMax: number | null;
|
||||||
|
columnUnits: 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>>;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { generatePath, useParams } from 'react-router-dom';
|
import { generatePath, useParams } from 'react-router-dom';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
import { ColumnUnit, Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
||||||
import { IField } from 'types/api/logs/fields';
|
import { IField } from 'types/api/logs/fields';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
@ -156,6 +156,10 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
: selectedWidget?.softMax || 0,
|
: selectedWidget?.softMax || 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [columnUnits, setColumnUnits] = useState<ColumnUnit>(
|
||||||
|
selectedWidget?.columnUnits || {},
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedWidget((prev) => {
|
setSelectedWidget((prev) => {
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
@ -174,11 +178,13 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
softMin,
|
softMin,
|
||||||
softMax,
|
softMax,
|
||||||
fillSpans: isFillSpans,
|
fillSpans: isFillSpans,
|
||||||
|
columnUnits,
|
||||||
selectedLogFields,
|
selectedLogFields,
|
||||||
selectedTracesFields,
|
selectedTracesFields,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
|
columnUnits,
|
||||||
currentQuery,
|
currentQuery,
|
||||||
description,
|
description,
|
||||||
isFillSpans,
|
isFillSpans,
|
||||||
@ -284,6 +290,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
panelTypes: graphType,
|
panelTypes: graphType,
|
||||||
query: currentQuery,
|
query: currentQuery,
|
||||||
thresholds: selectedWidget?.thresholds,
|
thresholds: selectedWidget?.thresholds,
|
||||||
|
columnUnits: selectedWidget?.columnUnits,
|
||||||
softMin: selectedWidget?.softMin || 0,
|
softMin: selectedWidget?.softMin || 0,
|
||||||
softMax: selectedWidget?.softMax || 0,
|
softMax: selectedWidget?.softMax || 0,
|
||||||
fillSpans: selectedWidget?.fillSpans,
|
fillSpans: selectedWidget?.fillSpans,
|
||||||
@ -305,6 +312,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
panelTypes: graphType,
|
panelTypes: graphType,
|
||||||
query: currentQuery,
|
query: currentQuery,
|
||||||
thresholds: selectedWidget?.thresholds,
|
thresholds: selectedWidget?.thresholds,
|
||||||
|
columnUnits: selectedWidget?.columnUnits,
|
||||||
softMin: selectedWidget?.softMin || 0,
|
softMin: selectedWidget?.softMin || 0,
|
||||||
softMax: selectedWidget?.softMax || 0,
|
softMax: selectedWidget?.softMax || 0,
|
||||||
fillSpans: selectedWidget?.fillSpans,
|
fillSpans: selectedWidget?.fillSpans,
|
||||||
@ -483,6 +491,8 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
setStacked={setStacked}
|
setStacked={setStacked}
|
||||||
opacity={opacity}
|
opacity={opacity}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
|
columnUnits={columnUnits}
|
||||||
|
setColumnUnits={setColumnUnits}
|
||||||
setOpacity={setOpacity}
|
setOpacity={setOpacity}
|
||||||
selectedNullZeroValue={selectedNullZeroValue}
|
selectedNullZeroValue={selectedNullZeroValue}
|
||||||
setSelectedNullZeroValue={setSelectedNullZeroValue}
|
setSelectedNullZeroValue={setSelectedNullZeroValue}
|
||||||
|
@ -16,6 +16,7 @@ function TablePanelWrapper({
|
|||||||
data={panelData}
|
data={panelData}
|
||||||
query={widget.query}
|
query={widget.query}
|
||||||
thresholds={thresholds}
|
thresholds={thresholds}
|
||||||
|
columnUnits={widget.columnUnits}
|
||||||
tableProcessedDataRef={tableProcessedDataRef}
|
tableProcessedDataRef={tableProcessedDataRef}
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
{...GRID_TABLE_CONFIG}
|
{...GRID_TABLE_CONFIG}
|
||||||
|
@ -83,6 +83,9 @@ export interface WidgetRow {
|
|||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ColumnUnit {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
export interface IBaseWidget {
|
export interface IBaseWidget {
|
||||||
isStacked: boolean;
|
isStacked: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
@ -98,6 +101,7 @@ export interface IBaseWidget {
|
|||||||
softMin: number | null;
|
softMin: number | null;
|
||||||
softMax: number | null;
|
softMax: number | null;
|
||||||
fillSpans?: boolean;
|
fillSpans?: boolean;
|
||||||
|
columnUnits?: ColumnUnit;
|
||||||
selectedLogFields: IField[] | null;
|
selectedLogFields: IField[] | null;
|
||||||
selectedTracesFields: BaseAutocompleteData[] | null;
|
selectedTracesFields: BaseAutocompleteData[] | null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user