mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 04:26:02 +08:00
Fix(FE): some eslint error are fixed (#382)
* chore(UI): @types/node version is updated and port sync finder is removed * chore(UI): tsconfig is updated * fix(bug) webpack config is updated * fix(bug): some eslint error is now fixed * chore(lock): yarn lock is fixed
This commit is contained in:
parent
73b5134971
commit
4dfbdd2d63
@ -19,6 +19,8 @@
|
|||||||
/**
|
/**
|
||||||
* @type {Cypress.PluginConfig}
|
* @type {Cypress.PluginConfig}
|
||||||
*/
|
*/
|
||||||
module.exports = (on, config: Cypress.ConfigOptions): void => {};
|
module.exports = (): void => {
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
// be explicit about types included
|
// be explicit about types included
|
||||||
// to avoid clashing with Jest types
|
// to avoid clashing with Jest types
|
||||||
"types": ["cypress", "@testing-library/cypress"],
|
"types": ["cypress", "@testing-library/cypress", "node"],
|
||||||
"isolatedModules": false
|
"isolatedModules": false
|
||||||
},
|
},
|
||||||
"include": ["../node_modules/cypress", "./**/*.ts"]
|
"include": ["../node_modules/cypress", "./**/*.ts"]
|
||||||
|
@ -18,13 +18,6 @@ export const ServiceMapPage = Loadable(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const TraceDetailPage = Loadable(
|
|
||||||
() =>
|
|
||||||
import(
|
|
||||||
/* webpackChunkName: "TraceDetailPage" */ 'modules/Traces/TraceDetail'
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const TraceDetailPages = Loadable(
|
export const TraceDetailPages = Loadable(
|
||||||
() => import(/* webpackChunkName: "TraceDetailPage" */ 'pages/TraceDetails'),
|
() => import(/* webpackChunkName: "TraceDetailPage" */ 'pages/TraceDetails'),
|
||||||
);
|
);
|
||||||
|
@ -17,7 +17,6 @@ import {
|
|||||||
ServicesTablePage,
|
ServicesTablePage,
|
||||||
SettingsPage,
|
SettingsPage,
|
||||||
SignupPage,
|
SignupPage,
|
||||||
TraceDetailPage,
|
|
||||||
TraceDetailPages,
|
TraceDetailPages,
|
||||||
TraceGraphPage,
|
TraceGraphPage,
|
||||||
UsageExplorerPage,
|
UsageExplorerPage,
|
||||||
@ -64,11 +63,6 @@ const routes: AppRoutes[] = [
|
|||||||
exact: true,
|
exact: true,
|
||||||
component: InstrumentationPage,
|
component: InstrumentationPage,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: ROUTES.TRACES,
|
|
||||||
exact: true,
|
|
||||||
component: TraceDetailPage,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: ROUTES.ALL_DASHBOARD,
|
path: ROUTES.ALL_DASHBOARD,
|
||||||
exact: true,
|
exact: true,
|
||||||
|
@ -12,5 +12,5 @@ export const SpinerStyle = styled.div<Props>`
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: ${({ height = '100vh' }) => height};
|
height: ${({ height = '100vh' }): number | string => height};
|
||||||
`;
|
`;
|
||||||
|
@ -2,7 +2,6 @@ const ROUTES = {
|
|||||||
SIGN_UP: '/signup',
|
SIGN_UP: '/signup',
|
||||||
SERVICE_METRICS: '/application/:servicename',
|
SERVICE_METRICS: '/application/:servicename',
|
||||||
SERVICE_MAP: '/service-map',
|
SERVICE_MAP: '/service-map',
|
||||||
TRACES: '/traces',
|
|
||||||
TRACE: '/trace',
|
TRACE: '/trace',
|
||||||
TRACE_GRAPH: '/traces/:id',
|
TRACE_GRAPH: '/traces/:id',
|
||||||
SETTINGS: '/settings',
|
SETTINGS: '/settings',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { ChartData, ChartOptions } from 'chart.js';
|
import { ChartData } from 'chart.js';
|
||||||
import Graph, { graphOnClickHandler } from 'components/Graph';
|
import Graph, { graphOnClickHandler } from 'components/Graph';
|
||||||
import ValueGraph from 'components/ValueGraph';
|
import ValueGraph from 'components/ValueGraph';
|
||||||
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Button, Select as DefaultSelect } from 'antd';
|
import { Button, Select as DefaultSelect } from 'antd';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { getDefaultOption, getOptions, Time } from './config';
|
import { getDefaultOption, getOptions, Time } from './config';
|
||||||
import { Container, Form, FormItem } from './styles';
|
import { Container, Form, FormItem } from './styles';
|
||||||
@ -75,7 +75,7 @@ const DateTimeSelection = ({
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { maxTime, minTime, selectedTime, loading } = useSelector<
|
const { maxTime, minTime, selectedTime } = useSelector<
|
||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
@ -56,7 +56,15 @@ const DescriptionOfDashboard = ({
|
|||||||
} else {
|
} else {
|
||||||
toggleEditMode();
|
toggleEditMode();
|
||||||
}
|
}
|
||||||
}, [isEditMode, updatedTitle, updatedTags, updatedDescription]);
|
}, [
|
||||||
|
isEditMode,
|
||||||
|
updatedTitle,
|
||||||
|
updatedTags,
|
||||||
|
updatedDescription,
|
||||||
|
selectedDashboard,
|
||||||
|
toggleEditMode,
|
||||||
|
updateDashboardTitleDescriptionTags,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -6,17 +6,16 @@ import { AppState } from 'store/reducers';
|
|||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { ThunkDispatch } from 'redux-thunk';
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
|
import {
|
||||||
|
GetTraceVisualAggregates,
|
||||||
|
GetTraceVisualAggregatesProps,
|
||||||
|
} from 'store/actions/trace/getTraceVisualAgrregates';
|
||||||
import AppActions from 'types/actions';
|
import AppActions from 'types/actions';
|
||||||
import { TraceReducer } from 'types/reducer/trace';
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
import { aggregation_options, entity } from './config';
|
import { aggregation_options, entity } from './config';
|
||||||
import { Card, CustomVisualizationsTitle, FormItem, Space } from './styles';
|
import { Card, CustomVisualizationsTitle, FormItem, Space } from './styles';
|
||||||
import TraceCustomGraph from './TraceCustomGraph';
|
import TraceCustomGraph from './TraceCustomGraph';
|
||||||
import {
|
|
||||||
GetTraceVisualAggregates,
|
|
||||||
GetTraceVisualAggregatesProps,
|
|
||||||
} from 'store/actions/trace/getTraceVisualAgrregates';
|
|
||||||
|
|
||||||
const TraceCustomVisualisation = ({
|
const TraceCustomVisualisation = ({
|
||||||
getTraceVisualAggregates,
|
getTraceVisualAggregates,
|
||||||
|
@ -5,12 +5,7 @@ import { connect, useSelector } from 'react-redux';
|
|||||||
import { bindActionCreators, Dispatch } from 'redux';
|
import { bindActionCreators, Dispatch } from 'redux';
|
||||||
import { ThunkDispatch } from 'redux-thunk';
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
import { TagItem } from 'store/actions';
|
import { TagItem } from 'store/actions';
|
||||||
import {
|
import { UpdateSelectedTags } from 'store/actions/trace';
|
||||||
UpdateSelectedLatency,
|
|
||||||
UpdateSelectedOperation,
|
|
||||||
UpdateSelectedService,
|
|
||||||
UpdateSelectedTags,
|
|
||||||
} from 'store/actions/trace';
|
|
||||||
import {
|
import {
|
||||||
UpdateSelectedData,
|
UpdateSelectedData,
|
||||||
UpdateSelectedDataProps,
|
UpdateSelectedDataProps,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Input, Typography, notification } from 'antd';
|
import { Button, Input, notification, Typography } from 'antd';
|
||||||
import { SelectValue } from 'antd/lib/select';
|
import { SelectValue } from 'antd/lib/select';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
@ -237,7 +237,13 @@ const TraceList = ({
|
|||||||
} ms`,
|
} ms`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [selectedService, selectedOperation, selectedKind, selectedLatency]);
|
}, [
|
||||||
|
selectedService,
|
||||||
|
selectedOperation,
|
||||||
|
selectedKind,
|
||||||
|
selectedLatency,
|
||||||
|
form_basefilter,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import React, { useState } from "react";
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import { servicesItem } from "store/actions";
|
import { Select } from 'antd';
|
||||||
import { InfoCircleOutlined } from "@ant-design/icons";
|
import React, { useState } from 'react';
|
||||||
import { Select } from "antd";
|
import { servicesItem } from 'store/actions';
|
||||||
import styled from "styled-components";
|
import styled from 'styled-components';
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
import { cloneDeep } from "lodash-es";
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
.info {
|
.info {
|
||||||
display:flex;
|
display: flex;
|
||||||
font-family: Roboto;
|
font-family: Roboto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
color: #4F4F4F;
|
color: #4f4f4f;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
.anticon-info-circle {
|
.anticon-info-circle {
|
||||||
margin-top: 22px;
|
margin-top: 22px;
|
||||||
@ -30,17 +30,20 @@ interface SelectServiceProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultOption = {
|
const defaultOption = {
|
||||||
serviceName: "Default"
|
serviceName: 'Default',
|
||||||
};
|
};
|
||||||
|
|
||||||
const SelectService = (props: SelectServiceProps) => {
|
const SelectService = (props: SelectServiceProps): JSX.Element => {
|
||||||
const [selectedVal, setSelectedVal] = useState<string>(defaultOption.serviceName);
|
const [selectedVal, setSelectedVal] = useState<string>(
|
||||||
|
defaultOption.serviceName,
|
||||||
|
);
|
||||||
const { zoomToService, zoomToDefault } = props;
|
const { zoomToService, zoomToDefault } = props;
|
||||||
const services = cloneDeep(props.services);
|
const services = cloneDeep(props.services);
|
||||||
services.unshift(defaultOption)
|
services.unshift(defaultOption);
|
||||||
const handleSelect = (value: string) => {
|
|
||||||
if(value === defaultOption.serviceName){
|
const handleSelect = (value: string): void => {
|
||||||
zoomToDefault()
|
if (value === defaultOption.serviceName) {
|
||||||
|
zoomToDefault();
|
||||||
} else {
|
} else {
|
||||||
zoomToService(value);
|
zoomToService(value);
|
||||||
}
|
}
|
||||||
@ -49,7 +52,7 @@ const SelectService = (props: SelectServiceProps) => {
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Select
|
<Select
|
||||||
style={{ width: 270, marginBottom: "56px" }}
|
style={{ width: 270, marginBottom: '56px' }}
|
||||||
placeholder="Select a service"
|
placeholder="Select a service"
|
||||||
onChange={handleSelect}
|
onChange={handleSelect}
|
||||||
value={selectedVal}
|
value={selectedVal}
|
||||||
@ -60,12 +63,14 @@ const SelectService = (props: SelectServiceProps) => {
|
|||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
<div className='info'>
|
<div className="info">
|
||||||
<InfoCircleOutlined />
|
<InfoCircleOutlined />
|
||||||
<div>
|
<div>
|
||||||
|
<div>
|
||||||
<div>-> Size of circles is proportial to the number of requests served by each node </div>
|
> Size of circles is proportial to the number of requests served by
|
||||||
<div>-> Click on node name to reposition the node</div>
|
each node
|
||||||
|
</div>
|
||||||
|
<div>> Click on node name to reposition the node</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -34,8 +34,8 @@ const Container = styled.div`
|
|||||||
interface ServiceMapProps extends RouteComponentProps<any> {
|
interface ServiceMapProps extends RouteComponentProps<any> {
|
||||||
serviceMap: serviceMapStore;
|
serviceMap: serviceMapStore;
|
||||||
globalTime: GlobalTime;
|
globalTime: GlobalTime;
|
||||||
getServiceMapItems: Function;
|
getServiceMapItems: (time: GlobalTime) => void;
|
||||||
getDetailedServiceMapItems: Function;
|
getDetailedServiceMapItems: (time: GlobalTime) => void;
|
||||||
}
|
}
|
||||||
interface graphNode {
|
interface graphNode {
|
||||||
id: string;
|
id: string;
|
||||||
@ -51,7 +51,7 @@ export interface graphDataType {
|
|||||||
links: graphLink[];
|
links: graphLink[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServiceMap = (props: ServiceMapProps) => {
|
const ServiceMap = (props: ServiceMapProps): JSX.Element => {
|
||||||
const fgRef = useRef();
|
const fgRef = useRef();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -68,7 +68,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
*/
|
*/
|
||||||
getServiceMapItems(globalTime);
|
getServiceMapItems(globalTime);
|
||||||
getDetailedServiceMapItems(globalTime);
|
getDetailedServiceMapItems(globalTime);
|
||||||
}, [globalTime]);
|
}, [globalTime, getServiceMapItems, getDetailedServiceMapItems]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fgRef.current && fgRef.current.d3Force('charge').strength(-400);
|
fgRef.current && fgRef.current.d3Force('charge').strength(-400);
|
||||||
@ -77,12 +77,14 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
return <Spinner size="large" tip="Loading..." />;
|
return <Spinner size="large" tip="Loading..." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const zoomToService = (value: string) => {
|
const zoomToService = (value: string): void => {
|
||||||
fgRef && fgRef.current.zoomToFit(700, getZoomPx(), (e) => e.id === value);
|
fgRef &&
|
||||||
|
fgRef.current &&
|
||||||
|
fgRef.current.zoomToFit(700, getZoomPx(), (e) => e.id === value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const zoomToDefault = () => {
|
const zoomToDefault = () => {
|
||||||
fgRef && fgRef.current.zoomToFit(100, 120);
|
fgRef && fgRef.current && fgRef.current.zoomToFit(100, 120);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { nodes, links } = getGraphData(serviceMap);
|
const { nodes, links } = getGraphData(serviceMap);
|
||||||
|
@ -1,94 +0,0 @@
|
|||||||
import { Col, Form, InputNumber, Modal, Row } from 'antd';
|
|
||||||
import { NamePath, Store } from 'antd/lib/form/interface';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface LatencyModalFormProps {
|
|
||||||
onCreate: (values: Store) => void; //Store is defined in antd forms library
|
|
||||||
onCancel: () => void;
|
|
||||||
latencyFilterValues: { min: string; max: string };
|
|
||||||
}
|
|
||||||
|
|
||||||
const LatencyModalForm: React.FC<LatencyModalFormProps> = ({
|
|
||||||
onCreate,
|
|
||||||
onCancel,
|
|
||||||
latencyFilterValues,
|
|
||||||
}) => {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const validateMinValue = ({
|
|
||||||
getFieldValue,
|
|
||||||
}: {
|
|
||||||
getFieldValue: (name: NamePath) => any;
|
|
||||||
}) => ({
|
|
||||||
validator(_, value: any) {
|
|
||||||
if (value < getFieldValue('max')) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return Promise.reject(new Error('Min value should be less than Max value'));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const validateMaxValue = ({
|
|
||||||
getFieldValue,
|
|
||||||
}: {
|
|
||||||
getFieldValue: (name: NamePath) => any;
|
|
||||||
}) => ({
|
|
||||||
validator(_, value: any) {
|
|
||||||
if (value > getFieldValue('min')) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return Promise.reject(
|
|
||||||
new Error('Max value should be greater than Min value'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
visible={true}
|
|
||||||
title="Chose min and max values of Latency"
|
|
||||||
okText="Apply"
|
|
||||||
cancelText="Cancel"
|
|
||||||
onCancel={onCancel}
|
|
||||||
onOk={() => {
|
|
||||||
form
|
|
||||||
.validateFields()
|
|
||||||
.then((values) => {
|
|
||||||
form.resetFields();
|
|
||||||
onCreate(values); // giving error for values
|
|
||||||
})
|
|
||||||
.catch((info) => {
|
|
||||||
// console.log('Validate Failed:', info);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
layout="horizontal"
|
|
||||||
name="form_in_modal"
|
|
||||||
initialValues={latencyFilterValues}
|
|
||||||
>
|
|
||||||
<Row>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="min"
|
|
||||||
label="Min (in ms)"
|
|
||||||
rules={[validateMinValue]}
|
|
||||||
// rules={[{ required: true, message: 'Please input the title of collection!' }]}
|
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="max" label="Max (in ms)" rules={[validateMaxValue]}>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{/* </Input.Group> */}
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LatencyModalForm;
|
|
@ -54,7 +54,7 @@ const CardContainer = styled(Card)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SelectedSpanDetails = (props: SelectedSpanDetailsProps) => {
|
const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => {
|
||||||
const spanTags = props.data?.tags;
|
const spanTags = props.data?.tags;
|
||||||
const service = props.data?.name?.split(':')[0];
|
const service = props.data?.name?.split(':')[0];
|
||||||
const operation = props.data?.name?.split(':')[1];
|
const operation = props.data?.name?.split(':')[1];
|
||||||
|
@ -1,272 +0,0 @@
|
|||||||
import { Form, Select, Space } from 'antd';
|
|
||||||
import Graph from 'components/Graph';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { connect, useSelector } from 'react-redux';
|
|
||||||
import { TraceFilters } from 'store/actions';
|
|
||||||
import { getFilteredTraceMetrics } from 'store/actions/MetricsActions';
|
|
||||||
import { customMetricsItem } from 'store/actions/MetricsActions';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
const { Option } = Select;
|
|
||||||
import { colors } from 'lib/getRandomColor';
|
|
||||||
import { GlobalTime } from 'types/actions/globalTime';
|
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CustomGraphContainer,
|
|
||||||
CustomVisualizationsTitle,
|
|
||||||
} from './styles';
|
|
||||||
|
|
||||||
const entity = [
|
|
||||||
{
|
|
||||||
title: 'Calls',
|
|
||||||
key: 'calls',
|
|
||||||
dataindex: 'calls',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Duration',
|
|
||||||
key: 'duration',
|
|
||||||
dataindex: 'duration',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Error',
|
|
||||||
key: 'error',
|
|
||||||
dataindex: 'error',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Status Code',
|
|
||||||
key: 'status_code',
|
|
||||||
dataindex: 'status_code',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const aggregation_options = [
|
|
||||||
{
|
|
||||||
linked_entity: 'calls',
|
|
||||||
default_selected: { title: 'Count', dataindex: 'count' },
|
|
||||||
options_available: [
|
|
||||||
{ title: 'Count', dataindex: 'count' },
|
|
||||||
{ title: 'Rate (per sec)', dataindex: 'rate_per_sec' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
linked_entity: 'duration',
|
|
||||||
default_selected: { title: 'p99', dataindex: 'p99' },
|
|
||||||
// options_available: [ {title:'Avg', dataindex:'avg'}, {title:'Max', dataindex:'max'},{title:'Min', dataindex:'min'}, {title:'p50', dataindex:'p50'},{title:'p95', dataindex:'p95'}, {title:'p95', dataindex:'p95'}]
|
|
||||||
options_available: [
|
|
||||||
{ title: 'p50', dataindex: 'p50' },
|
|
||||||
{ title: 'p95', dataindex: 'p95' },
|
|
||||||
{ title: 'p99', dataindex: 'p99' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
linked_entity: 'error',
|
|
||||||
default_selected: { title: 'Count', dataindex: 'count' },
|
|
||||||
options_available: [
|
|
||||||
{ title: 'Count', dataindex: 'count' },
|
|
||||||
{ title: 'Rate (per sec)', dataindex: 'rate_per_sec' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
linked_entity: 'status_code',
|
|
||||||
default_selected: { title: 'Count', dataindex: 'count' },
|
|
||||||
options_available: [{ title: 'Count', dataindex: 'count' }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
interface TraceCustomVisualizationsProps {
|
|
||||||
filteredTraceMetrics: customMetricsItem[];
|
|
||||||
globalTime: GlobalTime;
|
|
||||||
getFilteredTraceMetrics: (value: string, time: GlobalTime) => void;
|
|
||||||
traceFilters: TraceFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _TraceCustomVisualizations = (
|
|
||||||
props: TraceCustomVisualizationsProps,
|
|
||||||
): JSX.Element => {
|
|
||||||
const [selectedEntity, setSelectedEntity] = useState('calls');
|
|
||||||
const [selectedAggOption, setSelectedAggOption] = useState('count');
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const selectedStep = '60';
|
|
||||||
const {
|
|
||||||
filteredTraceMetrics,
|
|
||||||
getFilteredTraceMetrics,
|
|
||||||
globalTime,
|
|
||||||
traceFilters,
|
|
||||||
} = props;
|
|
||||||
const { loading } = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step should be multiples of 60, 60 -> 1 min
|
|
||||||
useEffect(() => {
|
|
||||||
let request_string =
|
|
||||||
'service=' +
|
|
||||||
traceFilters.service +
|
|
||||||
'&operation=' +
|
|
||||||
traceFilters.operation +
|
|
||||||
'&maxDuration=' +
|
|
||||||
traceFilters.latency?.max +
|
|
||||||
'&minDuration=' +
|
|
||||||
traceFilters.latency?.min +
|
|
||||||
'&kind=' +
|
|
||||||
traceFilters.kind;
|
|
||||||
if (traceFilters.tags)
|
|
||||||
request_string =
|
|
||||||
request_string +
|
|
||||||
'&tags=' +
|
|
||||||
encodeURIComponent(JSON.stringify(traceFilters.tags));
|
|
||||||
if (selectedEntity)
|
|
||||||
request_string =
|
|
||||||
request_string + '&dimension=' + selectedEntity.toLowerCase();
|
|
||||||
if (selectedAggOption)
|
|
||||||
request_string =
|
|
||||||
request_string + '&aggregation_option=' + selectedAggOption.toLowerCase();
|
|
||||||
if (selectedStep) request_string = request_string + '&step=' + selectedStep;
|
|
||||||
const plusMinus15 = {
|
|
||||||
minTime: globalTime.minTime - 15 * 60 * 1000000000,
|
|
||||||
maxTime: globalTime.maxTime + 15 * 60 * 1000000000,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Call the apis only when the route is loaded.
|
|
||||||
Check this issue: https://github.com/SigNoz/signoz/issues/110
|
|
||||||
*/
|
|
||||||
if (loading === false) {
|
|
||||||
getFilteredTraceMetrics(request_string, plusMinus15);
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
selectedEntity,
|
|
||||||
selectedAggOption,
|
|
||||||
traceFilters,
|
|
||||||
getFilteredTraceMetrics,
|
|
||||||
globalTime,
|
|
||||||
loading,
|
|
||||||
]);
|
|
||||||
|
|
||||||
//Custom metrics API called if time, tracefilters, selected entity or agg option changes
|
|
||||||
|
|
||||||
// PNOTE - Can also use 'coordinate' option in antd Select for implementing this - https://ant.design/components/select/
|
|
||||||
const handleFormValuesChange = (changedValues: any): void => {
|
|
||||||
const formFieldName = Object.keys(changedValues)[0];
|
|
||||||
if (formFieldName === 'entity') {
|
|
||||||
const temp_entity = aggregation_options.filter(
|
|
||||||
(item) => item.linked_entity === changedValues[formFieldName],
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
form.setFieldsValue({
|
|
||||||
agg_options: temp_entity.default_selected.title,
|
|
||||||
// PNOTE - TO DO Check if this has the same behaviour as selecting an option?
|
|
||||||
});
|
|
||||||
|
|
||||||
const temp = form.getFieldsValue(['agg_options', 'entity']);
|
|
||||||
|
|
||||||
setSelectedEntity(temp.entity);
|
|
||||||
setSelectedAggOption(temp.agg_options);
|
|
||||||
//form.setFieldsValue({ agg_options: aggregation_options.filter( item => item.linked_entity === selectedEntity )[0] }); //reset product selection
|
|
||||||
// PNOTE - https://stackoverflow.com/questions/64377293/update-select-option-list-based-on-other-select-field-selection-ant-design
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formFieldName === 'agg_options') {
|
|
||||||
setSelectedAggOption(changedValues[formFieldName]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CustomVisualizationsTitle>Custom Visualizations</CustomVisualizationsTitle>
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
onValuesChange={handleFormValuesChange}
|
|
||||||
initialValues={{
|
|
||||||
agg_options: 'Count',
|
|
||||||
chart_style: 'line',
|
|
||||||
interval: '5m',
|
|
||||||
group_by: 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<Form.Item name="entity">
|
|
||||||
<Select defaultValue={selectedEntity} style={{ width: 120 }} allowClear>
|
|
||||||
{entity.map((item) => (
|
|
||||||
<Option key={item.key} value={item.dataindex}>
|
|
||||||
{item.title}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="agg_options">
|
|
||||||
<Select style={{ width: 120 }} allowClear>
|
|
||||||
{aggregation_options
|
|
||||||
.filter((item) => item.linked_entity === selectedEntity)[0]
|
|
||||||
.options_available.map((item) => (
|
|
||||||
<Option key={item.dataindex} value={item.dataindex}>
|
|
||||||
{item.title}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="chart_style">
|
|
||||||
<Select style={{ width: 120 }} allowClear>
|
|
||||||
<Option value="line">Line Chart</Option>
|
|
||||||
<Option value="bar">Bar Chart</Option>
|
|
||||||
<Option value="area">Area Chart</Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item name="interval">
|
|
||||||
<Select style={{ width: 120 }} allowClear>
|
|
||||||
<Option value="1m">1 min</Option>
|
|
||||||
<Option value="5m">5 min</Option>
|
|
||||||
<Option value="30m">30 min</Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{/* Need heading for each option */}
|
|
||||||
<Form.Item name="group_by">
|
|
||||||
<Select style={{ width: 120 }} allowClear>
|
|
||||||
<Option value="none">Group By</Option>
|
|
||||||
<Option value="status">Status Code</Option>
|
|
||||||
<Option value="protocol">Protocol</Option>
|
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
|
||||||
</Space>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
<CustomGraphContainer>
|
|
||||||
<Graph
|
|
||||||
type="line"
|
|
||||||
data={{
|
|
||||||
labels: filteredTraceMetrics.map((s) => new Date(s.timestamp / 1000000)),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: filteredTraceMetrics.map((e) => e.value),
|
|
||||||
borderColor: colors[0],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</CustomGraphContainer>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (
|
|
||||||
state: AppState,
|
|
||||||
): {
|
|
||||||
filteredTraceMetrics: customMetricsItem[];
|
|
||||||
globalTime: GlobalTime;
|
|
||||||
traceFilters: TraceFilters;
|
|
||||||
} => {
|
|
||||||
return {
|
|
||||||
filteredTraceMetrics: state.metricsData.customMetricsItem,
|
|
||||||
globalTime: state.globalTime,
|
|
||||||
traceFilters: state.traceFilters,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TraceCustomVisualizations = connect(mapStateToProps, {
|
|
||||||
getFilteredTraceMetrics: getFilteredTraceMetrics,
|
|
||||||
})(_TraceCustomVisualizations);
|
|
@ -1,17 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { TraceCustomVisualizations } from './TraceCustomVisualizations';
|
|
||||||
import { TraceFilter } from './TraceFilter';
|
|
||||||
import { TraceList } from './TraceList';
|
|
||||||
|
|
||||||
const TraceDetail = (): JSX.Element => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TraceFilter />
|
|
||||||
<TraceCustomVisualizations />
|
|
||||||
<TraceList />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TraceDetail;
|
|
@ -1,487 +0,0 @@
|
|||||||
import { AutoComplete, Button, Form, Input, Select, Typography } from 'antd';
|
|
||||||
import FormItem from 'antd/lib/form/FormItem';
|
|
||||||
import { Store } from 'antd/lib/form/interface';
|
|
||||||
import api from 'api';
|
|
||||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
|
||||||
import React, {
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { connect, useSelector } from 'react-redux';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import { fetchTraces, TraceFilters, updateTraceFilters } from 'store/actions';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { GlobalTime } from 'types/actions/globalTime';
|
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
|
||||||
|
|
||||||
import { FilterStateDisplay } from './FilterStateDisplay';
|
|
||||||
import LatencyModalForm from './LatencyModalForm';
|
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
const InfoWrapper = styled.div`
|
|
||||||
padding-top: 10px;
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 12px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface TraceFilterProps {
|
|
||||||
traceFilters: TraceFilters;
|
|
||||||
globalTime: GlobalTime;
|
|
||||||
updateTraceFilters: (props: TraceFilters) => void;
|
|
||||||
fetchTraces: (globalTime: GlobalTime, filter_params: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TagKeyOptionItem {
|
|
||||||
tagKeys: string;
|
|
||||||
tagCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISpanKind {
|
|
||||||
label: 'SERVER' | 'CLIENT';
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _TraceFilter = (props: TraceFilterProps): JSX.Element => {
|
|
||||||
const [serviceList, setServiceList] = useState<string[]>([]);
|
|
||||||
const [operationList, setOperationsList] = useState<string[]>([]);
|
|
||||||
const [tagKeyOptions, setTagKeyOptions] = useState<TagKeyOptionItem[]>([]);
|
|
||||||
const location = useLocation();
|
|
||||||
const urlParams = useMemo(() => {
|
|
||||||
return new URLSearchParams(location.search.split('?')[1]);
|
|
||||||
}, [location.search]);
|
|
||||||
|
|
||||||
const { loading } = useSelector<AppState, GlobalReducer>(
|
|
||||||
(state) => state.globalTime,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { updateTraceFilters, traceFilters, globalTime, fetchTraces } = props;
|
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
|
||||||
|
|
||||||
const [latencyFilterValues, setLatencyFilterValues] = useState<{
|
|
||||||
min: string;
|
|
||||||
max: string;
|
|
||||||
}>({
|
|
||||||
min: '100',
|
|
||||||
max: '500',
|
|
||||||
});
|
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const [form_basefilter] = Form.useForm();
|
|
||||||
|
|
||||||
const handleChangeOperation = useCallback(
|
|
||||||
(value: string) => {
|
|
||||||
updateTraceFilters({ ...traceFilters, operation: value });
|
|
||||||
},
|
|
||||||
[traceFilters, updateTraceFilters],
|
|
||||||
);
|
|
||||||
|
|
||||||
const populateData = useCallback(
|
|
||||||
(value: string) => {
|
|
||||||
if (loading === false) {
|
|
||||||
const service_request = '/service/' + value + '/operations';
|
|
||||||
api.get<string[]>(service_request).then((response) => {
|
|
||||||
// form_basefilter.resetFields(['operation',])
|
|
||||||
setOperationsList(response.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
const tagkeyoptions_request = '/tags?service=' + value;
|
|
||||||
api.get<TagKeyOptionItem[]>(tagkeyoptions_request).then((response) => {
|
|
||||||
setTagKeyOptions(response.data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[loading],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChangeService = useCallback(
|
|
||||||
(value: string) => {
|
|
||||||
populateData(value);
|
|
||||||
updateTraceFilters({ ...traceFilters, service: value });
|
|
||||||
},
|
|
||||||
[traceFilters, updateTraceFilters, populateData],
|
|
||||||
);
|
|
||||||
|
|
||||||
const spanKindList: ISpanKind[] = [
|
|
||||||
{
|
|
||||||
label: 'SERVER',
|
|
||||||
value: '2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'CLIENT',
|
|
||||||
value: '3',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleApplyFilterForm = useCallback(
|
|
||||||
(values: any): void => {
|
|
||||||
updateTraceFilters({
|
|
||||||
service: values.service,
|
|
||||||
operation: values.operation,
|
|
||||||
latency: {
|
|
||||||
max: '',
|
|
||||||
min: '',
|
|
||||||
},
|
|
||||||
kind: values.kind,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[updateTraceFilters],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleApplyFilterForm({
|
|
||||||
service: '',
|
|
||||||
tags: [],
|
|
||||||
operation: '',
|
|
||||||
latency: { min: '', max: '' },
|
|
||||||
kind: '',
|
|
||||||
});
|
|
||||||
}, [handleApplyFilterForm]);
|
|
||||||
|
|
||||||
const onTagFormSubmit = useCallback(
|
|
||||||
(values) => {
|
|
||||||
if (traceFilters.tags) {
|
|
||||||
// If there are existing tag filters present
|
|
||||||
updateTraceFilters({
|
|
||||||
service: traceFilters.service,
|
|
||||||
operation: traceFilters.operation,
|
|
||||||
latency: traceFilters.latency,
|
|
||||||
tags: [
|
|
||||||
...traceFilters.tags,
|
|
||||||
{
|
|
||||||
key: values.tag_key,
|
|
||||||
value: values.tag_value,
|
|
||||||
operator: values.operator,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
kind: traceFilters.kind,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
updateTraceFilters({
|
|
||||||
service: traceFilters.service,
|
|
||||||
operation: traceFilters.operation,
|
|
||||||
latency: traceFilters.latency,
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
key: values.tag_key,
|
|
||||||
value: values.tag_value,
|
|
||||||
operator: values.operator,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
kind: traceFilters.kind,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
form.resetFields();
|
|
||||||
},
|
|
||||||
[form, traceFilters, updateTraceFilters],
|
|
||||||
);
|
|
||||||
|
|
||||||
const counter = useRef(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (loading === false && counter.current === 0) {
|
|
||||||
counter.current = 1;
|
|
||||||
api
|
|
||||||
.get<string[]>(`/services/list`)
|
|
||||||
.then((response) => {
|
|
||||||
setServiceList(response.data);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
const operationName = urlParams.get(METRICS_PAGE_QUERY_PARAM.operation);
|
|
||||||
const serviceName = urlParams.get(METRICS_PAGE_QUERY_PARAM.service);
|
|
||||||
const errorTag = urlParams.get(METRICS_PAGE_QUERY_PARAM.error);
|
|
||||||
if (operationName && serviceName) {
|
|
||||||
updateTraceFilters({
|
|
||||||
...traceFilters,
|
|
||||||
operation: operationName,
|
|
||||||
service: serviceName,
|
|
||||||
kind: '',
|
|
||||||
});
|
|
||||||
populateData(serviceName);
|
|
||||||
} else if (serviceName && errorTag) {
|
|
||||||
updateTraceFilters({
|
|
||||||
...traceFilters,
|
|
||||||
service: serviceName,
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
key: METRICS_PAGE_QUERY_PARAM.error,
|
|
||||||
value: errorTag,
|
|
||||||
operator: 'equals',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
kind: '',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (operationName) {
|
|
||||||
handleChangeOperation(operationName);
|
|
||||||
}
|
|
||||||
if (serviceName) {
|
|
||||||
handleChangeService(serviceName);
|
|
||||||
}
|
|
||||||
if (errorTag) {
|
|
||||||
onTagFormSubmit({
|
|
||||||
tag_key: METRICS_PAGE_QUERY_PARAM.error,
|
|
||||||
tag_value: errorTag,
|
|
||||||
operator: 'equals',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
handleChangeOperation,
|
|
||||||
onTagFormSubmit,
|
|
||||||
handleChangeService,
|
|
||||||
traceFilters,
|
|
||||||
urlParams,
|
|
||||||
updateTraceFilters,
|
|
||||||
populateData,
|
|
||||||
loading,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let request_string =
|
|
||||||
'service=' +
|
|
||||||
traceFilters.service +
|
|
||||||
'&operation=' +
|
|
||||||
traceFilters.operation +
|
|
||||||
'&maxDuration=' +
|
|
||||||
traceFilters.latency?.max +
|
|
||||||
'&minDuration=' +
|
|
||||||
traceFilters.latency?.min +
|
|
||||||
'&kind=' +
|
|
||||||
traceFilters.kind;
|
|
||||||
if (traceFilters.tags)
|
|
||||||
request_string =
|
|
||||||
request_string +
|
|
||||||
'&tags=' +
|
|
||||||
encodeURIComponent(JSON.stringify(traceFilters.tags));
|
|
||||||
|
|
||||||
if (loading === false) {
|
|
||||||
fetchTraces(globalTime, request_string);
|
|
||||||
}
|
|
||||||
}, [traceFilters, fetchTraces, loading, globalTime]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let latencyButtonText = 'Latency';
|
|
||||||
if (traceFilters.latency?.min === '' && traceFilters.latency?.max !== '')
|
|
||||||
latencyButtonText =
|
|
||||||
'Latency<' +
|
|
||||||
(parseInt(traceFilters.latency?.max) / 1000000).toString() +
|
|
||||||
'ms';
|
|
||||||
else if (traceFilters.latency?.min !== '' && traceFilters.latency?.max === '')
|
|
||||||
latencyButtonText =
|
|
||||||
'Latency>' +
|
|
||||||
(parseInt(traceFilters.latency?.min) / 1000000).toString() +
|
|
||||||
'ms';
|
|
||||||
else if (
|
|
||||||
traceFilters.latency !== undefined &&
|
|
||||||
traceFilters.latency?.min !== '' &&
|
|
||||||
traceFilters.latency?.max !== ''
|
|
||||||
)
|
|
||||||
latencyButtonText =
|
|
||||||
(parseInt(traceFilters.latency.min) / 1000000).toString() +
|
|
||||||
'ms <Latency<' +
|
|
||||||
(parseInt(traceFilters.latency.max) / 1000000).toString() +
|
|
||||||
'ms';
|
|
||||||
|
|
||||||
form_basefilter.setFieldsValue({ latency: latencyButtonText });
|
|
||||||
form_basefilter.setFieldsValue({ service: traceFilters.service });
|
|
||||||
form_basefilter.setFieldsValue({ operation: traceFilters.operation });
|
|
||||||
form_basefilter.setFieldsValue({ kind: traceFilters.kind });
|
|
||||||
}, [traceFilters, form_basefilter]);
|
|
||||||
|
|
||||||
const onLatencyButtonClick = (): void => {
|
|
||||||
setModalVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onLatencyModalApply = (values: Store): void => {
|
|
||||||
setModalVisible(false);
|
|
||||||
const { min, max } = values;
|
|
||||||
updateTraceFilters({
|
|
||||||
...traceFilters,
|
|
||||||
latency: {
|
|
||||||
min: min ? (parseInt(min) * 1000000).toString() : '',
|
|
||||||
max: max ? (parseInt(max) * 1000000).toString() : '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setLatencyFilterValues({ min, max });
|
|
||||||
};
|
|
||||||
|
|
||||||
// For autocomplete
|
|
||||||
//Setting value when autocomplete field is changed
|
|
||||||
const onChangeTagKey = (data: string): void => {
|
|
||||||
form.setFieldsValue({ tag_key: data });
|
|
||||||
};
|
|
||||||
|
|
||||||
const dataSource = ['status:200'];
|
|
||||||
const children = [];
|
|
||||||
for (let i = 0; i < dataSource.length; i++) {
|
|
||||||
children.push(
|
|
||||||
<Option value={dataSource[i]} key={dataSource[i]}>
|
|
||||||
{dataSource[i]}
|
|
||||||
</Option>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return (): void => {
|
|
||||||
updateTraceFilters({
|
|
||||||
service: '',
|
|
||||||
operation: '',
|
|
||||||
tags: [],
|
|
||||||
latency: { min: '', max: '' },
|
|
||||||
kind: '',
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}, [updateTraceFilters]);
|
|
||||||
|
|
||||||
const handleChangeSpanKind = (value = ''): void => {
|
|
||||||
updateTraceFilters({ ...traceFilters, kind: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Typography>Filter Traces</Typography>
|
|
||||||
<Form
|
|
||||||
form={form_basefilter}
|
|
||||||
layout="inline"
|
|
||||||
onFinish={handleApplyFilterForm}
|
|
||||||
initialValues={{ service: '', operation: '', latency: 'Latency' }}
|
|
||||||
style={{ marginTop: 10, marginBottom: 10 }}
|
|
||||||
>
|
|
||||||
<FormItem rules={[{ required: true }]} name="service">
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
style={{ width: 180 }}
|
|
||||||
onChange={handleChangeService}
|
|
||||||
placeholder="Select Service"
|
|
||||||
allowClear
|
|
||||||
>
|
|
||||||
{serviceList.map((s) => (
|
|
||||||
<Option key={s} value={s}>
|
|
||||||
{s}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem name="operation">
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
style={{ width: 180 }}
|
|
||||||
onChange={handleChangeOperation}
|
|
||||||
placeholder="Select Operation"
|
|
||||||
allowClear
|
|
||||||
>
|
|
||||||
{operationList.map((item) => (
|
|
||||||
<Option key={item} value={item}>
|
|
||||||
{item}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem name="latency">
|
|
||||||
<Input
|
|
||||||
style={{ width: 200 }}
|
|
||||||
type="button"
|
|
||||||
onClick={onLatencyButtonClick}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem name="spanKind">
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
style={{ width: 180 }}
|
|
||||||
onChange={handleChangeSpanKind}
|
|
||||||
placeholder="Select Span Kind"
|
|
||||||
allowClear
|
|
||||||
>
|
|
||||||
{spanKindList.map((spanKind) => (
|
|
||||||
<Option value={spanKind.value} key={spanKind.value}>
|
|
||||||
{spanKind.label}
|
|
||||||
</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
<FilterStateDisplay />
|
|
||||||
|
|
||||||
<InfoWrapper>Select Service to get Tag suggestions </InfoWrapper>
|
|
||||||
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
layout="inline"
|
|
||||||
onFinish={onTagFormSubmit}
|
|
||||||
initialValues={{ operator: 'equals' }}
|
|
||||||
style={{ marginTop: 10, marginBottom: 10 }}
|
|
||||||
>
|
|
||||||
<FormItem rules={[{ required: true }]} name="tag_key">
|
|
||||||
<AutoComplete
|
|
||||||
options={tagKeyOptions.map((s) => {
|
|
||||||
return { value: s.tagKeys };
|
|
||||||
})}
|
|
||||||
style={{ width: 200, textAlign: 'center' }}
|
|
||||||
onChange={onChangeTagKey}
|
|
||||||
filterOption={(inputValue, option): boolean =>
|
|
||||||
option?.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1
|
|
||||||
}
|
|
||||||
placeholder="Tag Key"
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem name="operator">
|
|
||||||
<Select style={{ width: 120, textAlign: 'center' }}>
|
|
||||||
<Option value="equals">EQUAL</Option>
|
|
||||||
<Option value="contains">CONTAINS</Option>
|
|
||||||
<Option value="regex">REGEX</Option>
|
|
||||||
</Select>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem rules={[{ required: true }]} name="tag_value">
|
|
||||||
<Input
|
|
||||||
style={{ width: 160, textAlign: 'center' }}
|
|
||||||
placeholder="Tag Value"
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem>
|
|
||||||
<Button type="primary" htmlType="submit">
|
|
||||||
{' '}
|
|
||||||
Apply Tag Filter{' '}
|
|
||||||
</Button>
|
|
||||||
</FormItem>
|
|
||||||
</Form>
|
|
||||||
|
|
||||||
{modalVisible && (
|
|
||||||
<LatencyModalForm
|
|
||||||
onCreate={onLatencyModalApply}
|
|
||||||
latencyFilterValues={latencyFilterValues}
|
|
||||||
onCancel={(): void => {
|
|
||||||
setModalVisible(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (
|
|
||||||
state: AppState,
|
|
||||||
): { traceFilters: TraceFilters; globalTime: GlobalTime } => {
|
|
||||||
return { traceFilters: state.traceFilters, globalTime: state.globalTime };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TraceFilter = connect(mapStateToProps, {
|
|
||||||
updateTraceFilters: updateTraceFilters,
|
|
||||||
fetchTraces: fetchTraces,
|
|
||||||
})(_TraceFilter);
|
|
@ -1,160 +0,0 @@
|
|||||||
import { Space, Table } from 'antd';
|
|
||||||
import ROUTES from 'constants/routes';
|
|
||||||
import moment from 'moment';
|
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { useHistory } from 'react-router-dom';
|
|
||||||
import { fetchTraces, pushDStree, traceResponseNew } from 'store/actions';
|
|
||||||
import { AppState } from 'store/reducers';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { isOnboardingSkipped } from 'utils/app';
|
|
||||||
|
|
||||||
const StyledTable = styled(Table)`
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TraceHeader = styled.div`
|
|
||||||
margin: 16px 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface TraceListProps {
|
|
||||||
traces: traceResponseNew;
|
|
||||||
fetchTraces: Function;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableDataSourceItem {
|
|
||||||
key: string;
|
|
||||||
spanid: string;
|
|
||||||
traceid: string;
|
|
||||||
operationName: string;
|
|
||||||
startTime: number;
|
|
||||||
duration: number;
|
|
||||||
service: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _TraceList = (props: TraceListProps) => {
|
|
||||||
// PNOTE (TO DO) - Currently this use of useEffect gives warning. May need to memoise fetchtraces - https://stackoverflow.com/questions/55840294/how-to-fix-missing-dependency-warning-when-using-useeffect-react-hook
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
props.fetchTraces();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const columns: any = [
|
|
||||||
{
|
|
||||||
title: 'Start Time',
|
|
||||||
dataIndex: 'startTime',
|
|
||||||
key: 'startTime',
|
|
||||||
sorter: (a: any, b: any) => a.startTime - b.startTime,
|
|
||||||
sortDirections: ['descend', 'ascend'],
|
|
||||||
render: (value: number) => moment(value).format('YYYY-MM-DD hh:mm:ss'),
|
|
||||||
|
|
||||||
// new Date() assumes input in milliseconds. Start Time stamp returned by druid api for span list is in ms
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Service',
|
|
||||||
dataIndex: 'service',
|
|
||||||
key: 'service',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Operation',
|
|
||||||
dataIndex: 'operationName',
|
|
||||||
key: 'operationName',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Duration (in ms)',
|
|
||||||
dataIndex: 'duration',
|
|
||||||
key: 'duration',
|
|
||||||
sorter: (a: any, b: any) => a.duration - b.duration,
|
|
||||||
sortDirections: ['descend', 'ascend'],
|
|
||||||
render: (value: number) => (value / 1000000).toFixed(2),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dataSource: TableDataSourceItem[] = [];
|
|
||||||
|
|
||||||
const renderTraces = () => {
|
|
||||||
if (
|
|
||||||
typeof props.traces[0] !== 'undefined' &&
|
|
||||||
props.traces[0].events.length > 0
|
|
||||||
) {
|
|
||||||
props.traces[0].events.map(
|
|
||||||
(item: (number | string | string[] | pushDStree[])[], index) => {
|
|
||||||
if (
|
|
||||||
typeof item[0] === 'number' &&
|
|
||||||
typeof item[4] === 'string' &&
|
|
||||||
typeof item[6] === 'string' &&
|
|
||||||
typeof item[1] === 'string' &&
|
|
||||||
typeof item[2] === 'string' &&
|
|
||||||
typeof item[3] === 'string'
|
|
||||||
)
|
|
||||||
dataSource.push({
|
|
||||||
startTime: item[0],
|
|
||||||
operationName: item[4],
|
|
||||||
duration: parseInt(item[6]),
|
|
||||||
spanid: item[1],
|
|
||||||
traceid: item[2],
|
|
||||||
key: index.toString(),
|
|
||||||
service: item[3],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
//antd table in typescript - https://codesandbox.io/s/react-typescript-669cv
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledTable
|
|
||||||
dataSource={dataSource}
|
|
||||||
columns={columns}
|
|
||||||
size="middle"
|
|
||||||
rowClassName=""
|
|
||||||
onRow={(record) => ({
|
|
||||||
onClick: () => {
|
|
||||||
history.push({
|
|
||||||
pathname: ROUTES.TRACES + '/' + record.traceid,
|
|
||||||
state: {
|
|
||||||
spanId: record.spanid,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (isOnboardingSkipped()) {
|
|
||||||
return (
|
|
||||||
<Space
|
|
||||||
style={{ width: '100%', margin: '40px 0', justifyContent: 'center' }}
|
|
||||||
>
|
|
||||||
No spans found. Please add instrumentation (follow this
|
|
||||||
<a
|
|
||||||
href={'https://signoz.io/docs/instrumentation/overview'}
|
|
||||||
target={'_blank'}
|
|
||||||
style={{ marginLeft: 3 }}
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
guide
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <div> No spans found for given filter!</div>;
|
|
||||||
}
|
|
||||||
}; // end of renderTraces
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TraceHeader>List of filtered spans</TraceHeader>
|
|
||||||
<div>{renderTraces()}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapStateToProps = (state: AppState): { traces: traceResponseNew } => {
|
|
||||||
return { traces: state.traces };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TraceList = connect(mapStateToProps, {
|
|
||||||
fetchTraces: fetchTraces,
|
|
||||||
})(_TraceList);
|
|
@ -14,8 +14,13 @@ import { Card } from './styles';
|
|||||||
|
|
||||||
interface UsageExplorerProps {
|
interface UsageExplorerProps {
|
||||||
usageData: usageDataItem[];
|
usageData: usageDataItem[];
|
||||||
getUsageData: Function;
|
getUsageData: (
|
||||||
getServicesList: Function;
|
minTime: number,
|
||||||
|
maxTime: number,
|
||||||
|
selectedInterval: any,
|
||||||
|
selectedService: string,
|
||||||
|
) => void;
|
||||||
|
getServicesList: (time: GlobalTime) => void;
|
||||||
globalTime: GlobalTime;
|
globalTime: GlobalTime;
|
||||||
servicesList: servicesListItem[];
|
servicesList: servicesListItem[];
|
||||||
totalCount: number;
|
totalCount: number;
|
||||||
@ -47,27 +52,30 @@ const interval = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const _UsageExplorer = (props: UsageExplorerProps) => {
|
const _UsageExplorer = (props: UsageExplorerProps): JSX.Element => {
|
||||||
const [selectedTime, setSelectedTime] = useState(timeDaysOptions[1]);
|
const [selectedTime, setSelectedTime] = useState(timeDaysOptions[1]);
|
||||||
const [selectedInterval, setSelectedInterval] = useState(interval[2]);
|
const [selectedInterval, setSelectedInterval] = useState(interval[2]);
|
||||||
const [selectedService, setSelectedService] = useState<string>('');
|
const [selectedService, setSelectedService] = useState<string>('');
|
||||||
const { loading } = useSelector<AppState, GlobalReducer>(
|
const { loading } = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
);
|
);
|
||||||
|
const {
|
||||||
|
getServicesList,
|
||||||
|
getUsageData,
|
||||||
|
globalTime,
|
||||||
|
servicesList,
|
||||||
|
totalCount,
|
||||||
|
usageData,
|
||||||
|
} = props;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedTime && selectedInterval) {
|
if (selectedTime && selectedInterval) {
|
||||||
const maxTime = new Date().getTime() * 1000000;
|
const maxTime = new Date().getTime() * 1000000;
|
||||||
const minTime = maxTime - selectedTime.value * 24 * 3600000 * 1000000;
|
const minTime = maxTime - selectedTime.value * 24 * 3600000 * 1000000;
|
||||||
|
|
||||||
props.getUsageData(
|
getUsageData(minTime, maxTime, selectedInterval.value, selectedService);
|
||||||
minTime,
|
|
||||||
maxTime,
|
|
||||||
selectedInterval!.value,
|
|
||||||
selectedService,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, [selectedTime, selectedInterval, selectedService]);
|
}, [selectedTime, selectedInterval, selectedService, getUsageData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
/*
|
/*
|
||||||
@ -75,16 +83,16 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
Check this issue: https://github.com/SigNoz/signoz/issues/110
|
Check this issue: https://github.com/SigNoz/signoz/issues/110
|
||||||
*/
|
*/
|
||||||
if (loading) {
|
if (loading) {
|
||||||
props.getServicesList(props.globalTime);
|
getServicesList(globalTime);
|
||||||
}
|
}
|
||||||
}, [loading, props]);
|
}, [loading, globalTime, getServicesList]);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
labels: props.usageData.map((s) => new Date(s.timestamp / 1000000)),
|
labels: usageData.map((s) => new Date(s.timestamp / 1000000)),
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: 'Span Count',
|
label: 'Span Count',
|
||||||
data: props.usageData.map((s) => s.count),
|
data: usageData.map((s) => s.count),
|
||||||
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||||
borderColor: 'rgba(255, 99, 132, 1)',
|
borderColor: 'rgba(255, 99, 132, 1)',
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
@ -94,11 +102,10 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{/* PNOTE - TODO - Keep it in reponsive row column tab */}
|
|
||||||
<Space style={{ marginTop: 40, marginLeft: 20 }}>
|
<Space style={{ marginTop: 40, marginLeft: 20 }}>
|
||||||
<Space>
|
<Space>
|
||||||
<Select
|
<Select
|
||||||
onSelect={(value, option) => {
|
onSelect={(value): void => {
|
||||||
setSelectedTime(
|
setSelectedTime(
|
||||||
timeDaysOptions.filter((item) => item.value == parseInt(value))[0],
|
timeDaysOptions.filter((item) => item.value == parseInt(value))[0],
|
||||||
);
|
);
|
||||||
@ -106,42 +113,48 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
value={selectedTime.label}
|
value={selectedTime.label}
|
||||||
>
|
>
|
||||||
{timeDaysOptions.map(({ value, label }) => (
|
{timeDaysOptions.map(({ value, label }) => (
|
||||||
<Option value={value}>{label}</Option>
|
<Option key={value} value={value}>
|
||||||
|
{label}
|
||||||
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<Select
|
<Select
|
||||||
onSelect={(value) => {
|
onSelect={(value): void => {
|
||||||
setSelectedInterval(
|
setSelectedInterval(
|
||||||
interval.filter((item) => item!.value === parseInt(value))[0],
|
interval.filter((item) => item.value === parseInt(value))[0],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
value={selectedInterval!.label}
|
value={selectedInterval.label}
|
||||||
>
|
>
|
||||||
{interval
|
{interval
|
||||||
.filter((interval) => interval!.applicableOn.includes(selectedTime))
|
.filter((interval) => interval.applicableOn.includes(selectedTime))
|
||||||
.map((item) => (
|
.map((item) => (
|
||||||
<Option value={item!.value}>{item!.label}</Option>
|
<Option key={item.label} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
<Space>
|
<Space>
|
||||||
<Select
|
<Select
|
||||||
onSelect={(value) => {
|
onSelect={(value): void => {
|
||||||
setSelectedService(value);
|
setSelectedService(value);
|
||||||
}}
|
}}
|
||||||
value={selectedService || 'All Services'}
|
value={selectedService || 'All Services'}
|
||||||
>
|
>
|
||||||
<Option value={''}>All Services</Option>
|
<Option value={''}>All Services</Option>
|
||||||
{props.servicesList.map((service) => (
|
{servicesList.map((service) => (
|
||||||
<Option value={service.serviceName}>{service.serviceName}</Option>
|
<Option key={service.serviceName} value={service.serviceName}>
|
||||||
|
{service.serviceName}
|
||||||
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Space>
|
</Space>
|
||||||
|
|
||||||
{isOnboardingSkipped() && props.totalCount === 0 ? (
|
{isOnboardingSkipped() && totalCount === 0 ? (
|
||||||
<Space
|
<Space
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@ -163,7 +176,7 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
</Space>
|
</Space>
|
||||||
) : (
|
) : (
|
||||||
<Space style={{ display: 'block', marginLeft: 20, width: 200 }}>
|
<Space style={{ display: 'block', marginLeft: 20, width: 200 }}>
|
||||||
{`Total count is ${props.totalCount}`}
|
{`Total count is ${totalCount}`}
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
@ -191,7 +204,7 @@ const mapStateToProps = (
|
|||||||
totalCount: totalCount,
|
totalCount: totalCount,
|
||||||
usageData: state.usageDate,
|
usageData: state.usageDate,
|
||||||
globalTime: state.globalTime,
|
globalTime: state.globalTime,
|
||||||
servicesList: state.metricsData.serviceList,
|
servicesList: state.metricsData.serviceList || [],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import MetricsApplicationContainer from 'container/MetricsApplication';
|
import MetricsApplicationContainer from 'container/MetricsApplication';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { connect, useSelector } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
@ -38,10 +38,10 @@ const MetricsApplication = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return (): void => {
|
||||||
resetInitialData();
|
resetInitialData();
|
||||||
};
|
};
|
||||||
}, [servicename, getInitialData, selectedTime]);
|
}, [servicename, getInitialData, selectedTime, resetInitialData]);
|
||||||
|
|
||||||
if (metricsApplicationLoading) {
|
if (metricsApplicationLoading) {
|
||||||
return <Spinner tip="Loading..." />;
|
return <Spinner tip="Loading..." />;
|
||||||
|
@ -9,8 +9,8 @@ import { bindActionCreators } from 'redux';
|
|||||||
import { ThunkDispatch } from 'redux-thunk';
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
import {
|
import {
|
||||||
GetInitialTraceData,
|
GetInitialTraceData,
|
||||||
ResetRaceData,
|
|
||||||
GetInitialTraceDataProps,
|
GetInitialTraceDataProps,
|
||||||
|
ResetRaceData,
|
||||||
} from 'store/actions/trace';
|
} from 'store/actions/trace';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import AppActions from 'types/actions';
|
import AppActions from 'types/actions';
|
||||||
@ -40,7 +40,7 @@ const TraceDetail = ({
|
|||||||
return (): void => {
|
return (): void => {
|
||||||
resetTraceData();
|
resetTraceData();
|
||||||
};
|
};
|
||||||
}, [getInitialTraceData, loading, selectedTime]);
|
}, [getInitialTraceData, loading, selectedTime, resetTraceData]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <Typography>{errorMessage}</Typography>;
|
return <Typography>{errorMessage}</Typography>;
|
||||||
|
@ -6,7 +6,7 @@ export const ResetInitialData = (): ((
|
|||||||
dispatch: Dispatch<AppActions>,
|
dispatch: Dispatch<AppActions>,
|
||||||
getState: () => AppState,
|
getState: () => AppState,
|
||||||
) => void) => {
|
) => void) => {
|
||||||
return (dispatch, getState): void => {
|
return (dispatch): void => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'RESET_INITIAL_APPLICATION_DATA',
|
type: 'RESET_INITIAL_APPLICATION_DATA',
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,7 @@ export interface servicesAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getServiceMapItems = (globalTime: GlobalTime) => {
|
export const getServiceMapItems = (globalTime: GlobalTime) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch): Promise<void> => {
|
||||||
dispatch<serviceMapItemAction>({
|
dispatch<serviceMapItemAction>({
|
||||||
type: ActionTypes.getServiceMapItems,
|
type: ActionTypes.getServiceMapItems,
|
||||||
payload: [],
|
payload: [],
|
||||||
@ -60,7 +60,7 @@ export const getServiceMapItems = (globalTime: GlobalTime) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => {
|
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch): Promise<void> => {
|
||||||
dispatch<servicesAction>({
|
dispatch<servicesAction>({
|
||||||
type: ActionTypes.getServices,
|
type: ActionTypes.getServices,
|
||||||
payload: [],
|
payload: [],
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from './getInitialData';
|
export * from './getInitialData';
|
||||||
|
export * from './resetTraceDetails';
|
||||||
export * from './updateSelectedAggOption';
|
export * from './updateSelectedAggOption';
|
||||||
export * from './updateSelectedEntity';
|
export * from './updateSelectedEntity';
|
||||||
export * from './updateSelectedKind';
|
export * from './updateSelectedKind';
|
||||||
@ -6,4 +7,3 @@ export * from './updateSelectedLatency';
|
|||||||
export * from './updateSelectedOperation';
|
export * from './updateSelectedOperation';
|
||||||
export * from './updateSelectedService';
|
export * from './updateSelectedService';
|
||||||
export * from './updateSelectedTags';
|
export * from './updateSelectedTags';
|
||||||
export * from './resetTraceDetails';
|
|
||||||
|
@ -26,7 +26,9 @@ export interface updateTraceFiltersAction {
|
|||||||
payload: TraceFilters;
|
payload: TraceFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateTraceFilters = (traceFilters: TraceFilters) => {
|
export const updateTraceFilters = (
|
||||||
|
traceFilters: TraceFilters,
|
||||||
|
): updateTraceFiltersAction => {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.updateTraceFilters,
|
type: ActionTypes.updateTraceFilters,
|
||||||
payload: traceFilters,
|
payload: traceFilters,
|
||||||
|
@ -20,7 +20,7 @@ export const getUsageData = (
|
|||||||
step: number,
|
step: number,
|
||||||
service: string,
|
service: string,
|
||||||
) => {
|
) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch): Promise<void> => {
|
||||||
const request_string = `/usage?start=${toUTCEpoch(minTime)}&end=${toUTCEpoch(
|
const request_string = `/usage?start=${toUTCEpoch(minTime)}&end=${toUTCEpoch(
|
||||||
maxTime,
|
maxTime,
|
||||||
)}&step=${step}&service=${service ? service : ''}`;
|
)}&step=${step}&service=${service ? service : ''}`;
|
||||||
|
@ -4,7 +4,6 @@ import appReducer from './app';
|
|||||||
import dashboardReducer from './dashboard';
|
import dashboardReducer from './dashboard';
|
||||||
import globalTimeReducer from './global';
|
import globalTimeReducer from './global';
|
||||||
import metricsReducers from './metric';
|
import metricsReducers from './metric';
|
||||||
import { metricsReducer } from './metrics';
|
|
||||||
import { ServiceMapReducer } from './serviceMap';
|
import { ServiceMapReducer } from './serviceMap';
|
||||||
import { traceReducer } from './trace';
|
import { traceReducer } from './trace';
|
||||||
import TraceFilterReducer from './traceFilters';
|
import TraceFilterReducer from './traceFilters';
|
||||||
@ -18,7 +17,6 @@ const reducers = combineReducers({
|
|||||||
trace: traceReducer,
|
trace: traceReducer,
|
||||||
usageDate: usageDataReducer,
|
usageDate: usageDataReducer,
|
||||||
globalTime: globalTimeReducer,
|
globalTime: globalTimeReducer,
|
||||||
metricsData: metricsReducer,
|
|
||||||
serviceMap: ServiceMapReducer,
|
serviceMap: ServiceMapReducer,
|
||||||
dashboards: dashboardReducer,
|
dashboards: dashboardReducer,
|
||||||
app: appReducer,
|
app: appReducer,
|
||||||
|
@ -5,8 +5,8 @@ import {
|
|||||||
GET_SERVICE_LIST_ERROR,
|
GET_SERVICE_LIST_ERROR,
|
||||||
GET_SERVICE_LIST_LOADING_START,
|
GET_SERVICE_LIST_LOADING_START,
|
||||||
GET_SERVICE_LIST_SUCCESS,
|
GET_SERVICE_LIST_SUCCESS,
|
||||||
RESET_INITIAL_APPLICATION_DATA,
|
|
||||||
MetricsActions,
|
MetricsActions,
|
||||||
|
RESET_INITIAL_APPLICATION_DATA,
|
||||||
} from 'types/actions/metrics';
|
} from 'types/actions/metrics';
|
||||||
import InitialValueTypes from 'types/reducer/metrics';
|
import InitialValueTypes from 'types/reducer/metrics';
|
||||||
|
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
import {
|
|
||||||
customMetricsItem,
|
|
||||||
dbOverviewMetricsItem,
|
|
||||||
externalErrCodeMetricsItem,
|
|
||||||
externalMetricsAvgDurationItem,
|
|
||||||
externalMetricsItem,
|
|
||||||
metricItem,
|
|
||||||
servicesListItem,
|
|
||||||
topEndpointListItem,
|
|
||||||
} from 'store/actions/MetricsActions';
|
|
||||||
import { MetricsActionTypes as ActionTypes } from 'store/actions/MetricsActions/metricsActionTypes';
|
|
||||||
|
|
||||||
export type MetricsInitialState = {
|
|
||||||
serviceList?: servicesListItem[];
|
|
||||||
metricItems?: metricItem[];
|
|
||||||
topEndpointListItem?: topEndpointListItem[];
|
|
||||||
externalMetricsAvgDurationItem?: externalMetricsAvgDurationItem[];
|
|
||||||
externalErrCodeMetricsItem?: externalErrCodeMetricsItem[];
|
|
||||||
externalMetricsItem?: externalMetricsItem[];
|
|
||||||
dbOverviewMetricsItem?: dbOverviewMetricsItem[];
|
|
||||||
customMetricsItem?: customMetricsItem[];
|
|
||||||
loading: boolean;
|
|
||||||
};
|
|
||||||
export const metricsInitialState: MetricsInitialState = {
|
|
||||||
serviceList: [],
|
|
||||||
metricItems: [],
|
|
||||||
topEndpointListItem: [],
|
|
||||||
externalMetricsAvgDurationItem: [],
|
|
||||||
externalErrCodeMetricsItem: [],
|
|
||||||
externalMetricsItem: [],
|
|
||||||
dbOverviewMetricsItem: [],
|
|
||||||
customMetricsItem: [],
|
|
||||||
loading: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
type ActionType = {
|
|
||||||
type: string;
|
|
||||||
payload: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const metricsReducer = (
|
|
||||||
state: MetricsInitialState = metricsInitialState,
|
|
||||||
action: ActionType,
|
|
||||||
) => {
|
|
||||||
switch (action.type) {
|
|
||||||
case ActionTypes.getFilteredTraceMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
customMetricsItem: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getServiceMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
metricItems: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getDbOverviewMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
dbOverviewMetricsItem: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getExternalMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
externalMetricsItem: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getTopEndpoints:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
topEndpointListItem: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getErrCodeMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
externalErrCodeMetricsItem: action.payload,
|
|
||||||
};
|
|
||||||
case ActionTypes.getAvgDurationMetrics:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
externalMetricsAvgDurationItem: action.payload,
|
|
||||||
};
|
|
||||||
|
|
||||||
case ActionTypes.getServicesList:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
serviceList: action.payload,
|
|
||||||
};
|
|
||||||
|
|
||||||
case 'UPDATE_INITIAL_VALUE_START': {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
loading: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'UPDATE_INITIAL_VALUE': {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
dbOverviewMetricsItem: action.payload.dbResponse,
|
|
||||||
topEndpointListItem: action.payload.topEndPointsResponse,
|
|
||||||
externalMetricsAvgDurationItem: action.payload.avgExternalDurationResponse,
|
|
||||||
externalErrCodeMetricsItem: action.payload.externalErrorCodeMetricsResponse,
|
|
||||||
metricItems: action.payload.serviceOverViewResponse,
|
|
||||||
externalMetricsItem: action.payload.externalServiceResponse,
|
|
||||||
loading: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
@ -5,7 +5,10 @@ const initialState: serviceMapStore = {
|
|||||||
services: [],
|
services: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ServiceMapReducer = (state = initialState, action: Action) => {
|
export const ServiceMapReducer = (
|
||||||
|
state = initialState,
|
||||||
|
action: Action,
|
||||||
|
): serviceMapStore => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.getServiceMapItems:
|
case ActionTypes.getServiceMapItems:
|
||||||
return {
|
return {
|
||||||
|
@ -3,7 +3,9 @@ import {
|
|||||||
GET_TRACE_INITIAL_DATA_SUCCESS,
|
GET_TRACE_INITIAL_DATA_SUCCESS,
|
||||||
GET_TRACE_LOADING_END,
|
GET_TRACE_LOADING_END,
|
||||||
GET_TRACE_LOADING_START,
|
GET_TRACE_LOADING_START,
|
||||||
|
RESET_TRACE_DATA,
|
||||||
TraceActions,
|
TraceActions,
|
||||||
|
UPDATE_AGGREGATES,
|
||||||
UPDATE_SELECTED_AGG_OPTION,
|
UPDATE_SELECTED_AGG_OPTION,
|
||||||
UPDATE_SELECTED_ENTITY,
|
UPDATE_SELECTED_ENTITY,
|
||||||
UPDATE_SELECTED_TRACE_DATA,
|
UPDATE_SELECTED_TRACE_DATA,
|
||||||
@ -13,8 +15,6 @@ import {
|
|||||||
UPDATE_TRACE_SELECTED_OPERATION,
|
UPDATE_TRACE_SELECTED_OPERATION,
|
||||||
UPDATE_TRACE_SELECTED_SERVICE,
|
UPDATE_TRACE_SELECTED_SERVICE,
|
||||||
UPDATE_TRACE_SELECTED_TAGS,
|
UPDATE_TRACE_SELECTED_TAGS,
|
||||||
RESET_TRACE_DATA,
|
|
||||||
UPDATE_AGGREGATES,
|
|
||||||
} from 'types/actions/trace';
|
} from 'types/actions/trace';
|
||||||
import { TraceReducer } from 'types/reducer/trace';
|
import { TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
|
@ -14,7 +14,10 @@ const initialState: TraceFilters = {
|
|||||||
kind: '',
|
kind: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const TraceFilterReducer = (state = initialState, action: ACTION) => {
|
const TraceFilterReducer = (
|
||||||
|
state = initialState,
|
||||||
|
action: ACTION,
|
||||||
|
): TraceFilters => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.updateTraceFilters:
|
case ActionTypes.updateTraceFilters:
|
||||||
return action.payload;
|
return action.payload;
|
||||||
|
@ -11,7 +11,7 @@ const spanlistinstance: spanList = { events: [], segmentID: '', columns: [] };
|
|||||||
export const tracesReducer = (
|
export const tracesReducer = (
|
||||||
state: traceResponseNew = { '0': spanlistinstance },
|
state: traceResponseNew = { '0': spanlistinstance },
|
||||||
action: Action,
|
action: Action,
|
||||||
) => {
|
): traceResponseNew => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.fetchTraces:
|
case ActionTypes.fetchTraces:
|
||||||
return action.payload;
|
return action.payload;
|
||||||
@ -23,7 +23,7 @@ export const tracesReducer = (
|
|||||||
export const traceItemReducer = (
|
export const traceItemReducer = (
|
||||||
state: spansWSameTraceIDResponse = { '0': spanlistinstance },
|
state: spansWSameTraceIDResponse = { '0': spanlistinstance },
|
||||||
action: Action,
|
action: Action,
|
||||||
) => {
|
): spansWSameTraceIDResponse => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.fetchTraceItem:
|
case ActionTypes.fetchTraceItem:
|
||||||
return action.payload;
|
return action.payload;
|
||||||
|
@ -3,7 +3,7 @@ import { Action, ActionTypes, usageDataItem } from 'store/actions';
|
|||||||
export const usageDataReducer = (
|
export const usageDataReducer = (
|
||||||
state: usageDataItem[] = [{ timestamp: 0, count: 0 }],
|
state: usageDataItem[] = [{ timestamp: 0, count: 0 }],
|
||||||
action: Action,
|
action: Action,
|
||||||
) => {
|
): usageDataItem[] => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.getUsageData:
|
case ActionTypes.getUsageData:
|
||||||
return action.payload;
|
return action.payload;
|
||||||
|
@ -34,6 +34,6 @@ declare module 'react-graph-vis' {
|
|||||||
NetworkGraphProps,
|
NetworkGraphProps,
|
||||||
NetworkGraphState
|
NetworkGraphState
|
||||||
> {
|
> {
|
||||||
render();
|
render(): JSX.Element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2236,9 +2236,9 @@
|
|||||||
integrity sha512-09x2d6kNBwjHgyh3jOUE2GE4DFoxDriDvWdu6mFhMP1ysynGYazt4ecZmJlL6/fe4Zi2vtYvTvtL7epjQQrBhA==
|
integrity sha512-09x2d6kNBwjHgyh3jOUE2GE4DFoxDriDvWdu6mFhMP1ysynGYazt4ecZmJlL6/fe4Zi2vtYvTvtL7epjQQrBhA==
|
||||||
|
|
||||||
"@types/node@^16.10.3":
|
"@types/node@^16.10.3":
|
||||||
version "16.10.3"
|
version "16.11.9"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185"
|
||||||
integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==
|
integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==
|
||||||
|
|
||||||
"@types/normalize-package-data@^2.4.0":
|
"@types/normalize-package-data@^2.4.0":
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user