This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch 6.0.0/dev
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking-ui.git

commit 44c7474a01edda4730ef576bf9ba10a89a2f29aa
Author: Gao Hongtao <[email protected]>
AuthorDate: Thu Oct 11 21:37:31 2018 +0800

    Refactor Endpoint dependencies chart with new V6 api
---
 .roadhogrc.mock.js                          |  3 +-
 mock/topology.js                            | 50 +++++++++++++++++++
 src/components/Charts/EndpointDeps/index.js | 74 +++++++++++++++++++++++++++++
 src/components/Charts/index.js              |  3 ++
 src/models/endpoint.js                      | 60 +++++++++++++++++++++++
 src/routes/Endpoint/Endpoint.js             | 69 +++++++++++----------------
 6 files changed, 218 insertions(+), 41 deletions(-)

diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 628b6dd..d255f73 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -1,6 +1,6 @@
 import fs from 'fs';
 import { delay } from 'roadhog-api-doc';
-import { getGlobalTopology, getServiceTopology } from './mock/topology';
+import { getGlobalTopology, getServiceTopology, getEndpointTopology } from 
'./mock/topology';
 import { Alarms, AlarmTrend } from './mock/alarm';
 import { TraceBrief, Trace } from './mock/trace'
 import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
@@ -19,6 +19,7 @@ const resolvers = {
     getAllEndpointTopN,
     getGlobalTopology,
     getServiceTopology,
+    getEndpointTopology,
     searchEndpoint,
     getEndpointTopN,
     getServiceInstanceTopN,
diff --git a/mock/topology.js b/mock/topology.js
index 62c4fbd..5861e93 100644
--- a/mock/topology.js
+++ b/mock/topology.js
@@ -69,6 +69,56 @@ export default {
       calls,
     };
   },
+  getEndpointTopology: () => {
+    const upNodes = mockjs.mock({
+      'nodes|1-5': [
+        {
+          'id|+1': 100,
+          name: '@url',
+          'type|1': ['DUBBO', 'USER', 'SPRINGMVC'],
+          isReal: true,
+        },
+      ],
+    });
+    const centerNodes = mockjs.mock({
+      nodes: [
+        {
+          'id|+1': 10,
+          name: '@url',
+          'type|1': ['DUBBO', 'tomcat', 'SPRINGMVC'],
+          isReal: true,
+        },
+      ],
+    });
+    const downNodes = mockjs.mock({
+      'nodes|2-5': [
+        {
+          'id|+1': 200,
+          name: '@url',
+          'type|1': ['Oracle', 'MYSQL', 'REDIS'],
+          isReal: false,
+        },
+      ],
+    });
+    downNodes.nodes.push({ id: -111 });
+    const nodes = upNodes.nodes.concat(centerNodes.nodes, downNodes.nodes);
+    const calls = upNodes.nodes.map(node => (mockjs.mock({
+      source: node.id,
+      target: 10,
+      'callType|1': ['rpc', 'http', 'dubbo'],
+      'cpm|0-1000': 1,
+    }))).concat(downNodes.nodes.map(node => (mockjs.mock({
+      source: 10,
+      target: node.id,
+      'callType|1': ['rpc', 'http', 'dubbo'],
+      'cpm|0-2000': 1,
+    }))));
+    calls.push({ source: '-175', target: 10, callType: 'GRPC', cpm: 0 });
+    return {
+      nodes,
+      calls,
+    };
+  },
   getGlobalTopology: () => {
     const application = mockjs.mock({
       'nodes|2-3': [
diff --git a/src/components/Charts/EndpointDeps/index.js 
b/src/components/Charts/EndpointDeps/index.js
new file mode 100644
index 0000000..8cc478a
--- /dev/null
+++ b/src/components/Charts/EndpointDeps/index.js
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React, { PureComponent } from 'react';
+import { Sankey } from '..';
+
+class EndpointDeps extends PureComponent {
+
+  componentDidUpdate({ deps: preDeps }) {
+    const { deps } = this.props;
+    if (deps === preDeps) {
+      return;
+    }
+    const { onLoadMetrics } = this.props;
+    onLoadMetrics(deps);
+  }
+
+  edgeWith = (edge) => {
+    const { metrics: { cpm: { values } } } = this.props;
+    if (values.length < 1) {
+      return 1;
+    }
+    const v = values.find(_ => _.id === edge.id);
+    if (!v) {
+      return 1;
+    }
+    return v.value;
+  }
+
+  render() {
+    const { deps: { nodes, calls } } = this.props;
+    if (nodes.length < 2) {
+      return <span style={{ display: 'none' }} />;
+    }
+    const nodesMap = new Map();
+    nodes.forEach((_, i) => {
+      nodesMap.set(`${_.id}`, i);
+    });
+    const nData = {
+      nodes,
+      edges: calls
+        .filter(_ => nodesMap.has(`${_.source}`) && 
nodesMap.has(`${_.target}`))
+        .map(_ =>
+          ({ ..._, value: (this.edgeWith(_) < 1 ? 1000 : this.edgeWith(_)), 
source: nodesMap.get(`${_.source}`), target: nodesMap.get(`${_.target}`) })),
+    };
+    return (
+      <Sankey
+        data={nData}
+        edgeTooltip={['target*source*value', (target, source, value) => {
+          return {
+            name: `${source.name} to ${target.name} </span>`,
+            value: `${value} cpm`,
+          };
+        }]}
+        edgeColor="#bbb"
+      />);
+    }
+}
+
+export default EndpointDeps;
\ No newline at end of file
diff --git a/src/components/Charts/index.js b/src/components/Charts/index.js
index fb5ec1f..959788d 100644
--- a/src/components/Charts/index.js
+++ b/src/components/Charts/index.js
@@ -28,6 +28,7 @@ import Field from './Field';
 import StackBar from './StackBar';
 import Sankey from './Sankey';
 import HeatMap from './HeatMap';
+import EndpointDeps from './EndpointDeps';
 
 const yuan = val => `&yen; ${numeral(val).format('0,0')}`;
 
@@ -44,6 +45,7 @@ const Charts = {
   StackBar,
   Sankey,
   HeatMap,
+  EndpointDeps,
 };
 
 export {
@@ -60,4 +62,5 @@ export {
   StackBar,
   Sankey,
   HeatMap,
+  EndpointDeps,
 };
diff --git a/src/models/endpoint.js b/src/models/endpoint.js
index 27135dd..c4b0dda 100644
--- a/src/models/endpoint.js
+++ b/src/models/endpoint.js
@@ -105,6 +105,21 @@ const dataQuery = `
         value
       }
     }
+    getEndpointTopology(endpointId: $endpointId, duration: $duration) {
+      nodes {
+        id
+        name
+        type
+        isReal
+      }
+      calls {
+        id
+        source
+        target
+        callType
+        detectPoint
+      }
+    }
   }
 `;
 
@@ -146,6 +161,29 @@ const spanQuery = `query Spans($traceId: ID!) {
   }
 }`;
 
+const metricQuery = `
+  query TopologyMetric($duration: Duration!, $idsS: [ID!]!, $idsC: [ID!]!) {
+    cpmS: getValues(metric: {
+      name: "endpoint_relation_server_cpm"
+      ids: $idsS
+    }, duration: $duration) {
+      values {
+        id
+        value
+      }
+    }
+    cpmC: getValues(metric: {
+      name: "endpoint_relation_client_cpm"
+      ids: $idsC
+    }, duration: $duration) {
+      values {
+        id
+        value
+      }
+    }
+  }
+`;
+
 export default base({
   namespace: 'endpoint',
   state: {
@@ -162,6 +200,11 @@ export default base({
       nodes: [],
       calls: [],
     },
+    metrics: {
+      cpm: {
+        values: [],
+      },
+    },
     queryBasicTraces: {
       traces: [],
       total: 0,
@@ -193,6 +236,23 @@ export default base({
         traceId: payload.variables.traceId,
       });
     },
+    *fetchMetrics({ payload }, { call, put }) {
+      const response = yield call(exec, { query: metricQuery, variables: 
payload.variables });
+      if (!response.data) {
+        return;
+      }
+      const { cpmS, cpmC } = response.data;
+      yield put({
+        type: 'saveData',
+        payload: {
+          metrics: {
+            cpm: {
+              values: cpmS.values.concat(cpmC.values),
+            },
+          },
+        },
+      });
+    },
   },
   reducers: {
     saveSpans(state, { payload, traceId }) {
diff --git a/src/routes/Endpoint/Endpoint.js b/src/routes/Endpoint/Endpoint.js
index a16f36f..7de5125 100644
--- a/src/routes/Endpoint/Endpoint.js
+++ b/src/routes/Endpoint/Endpoint.js
@@ -20,7 +20,7 @@ import React, { PureComponent } from 'react';
 import { connect } from 'dva';
 import { Row, Col, Form, Button, Icon, Select } from 'antd';
 import {
-  ChartCard, MiniArea, MiniBar, Sankey, Line,
+  ChartCard, MiniArea, MiniBar, Sankey, Line, EndpointDeps,
 } from 'components/Charts';
 import { axisY, axisMY } from '../../utils/time';
 import { avgTS } from '../../utils/utils';
@@ -137,11 +137,24 @@ export default class Endpoint extends PureComponent {
   }
 
   handleGoBack = () => {
-    this.props.dispatch({
+    const { dispatch } = this.props;
+    dispatch({
       type: 'endpoint/hideTimeline',
     });
   }
 
+  handleLoadMetrics = ({ calls }) => {
+    const { dispatch, globalVariables: { duration } } = this.props;
+    dispatch({
+      type: 'endpoint/fetchMetrics',
+      payload: { variables: {
+        idsS: calls.filter(_ => _.detectPoint === 'SERVER').map(_ => _.id),
+        idsC: calls.filter(_ => _.detectPoint === 'CLIENT').map(_ => _.id),
+        duration,
+      }},
+    });
+  }
+
   edgeWith = edge => edge.cpm;
 
   renderPanel = () => {
@@ -212,6 +225,20 @@ export default class Endpoint extends PureComponent {
         <Row gutter={8}>
           <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 8 
}}>
             <ChartCard
+              title="Dependency Map"
+              contentHeight={200}
+            >
+              <EndpointDeps
+                deps={data.getEndpointTopology}
+                metrics={data.metrics}
+                onLoadMetrics={this.handleLoadMetrics}
+              />
+            </ChartCard>
+          </Col>
+        </Row>
+        <Row gutter={8}>
+          <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 8 
}}>
+            <ChartCard
               title="Top 20 Slow Traces"
             >
               <TraceList
@@ -222,48 +249,10 @@ export default class Endpoint extends PureComponent {
             </ChartCard>
           </Col>
         </Row>
-        {this.renderSankey(getEndpointTopology)}
       </Panel>
     );
   }
 
-  renderSankey = (data) => {
-    if (data.nodes.length < 2) {
-      return <span style={{ display: 'none' }} />;
-    }
-    const nodesMap = new Map();
-    data.nodes.forEach((_, i) => {
-      nodesMap.set(`${_.id}`, i);
-    });
-    const nData = {
-      nodes: data.nodes,
-      edges: data.calls
-        .filter(_ => nodesMap.has(`${_.source}`) && 
nodesMap.has(`${_.target}`))
-        .map(_ =>
-          ({ ..._, value: (this.edgeWith(_) < 1 ? 1000 : this.edgeWith(_)), 
source: nodesMap.get(`${_.source}`), target: nodesMap.get(`${_.target}`) })),
-    };
-    return (
-      <Row gutter={8}>
-        <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginTop: 8 }}>
-          <ChartCard
-            title="Dependency Map"
-            contentHeight={200}
-          >
-            <Sankey
-              data={nData}
-              edgeTooltip={['target*source*cpm', (target, source, cpm) => {
-                return {
-                  name: `${source.name} to ${target.name} </span>`,
-                  value: `${cpm} cpm`,
-                };
-              }]}
-              edgeColor="#bbb"
-            />
-          </ChartCard>
-        </Col>
-      </Row>);
-  }
-
   render() {
     const { form, endpoint } = this.props;
     const { getFieldDecorator } = form;

Reply via email to