mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-06 05:46:17 +08:00
Merge branch 'develop' into 506-integrate-reactquery-devtools
This commit is contained in:
commit
ae5d4326a2
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 "+++++++++++++++++++++++++++++++++++++++++++++++++"
|
||||
|
@ -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,
|
||||
|
@ -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('');
|
||||
|
@ -24,8 +24,11 @@ function TextToolTip({ text, url }: TextToolTipProps): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
TextToolTip.defaultProps = {
|
||||
url: '',
|
||||
};
|
||||
interface TextToolTipProps {
|
||||
url: string;
|
||||
url?: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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';
|
||||
|
@ -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="%"
|
||||
|
@ -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`,
|
||||
);
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ const getWidget = (query: PromQLWidgets['query']): PromQLWidgets => {
|
||||
panelTypes: 'TIME_SERIES',
|
||||
query,
|
||||
queryData: {
|
||||
data: [],
|
||||
data: { queryData: [] },
|
||||
error: false,
|
||||
errorMessage: '',
|
||||
loading: false,
|
||||
|
@ -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],
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 } });
|
||||
|
@ -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 })
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
@ -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}
|
||||
|
@ -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}
|
||||
|
@ -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;
|
||||
}
|
@ -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,
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -9,3 +9,10 @@ export interface IMetricBuilderTagKeyQuery {
|
||||
operator: string;
|
||||
tagValue: string[];
|
||||
}
|
||||
|
||||
export interface ITagKeyValueQuery {
|
||||
id: string;
|
||||
key: string;
|
||||
op: string;
|
||||
value: string[];
|
||||
}
|
||||
|
@ -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[],
|
||||
};
|
||||
}
|
||||
|
@ -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}
|
||||
|
@ -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 } });
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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][
|
||||
|
@ -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={{
|
||||
|
@ -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';
|
||||
|
@ -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]}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
];
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 (
|
||||
|
@ -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,
|
||||
|
@ -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}>
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
@ -46,11 +46,10 @@ export const GetDashboard = ({
|
||||
title: '',
|
||||
queryType: 0,
|
||||
queryData: {
|
||||
data: [
|
||||
{
|
||||
queryData: [],
|
||||
},
|
||||
],
|
||||
data: {
|
||||
queryData: [],
|
||||
},
|
||||
|
||||
error: false,
|
||||
errorMessage: '',
|
||||
loading: false,
|
||||
|
@ -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'];
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
export * from './applySettingsToPanel';
|
||||
export * from './createQuery';
|
||||
export * from './deleteDashboard';
|
||||
export * from './deleteQuery';
|
||||
export * from './getAllDashboard';
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { QueryData } from '../widgets/getQuery';
|
||||
|
||||
export type MetricsRangeProps = any;
|
||||
export type MetricsRangeProps = never;
|
||||
export interface MetricRangePayloadProps {
|
||||
data: {
|
||||
result: QueryData[];
|
||||
|
@ -9,6 +9,7 @@ export interface QueryData {
|
||||
[key: string]: string;
|
||||
};
|
||||
queryName: string;
|
||||
legend?: string;
|
||||
values: [number, string][];
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user