mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-05 07:20:40 +08:00

* feat: dashboard panel grouping initial setup * feat: added panel map to the dashboard response and subsequent types for the same * feat: added panel map to the dashboard response and subsequent types for the same * feat: added settings modal * feat: handle panel collapse and open changes * feat: handle creating panel map when dashboard layout changes * feat: handle creating panel map when dashboard layout changes * feat: refactor code * feat: handle multiple collapsable rows * fix: type issues * feat: handle row collapse button and scroll * feat: handle y axis movement for rows * feat: handle delete row * feat: handle settings name change * feat: disable collapse/uncollapse when dashboard loading to avoid async states * feat: decrease the height of the grouping row * fix: row height management * fix: handle empty row case * feat: remove resize handle from the row * feat: handle re-arrangement of panels * feat: increase height of default new widget * feat: added safety checks
408 lines
9.7 KiB
TypeScript
408 lines
9.7 KiB
TypeScript
// ** Helpers
|
|
import { createIdFromObjectFields } from 'lib/createIdFromObjectFields';
|
|
import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderItemName';
|
|
import {
|
|
AutocompleteType,
|
|
BaseAutocompleteData,
|
|
DataTypes,
|
|
LocalDataType,
|
|
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
|
import {
|
|
HavingForm,
|
|
IBuilderFormula,
|
|
IBuilderQuery,
|
|
IClickHouseQuery,
|
|
IPromQLQuery,
|
|
Query,
|
|
QueryState,
|
|
TagFilter,
|
|
} from 'types/api/queryBuilder/queryBuilderData';
|
|
import { EQueryType } from 'types/common/dashboard';
|
|
import {
|
|
BoolOperators,
|
|
DataSource,
|
|
LogsAggregatorOperator,
|
|
MetricAggregateOperator,
|
|
NumberOperators,
|
|
QueryAdditionalFilter,
|
|
QueryBuilderData,
|
|
ReduceOperators,
|
|
StringOperators,
|
|
TracesAggregatorOperator,
|
|
} from 'types/common/queryBuilder';
|
|
import { SelectOption } from 'types/common/select';
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
import {
|
|
logsAggregateOperatorOptions,
|
|
metricAggregateOperatorOptions,
|
|
metricsGaugeAggregateOperatorOptions,
|
|
metricsGaugeSpaceAggregateOperatorOptions,
|
|
metricsHistogramSpaceAggregateOperatorOptions,
|
|
metricsSumAggregateOperatorOptions,
|
|
metricsSumSpaceAggregateOperatorOptions,
|
|
tracesAggregateOperatorOptions,
|
|
} from './queryBuilderOperators';
|
|
|
|
export const MAX_FORMULAS = 20;
|
|
export const MAX_QUERIES = 26;
|
|
|
|
export const idDivider = '--';
|
|
export const selectValueDivider = '__';
|
|
|
|
export const baseAutoCompleteIdKeysOrder: (keyof Omit<
|
|
BaseAutocompleteData,
|
|
'id' | 'isJSON'
|
|
>)[] = ['key', 'dataType', 'type', 'isColumn'];
|
|
|
|
export const autocompleteType: Record<AutocompleteType, AutocompleteType> = {
|
|
resource: 'resource',
|
|
tag: 'tag',
|
|
'': '',
|
|
};
|
|
|
|
export const formulasNames: string[] = Array.from(
|
|
Array(MAX_FORMULAS),
|
|
(_, i) => `F${i + 1}`,
|
|
);
|
|
const alpha: number[] = Array.from(Array(MAX_QUERIES), (_, i) => i + 65);
|
|
export const alphabet: string[] = alpha.map((str) => String.fromCharCode(str));
|
|
|
|
export enum QueryBuilderKeys {
|
|
GET_AGGREGATE_ATTRIBUTE = 'GET_AGGREGATE_ATTRIBUTE',
|
|
GET_AGGREGATE_KEYS = 'GET_AGGREGATE_KEYS',
|
|
}
|
|
|
|
export const mapOfOperators = {
|
|
metrics: metricAggregateOperatorOptions,
|
|
logs: logsAggregateOperatorOptions,
|
|
traces: tracesAggregateOperatorOptions,
|
|
};
|
|
|
|
export const metricsOperatorsByType = {
|
|
Sum: metricsSumAggregateOperatorOptions,
|
|
Gauge: metricsGaugeAggregateOperatorOptions,
|
|
};
|
|
|
|
export const metricsSpaceAggregationOperatorsByType = {
|
|
Sum: metricsSumSpaceAggregateOperatorOptions,
|
|
Gauge: metricsGaugeSpaceAggregateOperatorOptions,
|
|
Histogram: metricsHistogramSpaceAggregateOperatorOptions,
|
|
ExponentialHistogram: metricsHistogramSpaceAggregateOperatorOptions,
|
|
};
|
|
|
|
export const mapOfQueryFilters: Record<DataSource, QueryAdditionalFilter[]> = {
|
|
metrics: [
|
|
// eslint-disable-next-line sonarjs/no-duplicate-string
|
|
{ text: 'Aggregation interval', field: 'stepInterval' },
|
|
{ text: 'Having', field: 'having' },
|
|
],
|
|
logs: [
|
|
{ text: 'Order by', field: 'orderBy' },
|
|
{ text: 'Limit', field: 'limit' },
|
|
{ text: 'Having', field: 'having' },
|
|
{ text: 'Aggregation interval', field: 'stepInterval' },
|
|
],
|
|
traces: [
|
|
{ text: 'Order by', field: 'orderBy' },
|
|
{ text: 'Limit', field: 'limit' },
|
|
{ text: 'Having', field: 'having' },
|
|
{ text: 'Aggregation interval', field: 'stepInterval' },
|
|
],
|
|
};
|
|
|
|
const commonFormulaFilters: QueryAdditionalFilter[] = [
|
|
{
|
|
text: 'Having',
|
|
field: 'having',
|
|
},
|
|
{ text: 'Order by', field: 'orderBy' },
|
|
{ text: 'Limit', field: 'limit' },
|
|
];
|
|
|
|
export const mapOfFormulaToFilters: Record<
|
|
DataSource,
|
|
QueryAdditionalFilter[]
|
|
> = {
|
|
metrics: commonFormulaFilters,
|
|
logs: commonFormulaFilters,
|
|
traces: commonFormulaFilters,
|
|
};
|
|
|
|
export const REDUCE_TO_VALUES: SelectOption<ReduceOperators, string>[] = [
|
|
{ value: 'last', label: 'Latest of values in timeframe' },
|
|
{ value: 'sum', label: 'Sum of values in timeframe' },
|
|
{ value: 'avg', label: 'Average of values in timeframe' },
|
|
{ value: 'max', label: 'Max of values in timeframe' },
|
|
{ value: 'min', label: 'Min of values in timeframe' },
|
|
];
|
|
|
|
export const initialHavingValues: HavingForm = {
|
|
columnName: '',
|
|
op: '',
|
|
value: [],
|
|
};
|
|
|
|
export const initialAutocompleteData: BaseAutocompleteData = {
|
|
id: createIdFromObjectFields(
|
|
{ dataType: null, key: '', isColumn: null, type: null },
|
|
baseAutoCompleteIdKeysOrder,
|
|
),
|
|
dataType: DataTypes.EMPTY,
|
|
key: '',
|
|
isColumn: false,
|
|
type: '',
|
|
isJSON: false,
|
|
};
|
|
|
|
export const initialFilters: TagFilter = {
|
|
items: [],
|
|
op: 'AND',
|
|
};
|
|
|
|
export const initialQueryBuilderFormValues: IBuilderQuery = {
|
|
dataSource: DataSource.METRICS,
|
|
queryName: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
|
aggregateOperator: MetricAggregateOperator.COUNT,
|
|
aggregateAttribute: initialAutocompleteData,
|
|
timeAggregation: MetricAggregateOperator.RATE,
|
|
spaceAggregation: MetricAggregateOperator.SUM,
|
|
functions: [],
|
|
filters: { items: [], op: 'AND' },
|
|
expression: createNewBuilderItemName({
|
|
existNames: [],
|
|
sourceNames: alphabet,
|
|
}),
|
|
disabled: false,
|
|
having: [],
|
|
stepInterval: 60,
|
|
limit: null,
|
|
orderBy: [],
|
|
groupBy: [],
|
|
legend: '',
|
|
reduceTo: 'avg',
|
|
};
|
|
|
|
const initialQueryBuilderFormLogsValues: IBuilderQuery = {
|
|
...initialQueryBuilderFormValues,
|
|
aggregateOperator: LogsAggregatorOperator.COUNT,
|
|
dataSource: DataSource.LOGS,
|
|
};
|
|
|
|
const initialQueryBuilderFormTracesValues: IBuilderQuery = {
|
|
...initialQueryBuilderFormValues,
|
|
aggregateOperator: TracesAggregatorOperator.COUNT,
|
|
dataSource: DataSource.TRACES,
|
|
};
|
|
|
|
export const initialQueryBuilderFormValuesMap: Record<
|
|
DataSource,
|
|
IBuilderQuery
|
|
> = {
|
|
metrics: initialQueryBuilderFormValues,
|
|
logs: initialQueryBuilderFormLogsValues,
|
|
traces: initialQueryBuilderFormTracesValues,
|
|
};
|
|
|
|
export const initialFormulaBuilderFormValues: IBuilderFormula = {
|
|
queryName: createNewBuilderItemName({
|
|
existNames: [],
|
|
sourceNames: formulasNames,
|
|
}),
|
|
expression: '',
|
|
disabled: false,
|
|
legend: '',
|
|
};
|
|
|
|
export const initialQueryPromQLData: IPromQLQuery = {
|
|
name: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
|
query: '',
|
|
legend: '',
|
|
disabled: false,
|
|
};
|
|
|
|
export const initialClickHouseData: IClickHouseQuery = {
|
|
name: createNewBuilderItemName({ existNames: [], sourceNames: alphabet }),
|
|
legend: '',
|
|
disabled: false,
|
|
query: '',
|
|
};
|
|
|
|
export const initialQueryBuilderData: QueryBuilderData = {
|
|
queryData: [initialQueryBuilderFormValues],
|
|
queryFormulas: [],
|
|
};
|
|
|
|
export const initialSingleQueryMap: Record<
|
|
EQueryType.PROM | EQueryType.CLICKHOUSE,
|
|
IClickHouseQuery | IPromQLQuery
|
|
> = { clickhouse_sql: initialClickHouseData, promql: initialQueryPromQLData };
|
|
|
|
export const initialQueryState: QueryState = {
|
|
id: uuid(),
|
|
builder: initialQueryBuilderData,
|
|
clickhouse_sql: [initialClickHouseData],
|
|
promql: [initialQueryPromQLData],
|
|
};
|
|
|
|
const initialQueryWithType: Query = {
|
|
...initialQueryState,
|
|
queryType: EQueryType.QUERY_BUILDER,
|
|
};
|
|
|
|
const initialQueryLogsWithType: Query = {
|
|
...initialQueryWithType,
|
|
builder: {
|
|
...initialQueryWithType.builder,
|
|
queryData: [initialQueryBuilderFormValuesMap.logs],
|
|
},
|
|
};
|
|
const initialQueryTracesWithType: Query = {
|
|
...initialQueryWithType,
|
|
builder: {
|
|
...initialQueryWithType.builder,
|
|
queryData: [initialQueryBuilderFormValuesMap.traces],
|
|
},
|
|
};
|
|
|
|
export const initialQueriesMap: Record<DataSource, Query> = {
|
|
metrics: initialQueryWithType,
|
|
logs: initialQueryLogsWithType,
|
|
traces: initialQueryTracesWithType,
|
|
};
|
|
|
|
export const operatorsByTypes: Record<LocalDataType, string[]> = {
|
|
string: Object.values(StringOperators),
|
|
number: Object.values(NumberOperators),
|
|
bool: Object.values(BoolOperators),
|
|
};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
export enum PANEL_TYPES {
|
|
TIME_SERIES = 'graph',
|
|
VALUE = 'value',
|
|
TABLE = 'table',
|
|
LIST = 'list',
|
|
TRACE = 'trace',
|
|
BAR = 'bar',
|
|
PIE = 'pie',
|
|
EMPTY_WIDGET = 'EMPTY_WIDGET',
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
export enum PANEL_GROUP_TYPES {
|
|
ROW = 'row',
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
export enum ATTRIBUTE_TYPES {
|
|
SUM = 'Sum',
|
|
GAUGE = 'Gauge',
|
|
HISTOGRAM = 'Histogram',
|
|
EXPONENTIAL_HISTOGRAM = 'ExponentialHistogram',
|
|
}
|
|
|
|
export type IQueryBuilderState = 'search';
|
|
|
|
export const QUERY_BUILDER_SEARCH_VALUES = {
|
|
MULTIPLY: 'MULTIPLY_VALUE',
|
|
SINGLE: 'SINGLE_VALUE',
|
|
NON: 'NON_VALUE',
|
|
NOT_VALID: 'NOT_VALID',
|
|
};
|
|
|
|
export const OPERATORS = {
|
|
IN: 'IN',
|
|
NIN: 'NOT_IN',
|
|
LIKE: 'LIKE',
|
|
NLIKE: 'NOT_LIKE',
|
|
REGEX: 'REGEX',
|
|
NREGEX: 'NOT_REGEX',
|
|
'=': '=',
|
|
'!=': '!=',
|
|
EXISTS: 'EXISTS',
|
|
NOT_EXISTS: 'NOT_EXISTS',
|
|
CONTAINS: 'CONTAINS',
|
|
NOT_CONTAINS: 'NOT_CONTAINS',
|
|
'>=': '>=',
|
|
'>': '>',
|
|
'<=': '<=',
|
|
'<': '<',
|
|
HAS: 'HAS',
|
|
NHAS: 'NHAS',
|
|
};
|
|
|
|
export const QUERY_BUILDER_OPERATORS_BY_TYPES = {
|
|
string: [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.IN,
|
|
OPERATORS.NIN,
|
|
OPERATORS.LIKE,
|
|
OPERATORS.NLIKE,
|
|
OPERATORS.CONTAINS,
|
|
OPERATORS.NOT_CONTAINS,
|
|
OPERATORS.EXISTS,
|
|
OPERATORS.NOT_EXISTS,
|
|
OPERATORS.REGEX,
|
|
OPERATORS.NREGEX,
|
|
],
|
|
int64: [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.IN,
|
|
OPERATORS.NIN,
|
|
OPERATORS.EXISTS,
|
|
OPERATORS.NOT_EXISTS,
|
|
OPERATORS['>='],
|
|
OPERATORS['>'],
|
|
OPERATORS['<='],
|
|
OPERATORS['<'],
|
|
],
|
|
float64: [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.IN,
|
|
OPERATORS.NIN,
|
|
OPERATORS.EXISTS,
|
|
OPERATORS.NOT_EXISTS,
|
|
OPERATORS['>='],
|
|
OPERATORS['>'],
|
|
OPERATORS['<='],
|
|
OPERATORS['<'],
|
|
],
|
|
bool: [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.EXISTS,
|
|
OPERATORS.NOT_EXISTS,
|
|
],
|
|
universal: [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.IN,
|
|
OPERATORS.NIN,
|
|
OPERATORS.EXISTS,
|
|
OPERATORS.NOT_EXISTS,
|
|
OPERATORS.LIKE,
|
|
OPERATORS.NLIKE,
|
|
OPERATORS['>='],
|
|
OPERATORS['>'],
|
|
OPERATORS['<='],
|
|
OPERATORS['<'],
|
|
OPERATORS.CONTAINS,
|
|
OPERATORS.NOT_CONTAINS,
|
|
],
|
|
};
|
|
|
|
export const HAVING_OPERATORS: string[] = [
|
|
OPERATORS['='],
|
|
OPERATORS['!='],
|
|
OPERATORS.IN,
|
|
OPERATORS.NIN,
|
|
OPERATORS['>='],
|
|
OPERATORS['>'],
|
|
OPERATORS['<='],
|
|
OPERATORS['<'],
|
|
];
|