Merge branch 'develop' into 506-integrate-reactquery-devtools

This commit is contained in:
Palash 2022-07-04 13:10:56 +05:30 committed by GitHub
commit ae5d4326a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 407 additions and 520 deletions

View File

@ -39,7 +39,7 @@ services:
condition: on-failure
query-service:
image: signoz/query-service:0.8.2
image: signoz/query-service:0.9.0
command: ["-config=/root/config/prometheus.yml"]
# ports:
# - "6060:6060" # pprof port
@ -67,7 +67,7 @@ services:
- clickhouse
frontend:
image: signoz/frontend:0.8.2
image: signoz/frontend:0.9.0
deploy:
restart_policy:
condition: on-failure
@ -80,7 +80,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
@ -106,7 +106,7 @@ services:
- clickhouse
otel-collector-metrics:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml

View File

@ -38,7 +38,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
query-service:
image: signoz/query-service:0.8.2
image: signoz/query-service:0.9.0
container_name: query-service
command: ["-config=/root/config/prometheus.yml"]
# ports:
@ -65,7 +65,7 @@ services:
condition: service_healthy
frontend:
image: signoz/frontend:0.8.2
image: signoz/frontend:0.9.0
container_name: frontend
restart: on-failure
depends_on:
@ -77,7 +77,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
@ -98,7 +98,7 @@ services:
condition: service_healthy
otel-collector-metrics:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml

View File

@ -36,9 +36,9 @@ is_mac() {
[[ $OSTYPE == darwin* ]]
}
is_arm64(){
[[ `uname -m` == 'arm64' ]]
}
# is_arm64(){
# [[ `uname -m` == 'arm64' ]]
# }
check_os() {
if is_mac; then
@ -237,11 +237,7 @@ bye() { # Prints a friendly good bye message and exits the script.
echo "🔴 The containers didn't seem to start correctly. Please run the following command to check containers that may have errored out:"
echo ""
if is_arm64; then
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml ps -a"
else
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
fi
echo -e "$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml ps -a"
# echo "Please read our troubleshooting guide https://signoz.io/docs/deployment/docker#troubleshooting"
echo "or reach us for support in #help channel in our Slack Community https://signoz.io/slack"
@ -466,22 +462,14 @@ start_docker
echo ""
echo -e "\n🟡 Pulling the latest container images for SigNoz.\n"
if is_arm64; then
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml pull
else
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull
fi
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml pull
echo ""
echo "🟡 Starting the SigNoz containers. It may take a few minutes ..."
echo
# The docker-compose command does some nasty stuff for the `--detach` functionality. So we add a `|| true` so that the
# script doesn't exit because this command looks like it failed to do it's thing.
if is_arm64; then
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml up --detach --remove-orphans || true
else
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true
fi
$sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml up --detach --remove-orphans || true
wait_for_containers_start 60
echo ""
@ -510,11 +498,7 @@ else
echo -e "🟢 Your frontend is running on http://localhost:3301"
echo ""
if is_arm64; then
echo " To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.arm.yaml down -v"
else
echo " To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
fi
echo " To bring down SigNoz and clean volumes : $sudo_cmd docker-compose -f ./docker/clickhouse-setup/docker-compose.yaml down -v"
echo ""
echo "+++++++++++++++++++++++++++++++++++++++++++++++++"

View File

@ -102,6 +102,11 @@ export const AxiosAlertManagerInstance = axios.create({
export const ApiV2Instance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiV2}`,
});
ApiV2Instance.interceptors.response.use(
interceptorsResponse,
interceptorRejected,
);
ApiV2Instance.interceptors.request.use(interceptorsRequestResponse);
AxiosAlertManagerInstance.interceptors.response.use(
interceptorsResponse,

View File

@ -7,17 +7,13 @@ export const getYAxisFormattedValue = (
let decimalPrecision: number | undefined;
const parsedValue = getValueFormat(format)(
parseFloat(value),
12,
12,
undefined,
undefined,
undefined,
);
try {
const decimalSplitted = parsedValue.text.split('.');
if (
decimalSplitted.length === 1 ||
parseFloat(parsedValue.text) === parseInt(parsedValue.text, 10)
) {
if (decimalSplitted.length === 1) {
decimalPrecision = 0;
} else {
const decimalDigits = decimalSplitted[1].split('');

View File

@ -24,8 +24,11 @@ function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
);
}
TextToolTip.defaultProps = {
url: '',
};
interface TextToolTipProps {
url: string;
url?: string;
text: string;
}

View File

@ -113,20 +113,21 @@ function GridGraph(props: Props): JSX.Element {
errorMessage: '',
loading: true,
}));
const updatedDashboard: Dashboard = {
...selectedDashboard,
data: {
title: data.title,
description: data.description,
name: data.name,
tags: data.tags,
widgets: data.widgets,
layout,
},
uuid: selectedDashboard.uuid,
};
// Save layout only when users has the has the permission to do so.
if (saveLayoutPermission) {
const response = await updateDashboardApi({
data: {
title: data.title,
description: data.description,
name: data.name,
tags: data.tags,
widgets: data.widgets,
layout,
},
uuid: selectedDashboard.uuid,
});
const response = await updateDashboardApi(updatedDashboard);
if (response.statusCode === 200) {
setSaveLayoutState((state) => ({
...state,
@ -134,6 +135,10 @@ function GridGraph(props: Props): JSX.Element {
errorMessage: '',
loading: false,
}));
dispatch({
type: UPDATE_DASHBOARD,
payload: updatedDashboard,
});
} else {
setSaveLayoutState((state) => ({
...state,
@ -153,8 +158,9 @@ function GridGraph(props: Props): JSX.Element {
data.tags,
data.title,
data.widgets,
dispatch,
saveLayoutPermission,
selectedDashboard.uuid,
selectedDashboard,
],
);

View File

@ -36,18 +36,17 @@ export const UpdateDashboard = async ({
nullZeroValues: '',
opacity: '',
panelTypes: graphType,
queryType: 0,
query: {
queryType: EQueryType.QUERY_BUILDER,
promQL: [
{
name: GetQueryName([]),
name: GetQueryName([]) || '',
...PromQLQueryTemplate,
},
],
clickHouse: [
{
name: GetQueryName([]),
name: GetQueryName([]) || '',
...ClickHouseQueryTemplate,
},
],
@ -55,14 +54,14 @@ export const UpdateDashboard = async ({
formulas: [],
queryBuilder: [
{
name: GetQueryName([]),
name: GetQueryName([]) || '',
...QueryBuilderQueryTemplate,
},
],
},
},
queryData: {
data: [],
data: { queryData: [] },
error: false,
errorMessage: '',
loading: false,

View File

@ -73,10 +73,7 @@ function ImportJSON({
...e,
queryData: {
...e.queryData,
data: e.queryData.data.map((queryData) => ({
...queryData,
queryData: [],
})),
data: e.queryData.data,
error: false,
errorMessage: '',
loading: false,

View File

@ -4,7 +4,7 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { PromQLWidgets, Widgets } from 'types/api/dashboard/getAll';
import { PromQLWidgets } from 'types/api/dashboard/getAll';
import MetricReducer from 'types/reducer/metrics';
import { Card, GraphContainer, GraphTitle, Row } from '../styles';

View File

@ -29,7 +29,7 @@ function External({ getWidget }: ExternalProps): JSX.Element {
widget={getWidget([
{
query: `max((sum(rate(signoz_external_call_latency_count{service_name="${servicename}", status_code="STATUS_CODE_ERROR"${resourceAttributePromQLQuery}}[1m]) OR rate(signoz_external_call_latency_count{service_name="${servicename}", http_status_code=~"5.."${resourceAttributePromQLQuery}}[1m]) OR vector(0)) by (http_url))*100/sum(rate(signoz_external_call_latency_count{service_name="${servicename}"${resourceAttributePromQLQuery}}[1m])) by (http_url)) < 1000 OR vector(0)`,
legend,
legend: 'External Call Error Percentage',
},
])}
yAxisUnit="%"

View File

@ -42,7 +42,8 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
urlParams.set(METRICS_PAGE_QUERY_PARAM.endTime, tPlusOne.toString());
history.replace(
`${ROUTES.TRACE
`${
ROUTES.TRACE
}?${urlParams.toString()}&selected={"serviceName":["${servicename}"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&&isFilterExclude={"serviceName":false}&userSelectedFilter={"status":["error","ok"],"serviceName":["${servicename}"]}&spanAggregateCurrentPage=1&spanAggregateOrder=ascend`,
);
};
@ -93,7 +94,8 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
urlParams.set(METRICS_PAGE_QUERY_PARAM.endTime, tPlusOne.toString());
history.replace(
`${ROUTES.TRACE
`${
ROUTES.TRACE
}?${urlParams.toString()}?selected={"serviceName":["${servicename}"],"status":["error"]}&filterToFetchData=["duration","status","serviceName"]&spanAggregateCurrentPage=1&selectedTags=${selectedTraceTags}&isFilterExclude={"serviceName":false,"status":false}&userSelectedFilter={"serviceName":["${servicename}"],"status":["error"]}&spanAggregateCurrentPage=1&spanAggregateOrder=ascend`,
);
};

View File

@ -20,7 +20,7 @@ const getWidget = (query: PromQLWidgets['query']): PromQLWidgets => {
panelTypes: 'TIME_SERIES',
query,
queryData: {
data: [],
data: { queryData: [] },
error: false,
errorMessage: '',
loading: false,

View File

@ -5,7 +5,7 @@ export const AggregateFunctions = Object.keys(EAggregateOperator)
.map((key) => {
return {
label: key,
value: EAggregateOperator[key],
value: EAggregateOperator[key as keyof typeof EAggregateOperator],
};
});

View File

@ -10,13 +10,21 @@ import React, { useState } from 'react';
import { QueryWrapper } from '../styles';
interface IQueryHeaderProps {
disabled: boolean;
onDisable: VoidFunction;
name: string;
onDelete: VoidFunction;
children: React.ReactNode;
}
function QueryHeader({
disabled,
onDisable,
name,
onDelete,
children,
}): JSX.Element {
}: IQueryHeaderProps): JSX.Element {
const [collapse, setCollapse] = useState(false);
return (
<QueryWrapper>

View File

@ -2,23 +2,31 @@ import { PlusOutlined } from '@ant-design/icons';
import { ClickHouseQueryTemplate } from 'constants/dashboard';
import GetQueryName from 'lib/query/GetQueryName';
import React from 'react';
import { Query } from 'types/api/dashboard/getAll';
import { WIDGET_CLICKHOUSE_QUERY_KEY_NAME } from '../../constants';
import { QueryButton } from '../../styles';
import { IHandleUpdatedQuery } from '../../types';
import ClickHouseQueryBuilder from './query';
import { IClickHouseQueryHandleChange } from './types';
interface IClickHouseQueryContainerProps {
queryData: Query;
updateQueryData: (args: IHandleUpdatedQuery) => void;
clickHouseQueries: Query['clickHouse'];
}
function ClickHouseQueryContainer({
queryData,
updateQueryData,
clickHouseQueries,
}): JSX.Element | null {
}: IClickHouseQueryContainerProps): JSX.Element | null {
const handleClickHouseQueryChange = ({
queryIndex,
rawQuery,
legend,
toggleDisable,
toggleDelete,
}): void => {
}: IClickHouseQueryHandleChange): void => {
const allQueries = queryData[WIDGET_CLICKHOUSE_QUERY_KEY_NAME];
const currentIndexQuery = allQueries[queryIndex];
@ -40,7 +48,7 @@ function ClickHouseQueryContainer({
};
const addQueryHandler = (): void => {
queryData[WIDGET_CLICKHOUSE_QUERY_KEY_NAME].push({
name: GetQueryName(queryData[WIDGET_CLICKHOUSE_QUERY_KEY_NAME]),
name: GetQueryName(queryData[WIDGET_CLICKHOUSE_QUERY_KEY_NAME]) || '',
...ClickHouseQueryTemplate,
});
updateQueryData({ updatedQuery: { ...queryData } });

View File

@ -1,14 +1,22 @@
import { Input } from 'antd';
import MonacoEditor from 'components/Editor';
import React from 'react';
import { IClickHouseQuery } from 'types/api/dashboard/getAll';
import QueryHeader from '../QueryHeader';
import { IClickHouseQueryHandleChange } from './types';
interface IClickHouseQueryBuilderProps {
queryData: IClickHouseQuery;
queryIndex: number;
handleQueryChange: (args: IClickHouseQueryHandleChange) => void;
}
function ClickHouseQueryBuilder({
queryData,
queryIndex,
handleQueryChange,
}): JSX.Element | null {
}: IClickHouseQueryBuilderProps): JSX.Element | null {
if (queryData === undefined) {
return null;
}
@ -26,7 +34,6 @@ function ClickHouseQueryBuilder({
>
<MonacoEditor
language="sql"
theme="vs-dark"
height="200px"
onChange={(value): void =>
handleQueryChange({ queryIndex, rawQuery: value })

View File

@ -0,0 +1,9 @@
import { IClickHouseQuery } from 'types/api/dashboard/getAll';
export interface IClickHouseQueryHandleChange {
queryIndex: number;
rawQuery?: IClickHouseQuery['rawQuery'];
legend?: IClickHouseQuery['legend'];
toggleDisable?: IClickHouseQuery['disabled'];
toggleDelete?: boolean;
}

View File

@ -1,95 +0,0 @@
import {
DeleteOutlined,
DownOutlined,
EyeFilled,
RightOutlined,
} from '@ant-design/icons';
import { Button, Row } from 'antd';
import MonacoEditor from 'components/Editor';
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app';
import { QueryBuilderWrapper, QueryWrapper } from '../styles';
import { TQueryCategories } from '../types';
import PromQLQueryBuilder from './promQL/promQL';
import MetricsBuilder from './queryBuilder/query';
function QueryBuilder({
name,
onDelete,
queryCategory,
queryData,
updateQueryData,
}: QueryBuilderProps): JSX.Element {
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const [hideFromUI, setHideFromUI] = useState<boolean>(false);
const handleHideFromUI = (): void => {
setHideFromUI(!hideFromUI);
};
const handleClickhouseQueryChange = (clickHouseQuery): void => {
if (clickHouseQuery !== null) {
queryData.clickHouseQuery = clickHouseQuery;
}
updateQueryData(queryData);
};
const handlePromQLQueryChange = ({ query, legend }): void => {
if (query) queryData.promQL.query = query;
if (legend) queryData.promQL.legend = legend;
updateQueryData(queryData);
};
return (
<QueryWrapper>
<Row style={{ justifyContent: 'space-between' }}>
<Row>
<Button type="ghost" icon={<EyeFilled />}>
{name}
</Button>
<Button
type="ghost"
icon={hideFromUI ? <RightOutlined /> : <DownOutlined />}
onClick={handleHideFromUI}
/>
</Row>
<Button type="ghost" danger icon={<DeleteOutlined />} onClick={onDelete} />
</Row>
{!hideFromUI && (
<QueryBuilderWrapper isDarkMode={isDarkMode}>
{queryCategory === 0 ? (
<MetricsBuilder
queryData={queryData}
updateQueryData={updateQueryData}
metricName={queryData.queryBuilder.metricName}
/>
) : queryCategory === 1 ? (
<MonacoEditor
language="sql"
theme="vs-dark"
height="200px"
onChange={handleClickhouseQueryChange}
value={queryData.clickHouseQuery}
// options={options}
/>
) : queryCategory === 2 ? (
<PromQLQueryBuilder
query={queryData.promQL.query}
onQueryChange={(value) => handlePromQLQueryChange({ query: value })}
legend={queryData.promQL.legend}
onLegendChange={(value) => handlePromQLQueryChange({ legend: value })}
/>
) : null}
</QueryBuilderWrapper>
)}
</QueryWrapper>
);
}
interface QueryBuilderProps {
queryCategory: TQueryCategories;
name: string;
}
export default QueryBuilder;

View File

@ -2,25 +2,32 @@ import { PlusOutlined } from '@ant-design/icons';
import { PromQLQueryTemplate } from 'constants/dashboard';
import GetQueryName from 'lib/query/GetQueryName';
import React from 'react';
import { IPromQLQuery, Query } from 'types/api/dashboard/getAll';
import { WIDGET_PROMQL_QUERY_KEY_NAME } from '../../constants';
import { QueryButton } from '../../styles';
import { IHandleUpdatedQuery } from '../../types';
import PromQLQueryBuilder from './query';
import { IPromQLQueryHandleChange } from './types';
interface IPromQLQueryContainerProps {
queryData: Query;
updateQueryData: (args: IHandleUpdatedQuery) => void;
promQLQueries: IPromQLQuery[];
}
function PromQLQueryContainer({
queryData,
updateQueryData,
promQLQueries,
onQueryChange,
onQueryAdd,
}): JSX.Element | null {
}: IPromQLQueryContainerProps): JSX.Element | null {
const handlePromQLQueryChange = ({
queryIndex,
query,
legend,
toggleDisable,
toggleDelete,
}): void => {
}: IPromQLQueryHandleChange): void => {
const allQueries = queryData[WIDGET_PROMQL_QUERY_KEY_NAME];
const currentIndexQuery = allQueries[queryIndex];
if (query) currentIndexQuery.query = query;
@ -36,7 +43,7 @@ function PromQLQueryContainer({
};
const addQueryHandler = (): void => {
queryData[WIDGET_PROMQL_QUERY_KEY_NAME].push({
name: GetQueryName(queryData[WIDGET_PROMQL_QUERY_KEY_NAME]),
name: GetQueryName(queryData[WIDGET_PROMQL_QUERY_KEY_NAME]) || '',
...PromQLQueryTemplate,
});
updateQueryData({ updatedQuery: { ...queryData } });
@ -48,7 +55,7 @@ function PromQLQueryContainer({
return (
<>
{promQLQueries.map(
(q, idx): JSX.Element => (
(q: IPromQLQuery, idx: number): JSX.Element => (
<PromQLQueryBuilder
key={q.name}
queryIndex={idx}

View File

@ -1,13 +1,21 @@
import { Input } from 'antd';
import React from 'react';
import { IPromQLQuery } from 'types/api/dashboard/getAll';
import QueryHeader from '../QueryHeader';
import { IPromQLQueryHandleChange } from './types';
interface IPromQLQueryBuilderProps {
queryData: IPromQLQuery;
queryIndex: number;
handleQueryChange: (args: IPromQLQueryHandleChange) => void;
}
function PromQLQueryBuilder({
queryData,
queryIndex,
handleQueryChange,
}): JSX.Element {
}: IPromQLQueryBuilderProps): JSX.Element {
return (
<QueryHeader
name={queryData.name}

View File

@ -0,0 +1,9 @@
import { IPromQLQuery } from 'types/api/dashboard/getAll';
export interface IPromQLQueryHandleChange {
queryIndex: number;
query?: IPromQLQuery['query'];
legend?: IPromQLQuery['legend'];
toggleDisable?: IPromQLQuery['disabled'];
toggleDelete?: boolean;
}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { QueryChipContainer, QueryChipItem } from './styles';
import { IMetricBuilderTagKeyQuery } from './types';
import { ITagKeyValueQuery } from './types';
interface IQueryChipProps {
queryData: IMetricBuilderTagKeyQuery;
queryData: ITagKeyValueQuery;
onClose: (id: string) => void;
disabled: boolean;
disabled?: boolean;
}
export default function QueryChip({
@ -29,3 +29,6 @@ export default function QueryChip({
</QueryChipContainer>
);
}
QueryChip.defaultProps = {
disabled: false,
};

View File

@ -5,13 +5,14 @@ import { map } from 'lodash-es';
import React, { useCallback, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { IMetricsBuilderQuery } from 'types/api/dashboard/getAll';
import AppReducer from 'types/reducer/app';
import { v4 as uuid } from 'uuid';
import { ResourceAttributesFilterMachine } from './MetricTagKey.machine';
import QueryChip from './QueryChip';
import { QueryChipItem, SearchContainer } from './styles';
import { IMetricBuilderTagKeyQuery, IOption } from './types';
import { IOption, ITagKeyValueQuery } from './types';
import {
createQuery,
GetTagKeys,
@ -20,16 +21,22 @@ import {
SingleValueOperators,
} from './utils';
interface IMetricTagKeyFilterProps {
metricName: IMetricsBuilderQuery['metricName'];
onSetQuery: (args: IMetricsBuilderQuery['tagFilters']['items']) => void;
selectedTagFilters: IMetricsBuilderQuery['tagFilters']['items'];
}
function MetricTagKeyFilter({
metricName,
onSetQuery,
selectedTagFilters: selectedTagQueries,
}): JSX.Element | null {
}: IMetricTagKeyFilterProps): JSX.Element | null {
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const [loading, setLoading] = useState(true);
const [selectedValues, setSelectedValues] = useState<string[]>([]);
const [staging, setStaging] = useState<string[]>([]);
const [queries, setQueries] = useState<IMetricBuilderTagKeyQuery[]>([]);
const [queries, setQueries] = useState<ITagKeyValueQuery[]>([]);
const [optionsData, setOptionsData] = useState<{
mode: undefined | 'tags' | 'multiple';
options: IOption[];
@ -39,7 +46,7 @@ function MetricTagKeyFilter({
});
const dispatchQueries = (
updatedQueries: IMetricBuilderTagKeyQuery[],
updatedQueries: IMetricsBuilderQuery['tagFilters']['items'],
): void => {
onSetQuery(updatedQueries);
setQueries(updatedQueries);
@ -54,7 +61,7 @@ function MetricTagKeyFilter({
actions: {
onSelectTagKey: () => {
handleLoading(true);
GetTagKeys(metricName)
GetTagKeys(metricName || '')
.then((tagKeys) => setOptionsData({ options: tagKeys, mode: undefined }))
.finally(() => {
handleLoading(false);
@ -66,7 +73,7 @@ function MetricTagKeyFilter({
onSelectTagValue: () => {
handleLoading(true);
GetTagValues(staging[0], metricName)
GetTagValues(staging[0], metricName || '')
.then((tagValuesOptions) =>
setOptionsData({ options: tagValuesOptions, mode: 'tags' }),
)
@ -113,16 +120,17 @@ function MetricTagKeyFilter({
handleBlur();
}, [handleBlur, metricName]);
const handleChange = (value: never): void => {
const handleChange = (value: never | string[]): void => {
if (!optionsData.mode) {
setStaging((prevStaging) => [...prevStaging, value]);
setStaging((prevStaging) => [...prevStaging, String(value)]);
setSelectedValues([]);
send('NEXT');
return;
}
if (
state.value === 'TagValue' &&
SingleValueOperators.includes(staging[staging.length - 1])
SingleValueOperators.includes(staging[staging.length - 1]) &&
Array.isArray(value)
) {
setSelectedValues([value[value.length - 1]]);
return;
@ -142,12 +150,6 @@ function MetricTagKeyFilter({
setSelectedValues([]);
};
const disabledOrEmpty = !!(
queries.length ||
staging.length ||
selectedValues.length
);
return (
<SearchContainer isDarkMode={isDarkMode}>
<div style={{ display: 'inline-flex', flexWrap: 'wrap' }}>
@ -162,7 +164,7 @@ function MetricTagKeyFilter({
)}
</div>
<div>
{map(staging, (item, idx) => {
{map(staging, (item) => {
return <QueryChipItem key={uuid()}>{item}</QueryChipItem>;
})}
</div>

View File

@ -4,7 +4,7 @@ import styled from 'styled-components';
export const SearchContainer = styled.div<{
isDarkMode: boolean;
disabled: boolean;
disabled?: boolean;
}>`
background: ${({ isDarkMode }): string => (isDarkMode ? '#000' : '#fff')};
flex: 1;

View File

@ -9,3 +9,10 @@ export interface IMetricBuilderTagKeyQuery {
operator: string;
tagValue: string[];
}
export interface ITagKeyValueQuery {
id: string;
key: string;
op: string;
value: string[];
}

View File

@ -5,7 +5,7 @@ import {
import { v4 as uuid } from 'uuid';
import { TagKeyOperator } from '../../Options';
import { IMetricBuilderTagKeyQuery, IOption } from './types';
import { IOption, ITagKeyValueQuery } from './types';
export const OperatorSchema: IOption[] = TagKeyOperator;
@ -40,12 +40,12 @@ export const GetTagValues = async (
export const createQuery = (
selectedItems: Array<string | string[]> = [],
): IMetricBuilderTagKeyQuery | null => {
): ITagKeyValueQuery | null => {
if (selectedItems.length === 3) {
return {
id: uuid().slice(0, 8),
key: selectedItems[0] as string,
op: selectedItems[1] as string,
key: typeof selectedItems[0] === 'string' ? selectedItems[0] : '',
op: typeof selectedItems[1] === 'string' ? selectedItems[1] : '',
value: selectedItems[2] as string[],
};
}

View File

@ -1,15 +1,22 @@
import { Input } from 'antd';
import React from 'react';
import { IMetricsBuilderFormula } from 'types/api/dashboard/getAll';
import QueryHeader from '../QueryHeader';
import { IQueryBuilderFormulaHandleChange } from './types';
const { TextArea } = Input;
interface IMetricsBuilderFormulaProps {
formulaData: IMetricsBuilderFormula;
formulaIndex: number;
handleFormulaChange: (args: IQueryBuilderFormulaHandleChange) => void;
}
function MetricsBuilderFormula({
formulaData,
formulaIndex,
handleFormulaChange,
}): JSX.Element {
}: IMetricsBuilderFormulaProps): JSX.Element {
return (
<QueryHeader
name={formulaData.name}

View File

@ -4,25 +4,39 @@ import {
QueryBuilderFormulaTemplate,
QueryBuilderQueryTemplate,
} from 'constants/dashboard';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import GetFormulaName from 'lib/query/GetFormulaName';
import GetQueryName from 'lib/query/GetQueryName';
import React from 'react';
import { Query } from 'types/api/dashboard/getAll';
import {
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME,
WIDGET_QUERY_BUILDER_QUERY_KEY_NAME,
} from '../../constants';
import { QueryButton } from '../../styles';
import { IHandleUpdatedQuery } from '../../types';
import MetricsBuilderFormula from './formula';
import MetricsBuilder from './query';
import {
IQueryBuilderFormulaHandleChange,
IQueryBuilderQueryHandleChange,
} from './types';
import { canCreateQueryAndFormula } from './utils';
interface IQueryBuilderQueryContainerProps {
queryData: Query;
updateQueryData: (args: IHandleUpdatedQuery) => void;
metricsBuilderQueries: Query['metricsBuilder'];
selectedGraph: GRAPH_TYPES;
}
function QueryBuilderQueryContainer({
queryData,
updateQueryData,
metricsBuilderQueries,
selectedGraph,
}): JSX.Element | null {
}: IQueryBuilderQueryContainerProps): JSX.Element | null {
const handleQueryBuilderQueryChange = ({
queryIndex,
aggregateFunction,
@ -33,7 +47,7 @@ function QueryBuilderQueryContainer({
toggleDisable,
toggleDelete,
reduceTo,
}): void => {
}: IQueryBuilderQueryHandleChange): void => {
const allQueries =
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME].queryBuilder;
const currentIndexQuery = allQueries[queryIndex];
@ -73,7 +87,7 @@ function QueryBuilderQueryContainer({
expression,
toggleDisable,
toggleDelete,
}): void => {
}: IQueryBuilderFormulaHandleChange): void => {
const allFormulas =
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME][
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME
@ -102,9 +116,9 @@ function QueryBuilderQueryContainer({
return;
}
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME].queryBuilder.push({
name: GetQueryName(
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME].queryBuilder,
),
name:
GetQueryName(queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME].queryBuilder) ||
'',
...QueryBuilderQueryTemplate,
});
updateQueryData({ updatedQuery: { ...queryData } });
@ -121,11 +135,12 @@ function QueryBuilderQueryContainer({
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME][
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME
].push({
name: GetFormulaName(
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME][
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME
],
),
name:
GetFormulaName(
queryData[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME][
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME
],
) || '',
...QueryBuilderFormulaTemplate,
});
updateQueryData({ updatedQuery: { ...queryData } });

View File

@ -2,28 +2,40 @@ import { AutoComplete, Col, Input, Row, Select, Spin } from 'antd';
import { getMetricName } from 'api/metrics/getMetricName';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import React, { useEffect, useState } from 'react';
import { IMetricsBuilderQuery } from 'types/api/dashboard/getAll';
import { EReduceOperator } from 'types/common/dashboard';
import { TQueryCategories } from '../../types';
import { AggregateFunctions } from '../Options';
import QueryHeader from '../QueryHeader';
import MetricTagKeyFilter from './MetricTagKeyFilter';
import { IOption } from './MetricTagKeyFilter/types';
import { GetTagKeys } from './MetricTagKeyFilter/utils';
import { IQueryBuilderQueryHandleChange } from './types';
const { Option } = Select;
function MetricsBuilder({
queryData,
queryIndex,
handleQueryChange,
selectedGraph,
}: QueryBuilderProps): JSX.Element {
const [groupByOptions, setGroupByOptions] = useState([]);
const [metricName, setMetricName] = useState(queryData.metricName);
const [metricNameList, setMetricNameList] = useState([]);
interface IMetricsBuilderProps {
queryIndex: number;
selectedGraph: GRAPH_TYPES;
queryData: IMetricsBuilderQuery;
handleQueryChange: (args: IQueryBuilderQueryHandleChange) => void;
}
function MetricsBuilder({
queryIndex,
selectedGraph,
queryData,
handleQueryChange,
}: IMetricsBuilderProps): JSX.Element {
const [groupByOptions, setGroupByOptions] = useState<IOption[]>([]);
const [metricName, setMetricName] = useState<string | null>(
queryData.metricName,
);
const [metricNameList, setMetricNameList] = useState<string[]>([]);
const [metricNameLoading, setMetricNameLoading] = useState(false);
const handleMetricNameSelect = (e): void => {
const handleMetricNameSelect = (e: string): void => {
handleQueryChange({ queryIndex, metricName: e });
setMetricName(e);
};
@ -51,7 +63,7 @@ function MetricsBuilder({
};
useEffect(() => {
GetTagKeys(metricName).then((tagKeys) => {
GetTagKeys(metricName || '').then((tagKeys) => {
setGroupByOptions(tagKeys);
});
}, [metricName]);
@ -120,7 +132,9 @@ function MetricsBuilder({
<MetricTagKeyFilter
metricName={metricName}
selectedTagFilters={queryData.tagFilters.items}
onSetQuery={(updatedTagFilters): void =>
onSetQuery={(
updatedTagFilters: IMetricsBuilderQuery['tagFilters']['items'],
): void =>
handleQueryChange({ queryIndex, tagFilters: updatedTagFilters })
}
/>
@ -166,9 +180,13 @@ function MetricsBuilder({
.filter((op) => !(parseInt(op, 10) >= 0))
.map((op) => ({
label: op,
value: EReduceOperator[op],
value: EReduceOperator[op as keyof typeof EReduceOperator],
}))}
defaultValue={EReduceOperator[queryData.reduceTo]}
defaultValue={
EReduceOperator[
(queryData.reduceTo as unknown) as keyof typeof EReduceOperator
]
}
onChange={(e): void => {
handleQueryChange({ queryIndex, reduceTo: e });
}}
@ -193,8 +211,4 @@ function MetricsBuilder({
);
}
interface QueryBuilderProps {
selectedGraph: GRAPH_TYPES;
queryCategory: TQueryCategories;
}
export default MetricsBuilder;

View File

@ -0,0 +1,23 @@
import {
IMetricsBuilderFormula,
IMetricsBuilderQuery,
} from 'types/api/dashboard/getAll';
export interface IQueryBuilderQueryHandleChange {
queryIndex: number;
aggregateFunction?: IMetricsBuilderQuery['aggregateOperator'];
metricName?: IMetricsBuilderQuery['metricName'];
tagFilters?: IMetricsBuilderQuery['tagFilters']['items'];
groupBy?: IMetricsBuilderQuery['groupBy'];
legend?: IMetricsBuilderQuery['legend'];
toggleDisable?: boolean;
toggleDelete?: boolean;
reduceTo?: IMetricsBuilderQuery['reduceTo'];
}
export interface IQueryBuilderFormulaHandleChange {
formulaIndex: number;
expression?: IMetricsBuilderFormula['expression'];
toggleDisable?: IMetricsBuilderFormula['disabled'];
toggleDelete?: boolean;
}

View File

@ -1,3 +1,5 @@
import { Query } from 'types/api/dashboard/getAll';
import {
WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME,
WIDGET_QUERY_BUILDER_QUERY_KEY_NAME,
@ -5,7 +7,7 @@ import {
const QUERY_AND_FORMULA_LIMIT = 10;
export const canCreateQueryAndFormula = (query): boolean => {
export const canCreateQueryAndFormula = (query: Query): boolean => {
const queries = query[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME].queryBuilder;
const formulas =
query[WIDGET_QUERY_BUILDER_QUERY_KEY_NAME][

View File

@ -1,7 +1,15 @@
import { Tooltip } from 'antd';
import React from 'react';
function TabHeader({ tabName, hasUnstagedChanges }): JSX.Element {
interface ITabHeaderProps {
tabName: string;
hasUnstagedChanges: boolean;
}
function TabHeader({
tabName,
hasUnstagedChanges,
}: ITabHeaderProps): JSX.Element {
return (
<div
style={{

View File

@ -1,17 +1,21 @@
/* eslint-disable */
// @ts-ignore
// @ts-nocheck
import { EQueryType } from 'types/common/dashboard';
import { EQueryTypeToQueryKeyMapping } from './types';
export const WIDGET_PROMQL_QUERY_KEY_NAME: string = EQueryTypeToQueryKeyMapping[
EQueryType[EQueryType.PROM]
] as string;
export const WIDGET_PROMQL_QUERY_KEY_NAME: EQueryTypeToQueryKeyMapping.PROM =
EQueryTypeToQueryKeyMapping[EQueryType[EQueryType.PROM]];
export const WIDGET_CLICKHOUSE_QUERY_KEY_NAME: string = EQueryTypeToQueryKeyMapping[
export const WIDGET_CLICKHOUSE_QUERY_KEY_NAME: EQueryTypeToQueryKeyMapping.CLICKHOUSE = EQueryTypeToQueryKeyMapping[
EQueryType[EQueryType.CLICKHOUSE]
] as string;
export const WIDGET_QUERY_BUILDER_QUERY_KEY_NAME: string = EQueryTypeToQueryKeyMapping[
export const WIDGET_QUERY_BUILDER_QUERY_KEY_NAME: EQueryTypeToQueryKeyMapping.QUERY_BUILDER = EQueryTypeToQueryKeyMapping[
EQueryType[EQueryType.QUERY_BUILDER]
] as string;
export const WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME: string = 'formulas' as string;
type TFormulas = 'formulas';
export const WIDGET_QUERY_BUILDER_FORMULA_KEY_NAME: TFormulas = 'formulas';

View File

@ -1,3 +1,6 @@
/* eslint-disable */
//@ts-nocheck
import { Button, Tabs } from 'antd';
import TextToolTip from 'components/TextToolTip';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
@ -8,22 +11,13 @@ import { connect, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { bindActionCreators, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import { CreateQuery, CreateQueryProps } from 'store/actions';
import {
GetQueryResults,
GetQueryResultsProps,
} from 'store/actions/dashboard/getQueryResults';
import {
UpdateQuery,
UpdateQueryProps,
} from 'store/actions/dashboard/updateQuery';
import {
UpdateQueryType,
UpdateQueryTypeProps,
} from 'store/actions/dashboard/updateQueryType';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { Widgets } from 'types/api/dashboard/getAll';
import { Query, Widgets } from 'types/api/dashboard/getAll';
import { EQueryType } from 'types/common/dashboard';
import DashboardReducer from 'types/reducer/dashboards';
import { v4 as uuid } from 'uuid';
@ -46,11 +40,13 @@ function QuerySection({
updateQuery,
selectedGraph,
}: QueryProps): JSX.Element {
const [localQueryChanges, setLocalQueryChanges] = useState({});
const [rctTabKey, setRctTabKey] = useState({
const [localQueryChanges, setLocalQueryChanges] = useState<Query>({} as Query);
const [rctTabKey, setRctTabKey] = useState<
Record<keyof typeof EQueryType, string>
>({
QUERY_BUILDER: uuid(),
CLICKHOUSE: uuid(),
PROMQL: uuid(),
PROM: uuid(),
});
const { dashboards } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
@ -73,104 +69,80 @@ function QuerySection({
selectedWidget.query.queryType,
);
const { query = [] } = selectedWidget || {};
const { query } = selectedWidget || {};
useEffect(() => {
setLocalQueryChanges(cloneDeep(query));
setLocalQueryChanges(cloneDeep(query) as Query);
}, [query]);
const queryOnClickHandler = () => {
setLocalQueryChanges([
...localQueryChanges,
// {
// name: GetQueryName(localQueryChanges),
// disabled: false,
// promQL: {
// query: '',
// legend: '',
// },
// clickHouseQuery: '',
// queryBuilder: {
// metricName: null,
// aggregateOperator: null,
// tagFilters: {
// op: 'AND',
// items: [],
// },
// groupBy: [],
// },
// },
]);
};
const queryDiff = (queryA, queryB, queryCategory) => {
const queryDiff = (
queryA: Query,
queryB: Query,
queryCategory: EQueryType,
): boolean => {
const keyOfConcern = getQueryKey(queryCategory);
return !isEqual(queryA[keyOfConcern], queryB[keyOfConcern]);
};
useEffect(() => {
handleUnstagedChanges(
queryDiff(query, localQueryChanges, parseInt(queryCategory)),
queryDiff(query, localQueryChanges, parseInt(`${queryCategory}`, 10)),
);
}, [handleUnstagedChanges, localQueryChanges, query, queryCategory]);
const purgeLocalChanges = () => {
setLocalQueryChanges(query);
};
const regenRctKeys = () => {
const regenRctKeys = (): void => {
setRctTabKey((prevState) => {
Object.keys(prevState).map((key) => {
prevState[key] = uuid();
const newState = prevState;
Object.keys(newState).forEach((key) => {
newState[key as keyof typeof EQueryType] = uuid();
});
return cloneDeep(prevState);
return cloneDeep(newState);
});
};
const handleStageQuery = () => {
const handleStageQuery = (): void => {
updateQuery({
updatedQuery: localQueryChanges,
widgetId: urlQuery.get('widgetId'),
widgetId: urlQuery.get('widgetId') || '',
yAxisUnit: selectedWidget.yAxisUnit,
});
};
const handleQueryCategoryChange = (qCategory): void => {
const handleQueryCategoryChange = (qCategory: string): void => {
// If true, then it means that the user has made some changes and haven't staged them
const unstagedChanges = queryDiff(
query,
localQueryChanges,
parseInt(queryCategory),
parseInt(`${queryCategory}`, 10),
);
if (unstagedChanges && showUnstagedStashConfirmBox()) {
// eslint-disable-next-line no-alert
window.confirm(
"You are trying to navigate to different tab with unstaged changes. Your current changes will be purged. Press 'Stage & Run Query' to stage them.",
);
return;
}
setQueryCategory(parseInt(qCategory));
setQueryCategory(parseInt(`${qCategory}`, 10));
const newLocalQuery = {
...cloneDeep(query),
queryType: parseInt(qCategory),
queryType: parseInt(`${qCategory}`, 10),
};
setLocalQueryChanges(newLocalQuery);
regenRctKeys();
updateQuery({
updatedQuery: newLocalQuery,
widgetId: urlQuery.get('widgetId'),
widgetId: urlQuery.get('widgetId') || '',
yAxisUnit: selectedWidget.yAxisUnit,
});
};
const handleLocalQueryUpdate = ({ updatedQuery }) => {
setLocalQueryChanges(updatedQuery);
};
const handleDeleteQuery = ({ currentIndex }) => {
setLocalQueryChanges((prevState) => {
prevState.splice(currentIndex, 1);
return [...prevState];
});
const handleLocalQueryUpdate = ({
updatedQuery,
}: IHandleUpdatedQuery): void => {
setLocalQueryChanges(updatedQuery);
};
return (
@ -211,7 +183,7 @@ function QuerySection({
<QueryBuilderQueryContainer
key={rctTabKey.QUERY_BUILDER}
queryData={localQueryChanges}
updateQueryData={({ updatedQuery }) => {
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
handleLocalQueryUpdate({ updatedQuery });
}}
metricsBuilderQueries={
@ -236,7 +208,7 @@ function QuerySection({
<ClickHouseQueryContainer
key={rctTabKey.CLICKHOUSE}
queryData={localQueryChanges}
updateQueryData={({ updatedQuery }) => {
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
handleLocalQueryUpdate({ updatedQuery });
}}
clickHouseQueries={localQueryChanges[WIDGET_CLICKHOUSE_QUERY_KEY_NAME]}
@ -256,9 +228,9 @@ function QuerySection({
key={EQueryType.PROM.toString()}
>
<PromQLQueryContainer
key={rctTabKey.PROMQL}
key={rctTabKey.PROM}
queryData={localQueryChanges}
updateQueryData={({ updatedQuery }) => {
updateQueryData={({ updatedQuery }: IHandleUpdatedQuery): void => {
handleLocalQueryUpdate({ updatedQuery });
}}
promQLQueries={localQueryChanges[WIDGET_PROMQL_QUERY_KEY_NAME]}

View File

@ -1,3 +1,5 @@
import { Query } from 'types/api/dashboard/getAll';
export type TQueryCategories = 'query_builder' | 'clickhouse_query' | 'promql';
export enum EQueryCategories {
@ -11,3 +13,7 @@ export enum EQueryTypeToQueryKeyMapping {
CLICKHOUSE = 'clickHouse',
PROM = 'promQL',
}
export interface IHandleUpdatedQuery {
updatedQuery: Query;
}

View File

@ -2,6 +2,10 @@ import { EQueryType } from 'types/common/dashboard';
import { EQueryTypeToQueryKeyMapping } from '../types';
export const getQueryKey = (queryCategory): EQueryTypeToQueryKeyMapping => {
return EQueryTypeToQueryKeyMapping[EQueryType[queryCategory] as unknown];
export const getQueryKey = (
queryCategory: EQueryType,
): EQueryTypeToQueryKeyMapping => {
return EQueryTypeToQueryKeyMapping[
EQueryType[queryCategory] as keyof typeof EQueryTypeToQueryKeyMapping
];
};

View File

@ -4,7 +4,7 @@ import { EQueryType } from 'types/common/dashboard';
import { Tag } from '../styles';
interface IQueryTypeTagProps {
queryType: EQueryType;
queryType: EQueryType | undefined;
}
function QueryTypeTag({ queryType }: IQueryTypeTagProps): JSX.Element {
switch (queryType) {

View File

@ -1,8 +1,13 @@
import React from 'react';
import { EQueryType } from 'types/common/dashboard';
import QueryTypeTag from '../QueryTypeTag';
function PlotTag({ queryType }): JSX.Element | null {
interface IPlotTagProps {
queryType: EQueryType;
}
function PlotTag({ queryType }: IPlotTagProps): JSX.Element | null {
if (queryType === undefined) {
return null;
}

View File

@ -41,8 +41,7 @@ function WidgetGraph({
</NotFoundContainer>
);
}
if (queryData.data.length === 0 || queryData.data[0].queryData.length === 0) {
if (queryData.data.queryData.length === 0) {
return (
<NotFoundContainer>
<Typography>No Data</Typography>
@ -51,7 +50,7 @@ function WidgetGraph({
}
const chartDataSet = getChartData({
queryData: queryData.data,
queryData: [queryData.data],
});
return (

View File

@ -136,9 +136,9 @@ function NewWidget({
}, [dashboardId, dispatch]);
const getQueryResult = useCallback(() => {
if (selectedWidget?.id.length !== 0) {
if (selectedWidget?.id.length !== 0 && selectedWidget?.query) {
getQueryResults({
query: selectedWidget?.query || [],
query: selectedWidget?.query,
selectedTime: selectedTime.enum,
widgetId: selectedWidget?.id || '',
graphType: selectedGraph,

View File

@ -103,8 +103,8 @@ function SideNav(): JSX.Element {
icon={<Icon />}
onClick={(): void => onClickHandler(to)}
>
<Space style={{ position: 'relative' }}>
<Typography>{name}</Typography>
<Space>
<div>{name}</div>
{tags &&
tags.map((e) => (
<Tags style={{ lineHeight: '1rem' }} color="#177DDC" key={e}>

View File

@ -55,7 +55,7 @@
id="appMode"
rel="stylesheet"
type="text/css"
href="/css/antd.dark.min.css"
rel="preload"
/>
</head>
<body>
@ -64,13 +64,7 @@
<script>
const themeNode = document.getElementById('appMode');
let userTheme;
try {
userTheme = localStorage.getItem('theme');
} catch (e) {
userTheme = '';
}
let userTheme = localStorage.getItem('theme') || "";
if (userTheme === 'lightMode') {
themeNode.setAttribute('href', '/css/antd.min.css');

View File

@ -6,30 +6,31 @@ import convertIntoEpoc from './covertIntoEpoc';
import { colors } from './getRandomColor';
const getChartData = ({ queryData }: GetChartDataProps): ChartData => {
const response = queryData.map(({ queryData }) => {
return queryData.map((e) => {
const { values = [], metric, legend, queryName } = e || {};
const response = queryData.map(
({ queryData, query: queryG, legend: legendG }) => {
return queryData.map((e) => {
const { values = [], metric, legend, queryName } = e || {};
const labelNames = getLabelName(
metric,
queryName || queryG || '', // query
legend || legendG || '',
);
const dataValue = values?.map((e) => {
const [first = 0, second = ''] = e || [];
return {
first: new Date(parseInt(convertIntoEpoc(first * 1000), 10)), // converting in ms
second: Number(parseFloat(second)),
};
});
const labelNames = getLabelName(
metric,
queryName || '', // query
legend || '',
);
const dataValue = values?.map((e) => {
const [first = 0, second = ''] = e || [];
return {
first: new Date(parseInt(convertIntoEpoc(first * 1000), 10)), // converting in ms
second: Number(parseFloat(second)),
label: labelNames !== 'undefined' ? labelNames : '',
first: dataValue.map((e) => e.first),
second: dataValue.map((e) => e.second),
};
});
return {
label: labelNames !== 'undefined' ? labelNames : '',
first: dataValue.map((e) => e.first),
second: dataValue.map((e) => e.second),
};
});
});
},
);
const allLabels = response
.map((e) => e.map((e) => e.label))
.reduce((a, b) => [...a, ...b], []);
@ -58,7 +59,7 @@ const getChartData = ({ queryData }: GetChartDataProps): ChartData => {
};
interface GetChartDataProps {
queryData: Widgets['queryData']['data'];
queryData: Widgets['queryData']['data'][];
}
export default getChartData;

View File

@ -2,13 +2,16 @@ import { sortBy } from 'lodash-es';
const MAX_QUERIES = 20;
function GetFormulaName(formulas = []): string | null {
function GetFormulaName(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
formulas: { name: string; [key: string]: any }[] = [],
): string | null {
if (!formulas.length) return 'F1';
if (formulas.length === MAX_QUERIES) {
return null;
}
const formulasNameNumbered = sortBy(
formulas.map(({ name }) => {
formulas.map(({ name }: { name: string }) => {
return parseInt(name.slice(1), 10);
}),
(e) => e,
@ -22,6 +25,7 @@ function GetFormulaName(formulas = []): string | null {
}
// formulaIteratorIdx += 1;
}
return null;
}
export default GetFormulaName;

View File

@ -1,26 +1,26 @@
import { sortBy } from 'lodash-es';
const MAX_QUERIES = 26;
function GetQueryName(queries = []): string | null {
function GetQueryName(queries: { name: string }[] = []): string | null {
if (!queries.length) return 'A';
if (queries.length === MAX_QUERIES) {
return null;
}
const sortedQueries = sortBy(queries, function (q) {
const sortedQueries = sortBy(queries, (q) => {
return q.name;
});
let query_iterator_idx = 0;
let queryIteratorIdx = 0;
for (
let charItr = 'A'.charCodeAt(0);
charItr <= 'A'.charCodeAt(0) + MAX_QUERIES;
charItr += 1
) {
if (charItr !== sortedQueries[query_iterator_idx]?.name.charCodeAt(0)) {
if (charItr !== sortedQueries[queryIteratorIdx]?.name.charCodeAt(0)) {
return String.fromCharCode(charItr);
}
query_iterator_idx += 1;
queryIteratorIdx += 1;
}
return null;

View File

@ -92,7 +92,7 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
fgRef && fgRef.current && fgRef.current.zoomToFit(100, 120);
};
const { nodes, links } = getGraphData(serviceMap);
const { nodes, links } = getGraphData(serviceMap, isDarkMode);
const graphData = { nodes, links };
return (
<Container>
@ -109,7 +109,7 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
linkAutoColorBy={(d) => d.target}
linkDirectionalParticles="value"
linkDirectionalParticleSpeed={(d) => d.value}
nodeCanvasObject={(node, ctx, globalScale) => {
nodeCanvasObject={(node, ctx) => {
const label = transformLabel(node.id);
const { fontSize } = node;
ctx.font = `${fontSize}px Roboto`;
@ -118,7 +118,6 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
ctx.fillStyle = node.color;
ctx.beginPath();
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
ctx.fillStyle = isDarkMode ? '#3C8618' : '#D5F2BB';
ctx.fill();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

View File

@ -2,7 +2,6 @@
//@ts-nocheck
import { cloneDeep, find, maxBy, uniq, uniqBy } from 'lodash-es';
import { graphDataType } from './ServiceMap';
const MIN_WIDTH = 10;
@ -18,7 +17,7 @@ export const getDimensions = (num, highest) => {
};
};
export const getGraphData = (serviceMap): graphDataType => {
export const getGraphData = (serviceMap, isDarkMode): graphDataType => {
const { items, services } = serviceMap;
const highestCallCount = maxBy(items, (e) => e?.callCount)?.callCount;
const highestCallRate = maxBy(services, (e) => e?.callRate)?.callRate;
@ -39,7 +38,7 @@ export const getGraphData = (serviceMap): graphDataType => {
const uniqNodes = uniq([...uniqParent, ...uniqChild]);
const nodes = uniqNodes.map((node, i) => {
const service = find(services, (service) => service.serviceName === node);
let color = '#88CEA5';
let color = isDarkMode ? '#7CA568' : '#D5F2BB';
if (!service) {
return {
id: node,
@ -54,9 +53,9 @@ export const getGraphData = (serviceMap): graphDataType => {
};
}
if (service.errorRate > 0) {
color = '#F98989';
color = isDarkMode ? '#DB836E' : '#F98989';
} else if (service.fourXXRate > 0) {
color = '#F9DA7B';
color = isDarkMode ? '#C79931' : '#F9DA7B';
}
const { fontSize, width } = getDimensions(service.callRate, highestCallRate);
return {

View File

@ -1,17 +0,0 @@
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
export const CreateQuery = ({ widgetId }: CreateQueryProps) => (
dispatch: Dispatch<AppActions>,
): void => {
dispatch({
type: 'CREATE_NEW_QUERY',
payload: {
widgetId,
},
});
};
export interface CreateQueryProps {
widgetId: string;
}

View File

@ -46,11 +46,10 @@ export const GetDashboard = ({
title: '',
queryType: 0,
queryData: {
data: [
{
queryData: [],
},
],
data: {
queryData: [],
},
error: false,
errorMessage: '',
loading: false,

View File

@ -1,3 +1,7 @@
/* eslint-disable */
// @ts-ignore
// @ts-nocheck
import { getMetricsQueryRange } from 'api/metrics/getQueryRange';
import { AxiosError } from 'axios';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
@ -36,6 +40,7 @@ export async function GetMetricQueryRange({
EQueryTypeToQueryKeyMapping[EQueryType[query.queryType]];
const queryData = query[queryKey];
const legendMap: Record<string, string> = {};
const QueryPayload = {
dataSource: EDataSource.METRICS,
compositeMetricQuery: {
@ -175,12 +180,6 @@ export const GetQueryResults = (
return;
}
// const data = response.map((e) => ({
// query: e.query,
// legend: e.legend || '',
// queryData: e.queryData.payload?.result || [],
// }));
dispatch({
type: 'QUERY_SUCCESS',
payload: {
@ -216,7 +215,7 @@ export const GetQueryResults = (
export interface GetQueryResultsProps {
widgetId: string;
selectedTime: timePreferenceType;
query: Query[];
query: Query;
graphType: ITEMS;
globalSelectedInterval: GlobalReducer['selectedTime'];
}

View File

@ -1,5 +1,4 @@
export * from './applySettingsToPanel';
export * from './createQuery';
export * from './deleteDashboard';
export * from './deleteQuery';
export * from './getAllDashboard';

View File

@ -82,7 +82,6 @@ export const SaveDashboard = ({
...allLayout.slice(emptyLayoutIndex + 1, allLayout.length),
];
};
const allLayout = getAllLayout();
const response = await updateDashboardApi({
data: {
@ -109,12 +108,6 @@ export const SaveDashboard = ({
panelTypes: search.get('graphType') as Widgets['panelTypes'],
queryData: {
...selectedWidget.queryData,
data: [
...selectedWidget.queryData.data.map((e) => ({
...e,
queryData: [],
})),
],
},
},
...afterWidget,

View File

@ -1,21 +0,0 @@
import { Dispatch } from 'redux';
import AppActions from 'types/actions';
export const UpdateQueryType = (
props: UpdateQueryTypeProps,
): ((dispatch: Dispatch<AppActions>) => void) => {
return (dispatch: Dispatch<AppActions>): void => {
dispatch({
type: 'UPDATE_QUERY_TYPE',
payload: {
queryType: props.queryType,
widgetId: props.widgetId,
},
});
};
};
export interface UpdateQueryTypeProps {
widgetId: string;
queryType: number;
}

View File

@ -19,7 +19,6 @@ import {
TOGGLE_EDIT_MODE,
UPDATE_DASHBOARD,
UPDATE_QUERY,
UPDATE_QUERY_TYPE,
UPDATE_TITLE_DESCRIPTION_TAGS_SUCCESS,
} from 'types/actions/dashboard';
import InitialValueTypes from 'types/reducer/dashboards';
@ -216,6 +215,7 @@ const dashboard = (
case QUERY_SUCCESS: {
const { widgetId, data: queryDataResponse } = action.payload;
const { dashboards } = state;
const [selectedDashboard] = dashboards;
const { data } = selectedDashboard;
@ -243,7 +243,7 @@ const dashboard = (
{
...selectedWidget,
queryData: {
data: [queryDataResponse],
data: queryDataResponse,
error: selectedWidget.queryData.error,
errorMessage: selectedWidget.queryData.errorMessage,
loading: false,
@ -397,88 +397,6 @@ const dashboard = (
],
};
}
case UPDATE_QUERY_TYPE: {
const { widgetId, queryType } = action.payload;
const { dashboards } = state;
const [selectedDashboard] = dashboards;
const { data } = selectedDashboard;
const { widgets = [] } = data;
const selectedWidgetIndex = widgets.findIndex((e) => e.id === widgetId) || 0;
const preWidget = widgets?.slice(0, selectedWidgetIndex) || [];
const afterWidget =
widgets?.slice(
selectedWidgetIndex + 1, // this is never undefined
widgets.length,
) || [];
const selectedWidget = widgets[selectedWidgetIndex];
return {
...state,
dashboards: [
{
...selectedDashboard,
data: {
...data,
widgets: [
...preWidget,
{
...selectedWidget,
queryType,
},
...afterWidget,
],
},
},
],
};
}
// case DELETE_QUERY: {
// const { currentIndex, widgetId } = action.payload;
// const { dashboards } = state;
// const [selectedDashboard] = dashboards;
// const { data } = selectedDashboard;
// const { widgets = [] } = data;
// const selectedWidgetIndex = widgets.findIndex((e) => e.id === widgetId) || 0;
// const preWidget = widgets?.slice(0, selectedWidgetIndex) || [];
// const afterWidget =
// widgets?.slice(
// selectedWidgetIndex + 1, // this is never undefined
// widgets.length,
// ) || [];
// const selectedWidget = widgets[selectedWidgetIndex];
// const { query } = selectedWidget;
// const preQuery = query.slice(0, currentIndex);
// const postQuery = query.slice(currentIndex + 1, query.length);
// return {
// ...state,
// dashboards: [
// {
// ...selectedDashboard,
// data: {
// ...data,
// widgets: [
// ...preWidget,
// {
// ...selectedWidget,
// query: [...preQuery, ...postQuery],
// },
// ...afterWidget,
// ],
// },
// },
// ],
// };
// }
default:
return state;

View File

@ -41,7 +41,6 @@ export const DELETE_WIDGET_ERROR = 'DELETE_WIDGET_ERROR';
export const IS_ADD_WIDGET = 'IS_ADD_WIDGET';
export const DELETE_QUERY = 'DELETE_QUERY';
export const UPDATE_QUERY_TYPE = 'UPDATE_QUERY_TYPE';
export const FLUSH_DASHBOARD = 'FLUSH_DASHBOARD';
interface GetDashboard {
type: typeof GET_DASHBOARD;
@ -124,7 +123,7 @@ export interface QuerySuccessPayload {
// legend: string;
queryData: QueryData[];
// query: string
}[];
};
}
interface QuerySuccess {
type: typeof QUERY_SUCCESS;
@ -172,14 +171,6 @@ interface DeleteQuery {
payload: DeleteQueryProps;
}
interface UpdateQueryType {
type: typeof UPDATE_QUERY_TYPE;
payload: {
queryType: number;
widgetId: string;
};
}
interface FlushDashboard {
type: typeof FLUSH_DASHBOARD;
}
@ -203,5 +194,4 @@ export type DashboardActions =
| IsAddWidget
| UpdateQuery
| DeleteQuery
| UpdateQueryType
| FlushDashboard;

View File

@ -1,7 +1,11 @@
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
import { Layout } from 'react-grid-layout';
import { EAggregateOperator, EQueryType } from 'types/common/dashboard';
import {
EAggregateOperator,
EQueryType,
EReduceOperator,
} from 'types/common/dashboard';
import { QueryData } from '../widgets/getQuery';
@ -38,10 +42,10 @@ export interface IBaseWidget {
error: boolean;
errorMessage: string;
data: {
// legend?: string;
query?: string;
legend?: string;
queryData: QueryData[];
// query: string;
}[];
};
};
stepSize?: number;
yAxisUnit?: string;
@ -74,8 +78,9 @@ export interface IMetricsBuilderQuery {
name: string;
legend: string;
metricName: string | null;
groupBy: string[];
groupBy?: string[];
tagFilters: IQueryBuilderTagFilters;
reduceTo?: EReduceOperator;
}
export interface IQueryBuilderTagFilters {

View File

@ -1,6 +1,6 @@
import { QueryData } from '../widgets/getQuery';
export type MetricsRangeProps = any;
export type MetricsRangeProps = never;
export interface MetricRangePayloadProps {
data: {
result: QueryData[];

View File

@ -9,6 +9,7 @@ export interface QueryData {
[key: string]: string;
};
queryName: string;
legend?: string;
values: [number, string][];
}

View File

@ -58,7 +58,7 @@ services:
condition: service_healthy
otel-collector:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
@ -71,7 +71,7 @@ services:
condition: service_healthy
otel-collector-metrics:
image: signoz/otelcontribcol:0.45.1-0.3
image: signoz/otelcontribcol:0.45.1-1.0
command: ["--config=/etc/otel-collector-metrics-config.yaml"]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml