You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by ha...@apache.org on 2018/05/24 03:59:24 UTC

[incubator-skywalking-ui] branch 5.0.0/beta2 updated: Add application selection to service page

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

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


The following commit(s) were added to refs/heads/5.0.0/beta2 by this push:
     new 0e2e237  Add application selection to service page
0e2e237 is described below

commit 0e2e237e25b70cf9c23177bdb3b123ed7111b80a
Author: hanahmily <ha...@gmail.com>
AuthorDate: Thu May 24 11:52:50 2018 +0800

    Add application selection to service page
---
 .roadhogrc.mock.js                  |   1 +
 mock/service.js                     |   2 +-
 src/components/Page/Search/index.js |   9 +-
 src/models/service.js               |  27 ++++-
 src/routes/Service/Service.js       | 231 +++++++++++++++++++++++-------------
 src/utils/models.js                 | 111 ++++++++---------
 6 files changed, 245 insertions(+), 136 deletions(-)

diff --git a/.roadhogrc.mock.js b/.roadhogrc.mock.js
index 36ec6a0..436a0e2 100644
--- a/.roadhogrc.mock.js
+++ b/.roadhogrc.mock.js
@@ -19,6 +19,7 @@ const proxy = {
   'POST /api/server': getServer,
   'POST /api/service/search': searchService,
   'POST /api/service': getService,
+  'POST /api/service/options': getAllApplication,
   'POST /api/alarm': getAlarm,
   'POST /api/notice': getNoticeAlarm,
   'POST /api/trace/options': getAllApplicationForTrace,
diff --git a/mock/service.js b/mock/service.js
index 9c23a21..dcb37f4 100644
--- a/mock/service.js
+++ b/mock/service.js
@@ -44,7 +44,7 @@ export default {
               {
                 'traces|20': [{
                   key: '@id',
-                  operationName: '@url(200)',
+                  operationName: '200://wgmb.ev/jcknolzq',
                   duration: () => {
                     duration -= 100;
                     return duration;
diff --git a/src/components/Page/Search/index.js b/src/components/Page/Search/index.js
index 9f0026a..a7060a8 100644
--- a/src/components/Page/Search/index.js
+++ b/src/components/Page/Search/index.js
@@ -35,7 +35,14 @@ export default class Search extends PureComponent {
     fetching: false,
   }
   componentDidMount() {
-    this.originFetchServer('', !this.props.value.key);
+    if (this.props.variables && Object.keys(this.props.variables).length > 0) {
+      this.originFetchServer('', true);
+    }
+  }
+  componentDidUpdate(prevProps) {
+    if (prevProps.variables !== this.props.variables) {
+      this.originFetchServer('', true);
+    }
   }
   fetchServer = (value, isSelectOne) => {
     if (value === undefined) {
diff --git a/src/models/service.js b/src/models/service.js
index e25065b..0d47fbe 100644
--- a/src/models/service.js
+++ b/src/models/service.js
@@ -16,9 +16,18 @@
  */
 
 
-import { generateModal } from '../utils/models';
+import { generateModal, saveOptionsInState } from '../utils/models';
 import { query } from '../services/graphql';
 
+const optionsQuery = `
+  query ApplicationOption($duration: Duration!) {
+    applicationId: getAllApplication(duration: $duration) {
+      key: id
+      label: name
+    }
+  }
+`;
+
 const dataQuery = `
   query Service($serviceId: ID!, $duration: Duration!, $traceCondition: TraceQueryCondition!) {
     getServiceResponseTimeTrend(serviceId: $serviceId, duration: $duration) {
@@ -124,6 +133,7 @@ export default generateModal({
     },
   },
   dataQuery,
+  optionsQuery,
   effects: {
     *fetchSpans({ payload }, { call, put }) {
       const response = yield call(query, 'spans', { query: spanQuery, variables: payload.variables });
@@ -147,6 +157,21 @@ export default generateModal({
         },
       };
     },
+    saveAppInfo(preState, { payload: allOptions }) {
+      const rawState = saveOptionsInState(null, preState, { payload: allOptions });
+      const { data } = rawState;
+      if (data.appInfo) {
+        return rawState;
+      }
+      const { variables: { values } } = rawState;
+      return {
+        ...rawState,
+        data: {
+          ...data,
+          appInfo: { applicationId: values.applicationId },
+        },
+      };
+    },
     hideTimeline(state) {
       const { data } = state;
       return {
diff --git a/src/routes/Service/Service.js b/src/routes/Service/Service.js
index dff6946..82ac1c5 100644
--- a/src/routes/Service/Service.js
+++ b/src/routes/Service/Service.js
@@ -18,7 +18,7 @@
 
 import React, { PureComponent } from 'react';
 import { connect } from 'dva';
-import { Row, Col, Form, Button, Icon } from 'antd';
+import { Row, Col, Form, Button, Icon, Select } from 'antd';
 import {
   ChartCard, MiniArea, MiniBar, Sankey,
 } from '../../components/Charts';
@@ -29,16 +29,21 @@ import TraceList from '../../components/Trace/TraceList';
 import TraceTimeline from '../Trace/TraceTimeline';
 
 const { Item: FormItem } = Form;
+const { Option } = Select;
 
 @connect(state => ({
   service: state.service,
   duration: state.global.duration,
   globalVariables: state.global.globalVariables,
+  loading: state.loading.models.service,
 }))
 @Form.create({
   mapPropsToFields(props) {
     const { variables: { values, labels } } = props.service;
     return {
+      applicationId: Form.createFormField({
+        value: { key: values.applicationId ? values.applicationId : '', label: labels.applicationId ? labels.applicationId : '' },
+      }),
       serviceId: Form.createFormField({
         value: { key: values.serviceId ? values.serviceId : '', label: labels.serviceId ? labels.serviceId : '' },
       }),
@@ -46,6 +51,35 @@ const { Item: FormItem } = Form;
   },
 })
 export default class Service extends PureComponent {
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'service/initOptions',
+      payload: { variables: this.props.globalVariables, reducer: 'saveAppInfo' },
+    });
+  }
+  componentWillUpdate(nextProps) {
+    if (nextProps.globalVariables.duration === this.props.globalVariables.duration) {
+      return;
+    }
+    this.props.dispatch({
+      type: 'service/initOptions',
+      payload: { variables: nextProps.globalVariables, reducer: 'saveAppInfo' },
+    });
+  }
+  handleAppSelect = (selected) => {
+    this.props.dispatch({
+      type: 'service/save',
+      payload: {
+        variables: {
+          values: { applicationId: selected.key, serviceId: null },
+          labels: { applicationId: selected.label, serviceId: null },
+        },
+        data: {
+          appInfo: { applicationId: selected.key },
+        },
+      },
+    });
+  }
   handleSelect = (selected) => {
     this.props.dispatch({
       type: 'service/save',
@@ -61,13 +95,21 @@ export default class Service extends PureComponent {
     });
   }
   handleChange = (variables) => {
+    const { variables: { values } } = this.props.service;
+    if (!values.applicationId) {
+      return;
+    }
+    const { key: serviceId, label: serviceName } = variables;
+    if (!serviceId) {
+      return;
+    }
     this.props.dispatch({
       type: 'service/fetchData',
       payload: { variables: {
-        ...variables,
+        serviceId,
         traceCondition: {
-          applicationId: 1,
-          operationName: '',
+          applicationId: values.applicationId,
+          operationName: serviceName,
           queryDuration: variables.duration,
           paging: {
             pageNum: 1,
@@ -91,6 +133,75 @@ export default class Service extends PureComponent {
     });
   }
   edgeWith = edge => edge.cpm * edge.avgResponseTime;
+  renderPanel = () => {
+    const { service, duration } = this.props;
+    const { variables: { values }, data } = service;
+    const { getServiceResponseTimeTrend, getServiceThroughputTrend,
+      getServiceSLATrend, getServiceTopology, getTrace } = data;
+    if (!values.serviceId) {
+      return null;
+    }
+    return (
+      <Panel
+        variables={data.serviceInfo}
+        globalVariables={this.props.globalVariables}
+        onChange={this.handleChange}
+      >
+        <Row gutter={8}>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+            <ChartCard
+              title="Avg Throughput"
+              total={`${avgTimeSeries(getServiceThroughputTrend.trendList)} cpm`}
+              contentHeight={46}
+            >
+              <MiniArea
+                color="#975FE4"
+                data={axis(duration, getServiceThroughputTrend.trendList)}
+              />
+            </ChartCard>
+          </Col>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+            <ChartCard
+              title="Avg Response Time"
+              total={`${avgTimeSeries(getServiceResponseTimeTrend.trendList)} ms`}
+              contentHeight={46}
+            >
+              <MiniArea
+                data={axis(duration, getServiceResponseTimeTrend.trendList)}
+              />
+            </ChartCard>
+          </Col>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
+            <ChartCard
+              title="Avg SLA"
+              total={`${(avgTimeSeries(getServiceSLATrend.trendList) / 100).toFixed(2)} %`}
+            >
+              <MiniBar
+                animate={false}
+                height={46}
+                data={axis(duration, getServiceSLATrend.trendList,
+                  ({ x, y }) => ({ x, y: y / 100 }))}
+              />
+            </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
+                data={getTrace.traces}
+                onClickTraceTag={this.handleShowTrace}
+                loading={this.props.loading}
+              />
+            </ChartCard>
+          </Col>
+        </Row>
+        {this.renderSankey(getServiceTopology)}
+      </Panel>
+    );
+  }
   renderSankey = (data) => {
     if (data.nodes.length < 2) {
       return <span style={{ display: 'none' }} />;
@@ -126,12 +237,10 @@ export default class Service extends PureComponent {
       </Row>);
   }
   render() {
-    const { form, service, duration } = this.props;
+    const { form, service } = this.props;
     const { getFieldDecorator } = form;
-    const { variables: { values }, data } = service;
-    const { getServiceResponseTimeTrend, getServiceThroughputTrend,
-      getServiceSLATrend, getServiceTopology, getTrace,
-      showTimeline, queryTrace, currentTraceId } = data;
+    const { variables: { options }, data } = service;
+    const { showTimeline, queryTrace, currentTraceId } = data;
     return (
       <div>
         {showTimeline ? (
@@ -147,80 +256,42 @@ export default class Service extends PureComponent {
           <Col span={showTimeline ? 0 : 24}>
             <Form layout="inline">
               <FormItem>
-                {getFieldDecorator('serviceId')(
-                  <Search
-                    placeholder="Search a service"
-                    onSelect={this.handleSelect.bind(this)}
-                    url="/service/search"
-                    query={`
-                      query SearchService($keyword: String!) {
-                        searchService(keyword: $keyword, topN: 10) {
-                          key: id
-                          label: name
-                        }
-                      }
-                    `}
-                  />
+                {getFieldDecorator('applicationId')(
+                  <Select
+                    showSearch
+                    optionFilterProp="children"
+                    style={{ width: 200 }}
+                    placeholder="Select a application"
+                    labelInValue
+                    onSelect={this.handleAppSelect.bind(this)}
+                  >
+                    {options.applicationId && options.applicationId.map(app =>
+                      <Option key={app.key} value={app.key}>{app.label}</Option>)}
+                  </Select>
                 )}
               </FormItem>
-            </Form>
-            <Panel
-              variables={values}
-              globalVariables={this.props.globalVariables}
-              onChange={this.handleChange}
-            >
-              <Row gutter={8}>
-                <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
-                  <ChartCard
-                    title="Avg Throughput"
-                    total={`${avgTimeSeries(getServiceThroughputTrend.trendList)} cpm`}
-                    contentHeight={46}
-                  >
-                    <MiniArea
-                      color="#975FE4"
-                      data={axis(duration, getServiceThroughputTrend.trendList)}
-                    />
-                  </ChartCard>
-                </Col>
-                <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
-                  <ChartCard
-                    title="Avg Response Time"
-                    total={`${avgTimeSeries(getServiceResponseTimeTrend.trendList)} ms`}
-                    contentHeight={46}
-                  >
-                    <MiniArea
-                      data={axis(duration, getServiceResponseTimeTrend.trendList)}
-                    />
-                  </ChartCard>
-                </Col>
-                <Col xs={24} sm={24} md={24} lg={8} xl={8} style={{ marginTop: 8 }}>
-                  <ChartCard
-                    title="Avg SLA"
-                    total={`${(avgTimeSeries(getServiceSLATrend.trendList) / 100).toFixed(2)} %`}
-                  >
-                    <MiniBar
-                      animate={false}
-                      height={46}
-                      data={axis(duration, getServiceSLATrend.trendList,
-                        ({ x, y }) => ({ x, y: y / 100 }))}
-                    />
-                  </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
-                      data={getTrace.traces}
-                      onClickTraceTag={this.handleShowTrace}
+              {data.appInfo ? (
+                <FormItem>
+                  {getFieldDecorator('serviceId')(
+                    <Search
+                      placeholder="Search a service"
+                      onSelect={this.handleSelect.bind(this)}
+                      url="/service/search"
+                      variables={data.appInfo}
+                      query={`
+                        query SearchService($applicationId: ID!, $keyword: String!) {
+                          searchService(applicationId: $applicationId, keyword: $keyword, topN: 10) {
+                            key: id
+                            label: name
+                          }
+                        }
+                      `}
                     />
-                  </ChartCard>
-                </Col>
-              </Row>
-              {this.renderSankey(getServiceTopology)}
-            </Panel>
+                  )}
+                </FormItem>
+              ) : null}
+            </Form>
+            {this.renderPanel()}
           </Col>
           <Col span={showTimeline ? 24 : 0}>
             {showTimeline ? (
diff --git a/src/utils/models.js b/src/utils/models.js
index 25a064a..3c22d22 100644
--- a/src/utils/models.js
+++ b/src/utils/models.js
@@ -18,6 +18,61 @@
 
 import { query as queryService } from '../services/graphql';
 
+export function saveOptionsInState(defaultOption, preState, { payload: allOptions }) {
+  if (!allOptions) {
+    return preState;
+  }
+  const { variables } = preState;
+  const { values, labels, options } = variables;
+  const amendOptions = {};
+  const defaultValues = {};
+  const defaultLabels = {};
+  Object.keys(allOptions).forEach((_) => {
+    const thisOptions = allOptions[_];
+    let newOptions = [...thisOptions];
+    if (defaultOption && defaultOption[_]) {
+      newOptions = [defaultOption[_], ...newOptions];
+    }
+    if (!values[_]) {
+      if (defaultOption && defaultOption[_]) {
+        defaultValues[_] = defaultOption[_].key;
+        defaultLabels[_] = defaultOption[_].label;
+      } else if (thisOptions.length > 0) {
+        defaultValues[_] = thisOptions[0].key;
+        defaultLabels[_] = thisOptions[0].label;
+      }
+    }
+    const key = values[_];
+    if (!thisOptions.find(o => o.key === key)) {
+      newOptions = [...newOptions, { key, label: labels[_] }];
+    }
+    amendOptions[_] = newOptions;
+  });
+  variables.options = {
+    ...options,
+    ...allOptions,
+    ...amendOptions,
+  };
+  let newVariables = variables;
+  if (Object.keys(defaultValues).length > 0) {
+    newVariables = {
+      ...variables,
+      values: {
+        ...values,
+        ...defaultValues,
+      },
+      labels: {
+        ...labels,
+        ...defaultLabels,
+      },
+    };
+  }
+  return {
+    ...preState,
+    variables: newVariables,
+  };
+}
+
 export function generateModal({ namespace, dataQuery, optionsQuery, defaultOption, state = {},
   varState = {}, effects = {}, reducers = {}, subscriptions = {} }) {
   return {
@@ -68,59 +123,9 @@ export function generateModal({ namespace, dataQuery, optionsQuery, defaultOptio
       ...effects,
     },
     reducers: {
-      saveOptions(preState, { payload: allOptions }) {
-        if (!allOptions) {
-          return preState;
-        }
-        const { variables } = preState;
-        const { values, labels, options } = variables;
-        const amendOptions = {};
-        const defaultValues = {};
-        const defaultLabels = {};
-        Object.keys(allOptions).forEach((_) => {
-          const thisOptions = allOptions[_];
-          let newOptions = [...thisOptions];
-          if (defaultOption && defaultOption[_]) {
-            newOptions = [defaultOption[_], ...newOptions];
-          }
-          if (!values[_]) {
-            if (defaultOption && defaultOption[_]) {
-              defaultValues[_] = defaultOption[_].key;
-              defaultLabels[_] = defaultOption[_].label;
-            } else if (thisOptions.length > 0) {
-              defaultValues[_] = thisOptions[0].key;
-              defaultLabels[_] = thisOptions[0].label;
-            }
-          }
-          const key = values[_];
-          if (!thisOptions.find(o => o.key === key)) {
-            newOptions = [...newOptions, { key, label: labels[_] }];
-          }
-          amendOptions[_] = newOptions;
-        });
-        variables.options = {
-          ...options,
-          ...allOptions,
-          ...amendOptions,
-        };
-        let newVariables = variables;
-        if (Object.keys(defaultValues).length > 0) {
-          newVariables = {
-            ...variables,
-            values: {
-              ...values,
-              ...defaultValues,
-            },
-            labels: {
-              ...labels,
-              ...defaultLabels,
-            },
-          };
-        }
-        return {
-          ...preState,
-          variables: newVariables,
-        };
+      saveOptions(preState, action) {
+        const raw = saveOptionsInState(defaultOption, preState, action);
+        return raw;
       },
       save(preState, { payload: { variables: { values = {}, options = {}, labels = {} },
         data = {} } }) {

-- 
To stop receiving notification emails like this one, please contact
hanahmily@apache.org.