Feature: Add serviceInstance Search Support (#233)
diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 1de7bd0..e59d3b2 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -33,7 +33,7 @@
"scalar Long",
fs.readFileSync('query-protocol/common.graphqls', 'utf8'),
fs.readFileSync('query-protocol/metadata.graphqls', 'utf8'),
- fs.readFileSync('query-protocol/database.graphqls', 'utf8'),
+ fs.readFileSync('query-protocol/top-n-records.graphqls', 'utf8'),
fs.readFileSync('query-protocol/alarm.graphqls', 'utf8'),
fs.readFileSync('query-protocol/metric.graphqls', 'utf8'),
fs.readFileSync('query-protocol/aggregation.graphqls', 'utf8'),
diff --git a/mock/trace.js b/mock/trace.js
index 93867b0..bdd79e4 100644
--- a/mock/trace.js
+++ b/mock/trace.js
@@ -19,6 +19,13 @@
import mockjs from 'mockjs';
export default {
+
+ getServiceInstances: () => {
+ const data = mockjs.mock({
+ 'instanceId|20-50': [{ 'id|+1': 3, name: function() { return `service-${this.id}`; } }], // eslint-disable-line
+ });
+ return data.instanceId;
+ },
TraceBrief: () => {
let offset = 0;
return mockjs.mock({
diff --git a/src/models/trace.js b/src/models/trace.js
index 9b2f8c4..bb2485d 100644
--- a/src/models/trace.js
+++ b/src/models/trace.js
@@ -29,6 +29,15 @@
}
`;
+const serviceInstanceQuery = `
+ query ServiceInstanceOption($duration: Duration!, $serviceId: ID!) {
+ instanceId: getServiceInstances(duration: $duration, serviceId: $serviceId) {
+ key: id
+ label: name
+ }
+ }
+`;
+
const dataQuery = `
query BasicTraces($condition: TraceQueryCondition) {
queryBasicTraces(condition: $condition) {
@@ -85,6 +94,7 @@
export default base({
namespace: 'trace',
state: {
+ instances: [],
queryBasicTraces: {
traces: [],
total: 0,
@@ -116,6 +126,13 @@
},
dataQuery,
effects: {
+ *fetchInstances({ payload }, { call, put }) {
+ const response = yield call(exec, { query: serviceInstanceQuery, variables: payload.variables });
+ yield put({
+ type: 'saveInstances',
+ payload: response,
+ });
+ },
*fetchSpans({ payload }, { call, put }) {
const response = yield call(exec, { query: spanQuery, variables: payload.variables });
yield put({
@@ -138,6 +155,16 @@
},
};
},
+ saveInstances(state, { payload }) {
+ const { data } = state;
+ return {
+ ...state,
+ data: {
+ ...data,
+ instances: payload.data.instanceId,
+ },
+ };
+ },
hideTimeline(state) {
const { data } = state;
return {
diff --git a/src/routes/Trace/TraceSearch.js b/src/routes/Trace/TraceSearch.js
index 5b40633..4448304 100644
--- a/src/routes/Trace/TraceSearch.js
+++ b/src/routes/Trace/TraceSearch.js
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import React, { PureComponent } from 'react';
+import React, { Component } from 'react';
import { Form, Input, Select, Button, Card, InputNumber, Row, Col, Pagination, DatePicker,notification } from 'antd';
import { Chart, Geom, Axis, Tooltip, Legend } from 'bizcharts';
import { DataSet } from '@antv/data-set';
@@ -51,7 +51,15 @@
return result;
},
})
-export default class Trace extends PureComponent {
+export default class Trace extends Component {
+ constructor(props){
+ super(props);
+ this.state = {
+ serviceId: '',
+ serviceInstanceId: '',
+ }
+ }
+
componentDidMount() {
this.timer = false;
const {...propsData} = this.props;
@@ -118,12 +126,20 @@
fetchData = (queryCondition, paging = initPaging) => {
const {...propsData} = this.props;
+ const { serviceId, serviceInstanceId } = this.state;
+ const newData = {...queryCondition, serviceId, serviceInstanceId}
+ if (!serviceId) {
+ delete newData.serviceId;
+ }
+ if (!serviceInstanceId) {
+ delete newData.serviceInstanceId;
+ }
propsData.dispatch({
type: 'trace/fetchData',
payload: {
variables: {
condition: {
- ...queryCondition,
+ ...newData,
paging,
},
},
@@ -161,6 +177,42 @@
});
}
+ handleSelectInstance = (serviceInstanceId) => {
+ this.setState({ serviceInstanceId });
+ }
+
+ handleRefreshServiceInstances = () => {
+ const { dispatch } = this.props;
+ const { ...propsData } = this.props;
+ const { serviceId } = this.state;
+ propsData.form.validateFields((err, fieldsValue) => {
+ if (err || !serviceId) return;
+ const rangeTime = fieldsValue['range-time-picker'];
+ const duration = generateDuration({ from: () => rangeTime[0], to: () => rangeTime[1] }).input;
+ dispatch({
+ type: 'trace/fetchInstances',
+ payload: { variables: { duration, serviceId } },
+ });
+ });
+ return true;
+ }
+
+ handleShowServiceInstances = (serviceId) => {
+ const { dispatch } = this.props;
+ const { ...propsData } = this.props;
+ this.setState({ serviceId });
+ propsData.form.validateFields((err, fieldsValue) => {
+ if (err || !serviceId) return;
+ const rangeTime = fieldsValue['range-time-picker'];
+ const duration = generateDuration({ from: () => rangeTime[0], to: () => rangeTime[1] }).input;
+ dispatch({
+ type: 'trace/fetchInstances',
+ payload: { variables: { duration, serviceId } },
+ });
+ });
+ return true;
+ }
+
renderPointChart = (traces) => {
if (!traces) {
return null;
@@ -240,6 +292,7 @@
}],
})(
<RangePicker
+ onCalendarChange={this.handleRefreshServiceInstances}
showTime
disabledDate={current => current && current.valueOf() >= Date.now()}
format="YYYY-MM-DD HH:mm"
@@ -248,16 +301,29 @@
)}
</FormItem>
<FormItem label="Service">
- {getFieldDecorator('serviceId')(
- <Select placeholder="All service" style={{ width: '100%' }}>
- {options.serviceId && options.serviceId.map((service) => {
- return (
- <Option key={service.key ? service.key : -1} value={service.key}>
- {service.label}
- </Option>);
- })}
- </Select>
- )}
+ <Select placeholder="All services" onChange={this.handleShowServiceInstances} style={{ width: '100%' }}>
+ {options.serviceId && options.serviceId.map((service) => {
+ if (service.key) {
+ return (
+ <Option key={service.key ? service.key : -1} value={service.key? service.key : ''}>
+ {service.label}
+ </Option>);
+ }
+ return (
+ <Option value="">All Services</Option>
+ )})}
+ </Select>
+ </FormItem>
+ <FormItem label="ServiceInstance">
+ <Select placeholder="All Service Instances" onChange={this.handleSelectInstance} style={{ width: '100%' }}>
+ <Option value="">All Service Instances</Option>
+ {propsData.trace.data.instances && propsData.trace.data.instances.map((instance) => {
+ return (
+ <Option key={instance.key ? instance.key : -1} value={instance.key}>
+ {instance.label}
+ </Option>);
+ })}
+ </Select>
</FormItem>
<FormItem label="Trace State">
{getFieldDecorator('traceState')(