You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by GitBox <gi...@apache.org> on 2018/11/08 05:56:23 UTC

[GitHub] peng-yongsheng closed pull request #198: Yonghui/master

peng-yongsheng closed pull request #198: Yonghui/master
URL: https://github.com/apache/incubator-skywalking-ui/pull/198
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/src/assets/common.less b/src/assets/common.less
new file mode 100644
index 0000000..669ced2
--- /dev/null
+++ b/src/assets/common.less
@@ -0,0 +1,122 @@
+:global {
+  //margin-bottom
+  .mb-xxs {
+    margin-bottom: 5px;
+  }
+
+  .mb-xs {
+    margin-bottom: 10px;
+  }
+
+  .mb-sm {
+    margin-bottom: 15px;
+  }
+
+  .mb-md {
+    margin-bottom: 20px;
+  }
+
+  .mb-lg {
+    margin-bottom: 30px;
+  }
+
+  //margin-top
+  .mt-xxs {
+    margin-top: 5px;
+  }
+
+  .mt-xs {
+    margin-top: 10px;
+  }
+
+  .mt-sm {
+    margin-top: 15px;
+  }
+
+  .mt-md {
+    margin-top: 20px;
+  }
+
+  .mt-lg {
+    margin-top: 30px;
+  }
+
+  //margin-right
+  .mr-xxs {
+    margin-right: 5px;
+  }
+
+  .mr-xs {
+    margin-right: 10px;
+  }
+
+  .mr-sm {
+    margin-right: 15px;
+  }
+
+  .mr-md {
+    margin-right: 20px;
+  }
+
+  .mr-lg {
+    margin-right: 30px;
+  }
+
+  .ml-xxs {
+    margin-left: 5px;
+  }
+
+  .ml-xs {
+    margin-left: 10px;
+  }
+
+  .ml-sm {
+    margin-left: 15px;
+  }
+
+  .ml-md {
+    margin-left: 20px;
+  }
+
+  .ml-lg {
+    margin-left: 30px;
+  }
+
+  .pull-left {
+    float: left;
+  }
+
+  .pull-right {
+    float: right;
+  }
+
+  .flex-vertical {
+    display: flex;
+    align-items: center;
+  }
+
+  .din {
+    display: inline-block;
+  }
+  .db {
+    display: block;
+  }
+
+  .pb-md {
+    padding-bottom: 20px;
+  }
+
+  .clearfix::before,
+  .clearfix::after {
+    content: '';
+    display: table;
+  }
+
+  .clearfix::after {
+    clear: both;
+  }
+
+  .pointer {
+    cursor: pointer;
+  }
+}
diff --git a/src/components/Charts/ChartCard/index.js b/src/components/Charts/ChartCard/index.js
index 2801d92..13c3e12 100644
--- a/src/components/Charts/ChartCard/index.js
+++ b/src/components/Charts/ChartCard/index.js
@@ -22,16 +22,16 @@ import classNames from 'classnames';
 import styles from './index.less';
 
 const ChartCard = ({
-  loading = false,
-  contentHeight,
-  title,
-  avatar,
-  action,
-  total,
-  footer,
-  children,
-  ...rest
-}) => {
+                     loading = false,
+                     contentHeight,
+                     title,
+                     avatar,
+                     action,
+                     total,
+                     footer,
+                     children,
+                     ...rest
+                   }) => {
   const content = (
     <div className={styles.chartCard}>
       <div
@@ -44,9 +44,9 @@ const ChartCard = ({
             <span className={styles.action}>{action}</span>
           </div>
           {// eslint-disable-next-line
-          total !== undefined && (
-            <div className={styles.total} dangerouslySetInnerHTML={{ __html: total }} />
-          )}
+            total !== undefined && (
+              <div className={styles.total} dangerouslySetInnerHTML={{ __html: total }} />
+            )}
         </div>
       </div>
       {children && (
diff --git a/src/components/Charts/ChartCard/index.less b/src/components/Charts/ChartCard/index.less
index be9f93a..4712309 100644
--- a/src/components/Charts/ChartCard/index.less
+++ b/src/components/Charts/ChartCard/index.less
@@ -88,6 +88,23 @@
   .footerMargin {
     margin-top: 20px;
   }
+  :global(.leftTextContainer) {
+    float: left;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-end;
+    width: 107px;
+    :global(.data) {
+      color: rgba(0, 0, 0, 0.85);
+      font-size: 30px;
+    }
+    :global(.unit) {
+      color: rgba(0, 0, 0, 0.45);
+      font-size: 18px;
+    }
+  }
 }
 
 .spin :global(.ant-spin-container) {
diff --git a/src/components/Charts/Line/index.js b/src/components/Charts/Line/index.js
index 9ac23da..7080b6b 100644
--- a/src/components/Charts/Line/index.js
+++ b/src/components/Charts/Line/index.js
@@ -93,13 +93,13 @@ class Line extends Component {
     };
 
     const ds = new DataSet();
-      const dv = ds.createView().source(data);
-      dv.transform({
-        type: 'map',
-        callback(row) {
-          return row.d ? row : { ...row, d: 'default'};
-        },
-      });
+    const dv = ds.createView().source(data);
+    dv.transform({
+      type: 'map',
+      callback(row) {
+        return row.d ? row : { ...row, d: 'default'};
+      },
+    });
 
     return (
       <div className={styles.chart} style={{ height }} ref={this.handleRoot}>
diff --git a/src/components/Charts/MiniChartCard/index.js b/src/components/Charts/MiniChartCard/index.js
new file mode 100644
index 0000000..e7cc570
--- /dev/null
+++ b/src/components/Charts/MiniChartCard/index.js
@@ -0,0 +1,87 @@
+/**
+ * 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 from 'react';
+import { Card, Spin } from 'antd';
+import classNames from 'classnames';
+
+import styles from './index.less';
+
+const MiniChartCard = ({
+  loading = false, contentHeight, title, avatar, action, total, footer, children,
+  runningStatus = false, ...rest
+}) => {
+  const content = (
+    <div className={styles.chartCard}>
+      <div
+        className={classNames(styles.chartTop, { [styles.chartTopMargin]: (!children && !footer) })}
+      >
+        {/* <div className={styles.avatar}>
+          {
+            avatar
+          }
+        </div> */}
+        <div className={styles.metaWrap}>
+          <div className={styles.meta}>
+            <span className={styles.title}>{title}</span>
+            <span className={styles.action}>{action}</span>
+          </div>
+          <div className={styles.avatar}>
+            {
+                avatar
+              }
+          </div>
+          {
+            // eslint-disable-next-line
+            (total !== undefined) && (<div className={styles.totalNew} dangerouslySetInnerHTML={{ __html: total }} />)
+          }
+          {
+            runningStatus && (<span className={styles.runningStatus}>进行中 </span>)
+          }
+        </div>
+      </div>
+      {
+        children && (
+          <div className={styles.content} style={{ height: contentHeight || 'auto' }}>
+            <div className={contentHeight && styles.contentFixed}>
+              {children}
+            </div>
+          </div>
+        )
+      }
+      {
+        footer && (
+          <div className={classNames(styles.footer, { [styles.footerMargin]: !children })}>
+            {footer}
+          </div>
+        )
+      }
+    </div>
+  );
+
+  return (
+    <Card
+      bodyStyle={{ padding: '20px 24px 8px 24px' }}
+      {...rest}
+    >
+      {<Spin spinning={loading} wrapperClassName={styles.spin}>{content}</Spin>}
+    </Card>
+  );
+};
+
+export default MiniChartCard;
diff --git a/src/components/Charts/MiniChartCard/index.less b/src/components/Charts/MiniChartCard/index.less
new file mode 100644
index 0000000..0715c4d
--- /dev/null
+++ b/src/components/Charts/MiniChartCard/index.less
@@ -0,0 +1,105 @@
+/*
+ * 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 "~antd/lib/style/themes/default.less";
+
+.chartCard {
+  position: relative;
+  .chartTop {
+    position: relative;
+    overflow: hidden;
+    width: 100%;
+    height: 96px;
+  }
+  .chartTopMargin {
+    margin-bottom: 12px;
+  }
+  .chartTopHasMargin {
+    margin-bottom: 20px;
+  }
+  .metaWrap {
+    float: left;
+  }
+  .avatar {
+    position: relative;
+    top: 4px;
+    float: left;
+    margin-right: 20px;
+    img {
+      border-radius: 100%;
+    }
+  }
+  .meta {
+    color: @text-color-secondary;
+    font-size: @font-size-base;
+    line-height: 22px;
+    height: 22px;
+  }
+  .action {
+    cursor: pointer;
+    position: absolute;
+    top: 0;
+    right: 0;
+  }
+  .totalNew {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    white-space: nowrap;
+    color: @heading-color;
+    margin-top: 4px;
+    margin-bottom: 0;
+    font-size: 30px;
+    line-height: 38px;
+    height: 38px;
+    // add by kevin
+    position: absolute;
+    right: 1px;
+    bottom: 22px;
+  }
+  // add by kevin
+  .runningStatus {
+    position: absolute;
+    right: 0;
+    bottom: -2px;
+  }
+  .content {
+    margin-bottom: 12px;
+    position: relative;
+    width: 100%;
+  }
+  .contentFixed {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+  }
+  .footer {
+    border-top: 1px solid @border-color-split;
+    padding-top: 9px;
+    margin-top: 8px;
+    & > * {
+      position: relative;
+    }
+  }
+  .footerMargin {
+    margin-top: 20px;
+  }
+}
+.spin :global(.ant-spin-container) {
+  overflow: visible;
+}
diff --git a/src/components/Charts/index.js b/src/components/Charts/index.js
index 959788d..5f68c47 100644
--- a/src/components/Charts/index.js
+++ b/src/components/Charts/index.js
@@ -29,6 +29,7 @@ import StackBar from './StackBar';
 import Sankey from './Sankey';
 import HeatMap from './HeatMap';
 import EndpointDeps from './EndpointDeps';
+import MiniChartCard from './MiniChartCard';
 
 const yuan = val => `&yen; ${numeral(val).format('0,0')}`;
 
@@ -46,6 +47,7 @@ const Charts = {
   Sankey,
   HeatMap,
   EndpointDeps,
+  MiniChartCard,
 };
 
 export {
diff --git a/src/components/ControlPanel/Cell.js b/src/components/ControlPanel/Cell.js
new file mode 100644
index 0000000..91cc739
--- /dev/null
+++ b/src/components/ControlPanel/Cell.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Cell = ({ timeZone }) => {
+  return (
+    <span>
+      {timeZone}
+    </span>
+  );
+};
+
+Cell.defaultProps = {
+  timeZone: '',
+};
+
+export default Cell;
diff --git a/src/components/ControlPanel/index.js b/src/components/ControlPanel/index.js
new file mode 100644
index 0000000..ed1d5a9
--- /dev/null
+++ b/src/components/ControlPanel/index.js
@@ -0,0 +1,73 @@
+import React, { Component } from 'react';
+import { DatePicker, Select } from 'antd';
+import moment from 'moment';
+import classNames from 'classnames';
+import Cell from './Cell';
+import styles from './index.less';
+
+const { Option } = Select;
+const { RangePicker } = DatePicker;
+function onChange() {
+  // console.warn('From: ', dates[0], ', to: ', dates[1]);
+  // console.warn('From: ', dateStrings[0], ', to: ', dateStrings[1]);
+}
+
+function handleChange() {
+  // console.log('下拉框的change事件');
+}
+
+export default class ControlPanel extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { activeIndex: 0 };
+  }
+  changeIndex(index) {
+    this.setState({ activeIndex: index }, () => {
+    });
+  }
+  render() {
+    const { className } = this.props;
+    const firstLineTimeZones = [];
+    const secondLineTimeZones = [];
+    const temp = ['15分钟内', '30分钟内', '1小时内', '6小时内', '12小时内', '1天内',
+      '2天内', '1周内', '2周内', '1月内', '半年内', '1年内'];
+
+    for (let i = 0; i < temp.length; i += 1) {
+      if (i <= 5) {
+        firstLineTimeZones.push((<td onClick={this.changeIndex.bind(this, i)} className={this.state.activeIndex === i ? styles.active : ''} key={`${i}first_line`}><Cell key={`${i}first_line`} timeZone={temp[i]} /></td>));
+      } else {
+        secondLineTimeZones.push((<td onClick={this.changeIndex.bind(this, i)} className={this.state.activeIndex === i ? styles.active : ''} key={`${i}first_line`}><Cell key={`${i}second_line`} timeZone={temp[i]} /></td>));
+      }
+    }
+
+    return (
+      <div className={classNames('clearfix', styles.controlPanel, className)}>
+        <div className={styles.timeZoneContainer}>
+          <table className={styles.timeTable}>
+            <tbody>
+              <tr key="a">{firstLineTimeZones}</tr>
+              <tr key="b">{secondLineTimeZones}</tr>
+            </tbody>
+          </table>
+        </div>
+        <div className={styles.datePickContaier}>
+          <RangePicker
+            style={{ width: '100%' }}
+            ranges={{ Today: [moment(), moment()], 'This Month': [moment(), moment().endOf('month')] }}
+            onChange={onChange}
+          />
+        </div>
+        <div className={styles.refreshControlContainer}>
+          <span className="mr-md kk">定时刷新</span>
+          <Select defaultValue="5s" onChange={handleChange} style={{ width: '70%' }}>
+            <Option value="5s">5s</Option>
+            <Option value="30s">30s</Option>
+            <Option value="60s">60s</Option>
+            <Option value="120s">120s</Option>
+          </Select>
+        </div>
+      </div>
+
+    );
+  }
+}
diff --git a/src/components/ControlPanel/index.less b/src/components/ControlPanel/index.less
new file mode 100644
index 0000000..e45d068
--- /dev/null
+++ b/src/components/ControlPanel/index.less
@@ -0,0 +1,64 @@
+.controlPanel {
+  border: 1px solid #ddd;
+  padding: 8px 14px;
+  display: flex;
+  align-items: center;
+  margin-left: 0;
+  margin-right: 0;
+  & > div:not(:first-of-type) {
+    height: 50px;
+    text-align: center;
+    padding-top: 10px;
+    padding-bottom: 10px;
+  }
+  .timeZoneContainer {
+    border: 1px solid #ddd;
+    border-right: none;
+    margin-right: 40px;
+    width: 40%;
+    .timeTable {
+      background-color: white;
+      width: 100%;
+      tbody > tr:nth-child(1) td {
+        border-bottom: 1px solid #ddd;
+      }
+      // tbody > tr td:not(:last-child) {
+      //   border-right: 1px solid #ddd;
+      // }
+      tbody > tr td {
+        border-right: 1px solid #ddd;
+      }
+      tbody tr td {
+        text-align: center;
+        padding: 6px 7px;
+        width: 16.66%;
+        cursor: pointer;
+
+        &:hover {
+          background-color: rgb(34, 122, 203);
+          color: white;
+        }
+        &.active {
+          background-color: rgb(34, 122, 203);
+          color: white;
+        }
+      }
+    }
+  }
+  .datePickContaier {
+    padding-left: 40px;
+    padding-right: 40px;
+    border-left: 1px solid #ddd;
+    width: 30%;
+    span.ant-calendar-picker {
+      width: 100%;
+    }
+  }
+  .refreshControlContainer {
+    width: 30%;
+    padding-left: 40px;
+    border-left: 1px solid #ddd;
+    display: flex;
+    align-items: center;
+  }
+}
diff --git a/src/components/RankList/index.js b/src/components/RankList/index.js
index e6bed3a..686927d 100644
--- a/src/components/RankList/index.js
+++ b/src/components/RankList/index.js
@@ -15,12 +15,11 @@
  * limitations under the License.
  */
 
-
+import classNames from 'classnames';
 import React, { PureComponent } from 'react';
 import { List, Row, Col, Tag } from 'antd';
 import styles from './index.less';
 
-
 class RankList extends PureComponent {
   renderLabel = (item) => {
     const { renderLabel } = this.props;
@@ -41,26 +40,34 @@ class RankList extends PureComponent {
   renderTitle = (item, maxValue) => {
     const { onClick, color = '#87CEFA' } = this.props;
     return (
-      <div className={styles.progressWrap}>
-        {maxValue > 0 ? (
-          <div
-            className={styles.progress}
-            style={{
+      <div>
+        <span>{onClick ?
+          <a onClick={() => onClick(item.key, item)}>{this.renderLabel(item)}</a>
+            : this.renderLabel(item)}
+        </span>
+        <span className={styles.value}>{this.renderValue(item)}
+        </span>
+        <div className={styles.progressWrap}>
+          {maxValue > 0 ? (
+            <div
+              className={styles.progress}
+              style={{
               backgroundColor: color,
               width: `${(item.value * 100) / maxValue}%`,
-              height: 25,
             }}
-          />
+            />
         ) : null}
-        <div className={styles.mainInfo}>
-          <span>{onClick ?
+          <div className={styles.mainInfo}>
+            {/* <span>{onClick ?
             <a onClick={() => onClick(item.key, item)}>{this.renderLabel(item)}</a>
               : this.renderLabel(item)}
-          </span>
-          <span className={styles.value}>{this.renderValue(item)}
-          </span>
+          </span> */}
+            {/* <span className={styles.value}>{this.renderValue(item)}
+            </span> */}
+          </div>
         </div>
-      </div>);
+      </div>
+    );
   }
 
   renderBadges = (item) => {
@@ -85,7 +92,7 @@ class RankList extends PureComponent {
   }
 
   render() {
-    const { data, loading, renderBadge } = this.props;
+    const { data, loading, renderBadge, listTitles } = this.props;
     let maxValue = 0;
     const sortData = [...data];
     sortData.sort((a, b) => {
@@ -97,21 +104,28 @@ class RankList extends PureComponent {
       return b.value - a.value;
     });
     return (
-      <List
-        className={styles.rankList}
-        itemLayout="horizontal"
-        size="small"
-        dataSource={sortData}
-        loading={loading}
-        renderItem={item => (
-          <List.Item>
-            <List.Item.Meta
-              title={this.renderTitle(item, maxValue)}
-              description={renderBadge ? this.renderBadges(item) : null}
-            />
-          </List.Item>
-        )}
-      />
+      <div>
+        {
+          listTitles && (
+          <div className={classNames('clearfix', styles.rankList, 'mt-md')} > <span className="pull-left"> {listTitles[0]} </span> <span className="pull-right">{listTitles[1]}</span> </div>
+          )
+        }
+        <List
+          className={styles.rankList}
+          itemLayout="horizontal"
+          size="small"
+          dataSource={sortData}
+          loading={loading}
+          renderItem={item => (
+            <List.Item>
+              <List.Item.Meta
+                title={this.renderTitle(item, maxValue)}
+                description={renderBadge ? this.renderBadges(item) : null}
+              />
+            </List.Item>
+          )}
+        />
+      </div>
     );
   }
 }
diff --git a/src/components/RankList/index.less b/src/components/RankList/index.less
index 2a151a0..62f822f 100644
--- a/src/components/RankList/index.less
+++ b/src/components/RankList/index.less
@@ -18,14 +18,18 @@
 @import '~antd/lib/style/themes/default.less';
 
 .rankList {
-  padding: 5px 0;
+  padding: 5px 34px;
   position: relative;
   width: 100%;
   .progressWrap {
     background-color: @background-color-base;
     position: relative;
-    height: 25px;
+    height: 12px;
+    // add by kevin
+    width: 50%;
+    float: right;
   }
+
   .progress {
     position: absolute;
     z-index: 10;
@@ -39,9 +43,9 @@
     position: absolute;
     z-index: 20;
     width: 100%;
-    .value {
-      float: right;
-    }
+    // .value {
+    //   float: right;
+    // }
     a {
       color: #001529;
     }
@@ -49,4 +53,8 @@
       color: #1890ff;
     }
   }
+  .value {
+    float: right;
+    margin-left: 20px;
+  }
 }
diff --git a/src/components/Topology/AppTopology.js b/src/components/Topology/AppTopology.js
index e3f944e..3715c78 100644
--- a/src/components/Topology/AppTopology.js
+++ b/src/components/Topology/AppTopology.js
@@ -77,7 +77,7 @@ export default class AppTopology extends Base {
         onSelectedApplication();
       });
     }
-    
+
   }
 
   updateMetrics = (cy, data) => {
@@ -89,7 +89,7 @@ export default class AppTopology extends Base {
     const { sla: { values: slaValues } } = data;
     const layer = cy.cyCanvas();
     const canvas = layer.getCanvas();
-    
+
     cy.on('render cyCanvas.resize', (evt) => {
       const ctx = canvas.getContext('2d');
       layer.resetTransform(ctx);
@@ -110,12 +110,12 @@ export default class AppTopology extends Base {
         }
 
         const arc = d3.arc()
-            .outerRadius(33)
-            .innerRadius(27)
-            .context(ctx);
+          .outerRadius(33)
+          .innerRadius(27)
+          .context(ctx);
 
         const pie = d3.pie()
-            .sort(null);
+          .sort(null);
 
         ctx.translate(pos.x, pos.y);
 
@@ -151,26 +151,26 @@ export default class AppTopology extends Base {
     })
     const cpmFunc = this.mapFunc(cpm.values);
     cy.style().selector('edge')
-    .css({
-      width: ele => cpmFunc(ele.data('dataId'), 3, 12),
-      'line-color': ele => this.lineColor(latency.values, ele.data('dataId'), colorRange),
-      'target-arrow-color': ele => this.lineColor(latency.values, ele.data('dataId'), colorRange),
-      'curve-style': 'bezier',
-      'control-point-step-size': 100,
-      'target-arrow-shape': 'triangle',
-      'arrow-scale': 1.2,
-      'opacity': 0.666,
-      'text-wrap': 'wrap',
-      'text-rotation': 'autorotate',
-    })
-    .update();
+      .css({
+        width: ele => cpmFunc(ele.data('dataId'), 3, 12),
+        'line-color': ele => this.lineColor(latency.values, ele.data('dataId'), colorRange),
+        'target-arrow-color': ele => this.lineColor(latency.values, ele.data('dataId'), colorRange),
+        'curve-style': 'bezier',
+        'control-point-step-size': 100,
+        'target-arrow-shape': 'triangle',
+        'arrow-scale': 1.2,
+        'opacity': 0.666,
+        'text-wrap': 'wrap',
+        'text-rotation': 'autorotate',
+      })
+      .update();
   }
 
   mapFunc = (values) => {
     if (values.length < 1) {
       return (id, rLimit) => {
         return rLimit;
-      }; 
+      };
     }
     const valueData = values.map(_ => _.value);
     const max = Math.max(...valueData);
diff --git a/src/components/Trace/TraceList/index.less b/src/components/Trace/TraceList/index.less
index 2413b19..bad77a5 100644
--- a/src/components/Trace/TraceList/index.less
+++ b/src/components/Trace/TraceList/index.less
@@ -49,4 +49,36 @@
   .content {
     width: 30%;
   }
+  .traceListItem {
+    display: flex;
+    margin-bottom: 15px;
+    padding-top: 5px;
+    align-items: center;
+    justify-content: space-between;
+    .name {
+      width: 30%;
+    }
+    .status {
+      width: 5%;
+    }
+    .progressBar {
+      width: 40%;
+      height: 15;
+    }
+    .averageTime {
+      min-width: 70px;
+    }
+    .timeStamp {
+      width: 163px;
+    }
+  }
+}
+
+.traceListHead {
+  p {
+    font-size: 16px;
+  }
+  div {
+    color: rgba(0, 0, 0, .4);
+  }
 }
diff --git a/src/components/TraceStack/index.js b/src/components/TraceStack/index.js
index c751188..e9cb645 100644
--- a/src/components/TraceStack/index.js
+++ b/src/components/TraceStack/index.js
@@ -327,7 +327,13 @@ class TraceStack extends PureComponent {
   render() {
     const { colorMap, span = {}, position = { width: 100, top: 0 } } = this.state;
     const legendButtons = Object.keys(colorMap).map(key =>
-      (<Tag color={colorMap[key]} key={key}>{key}</Tag>));
+      (
+        <div className={styles.tag}>
+          <Tag className={styles.colorBlock} color={colorMap[key]} key={key} />
+          <span className={styles.value}>{key}</span>
+        </div>
+      )
+    );
     const tabList = [];
     const contentList = {};
     if (span.content) {
diff --git a/src/components/TraceStack/index.less b/src/components/TraceStack/index.less
index 62e59ba..6a3f6e4 100644
--- a/src/components/TraceStack/index.less
+++ b/src/components/TraceStack/index.less
@@ -89,3 +89,16 @@
   white-space: -moz-pre-wrap; /* Firefox 1.0-2.0 */
   white-space: pre-wrap;      /* Modern browsers */
 }
+
+.tag {
+  display: inline-block;
+  margin-right: 9px;
+  .value {
+    position: relative;
+    top: -2px;
+  }
+  .colorBlock {
+    height: 13px;
+    border-radius: 0;
+  }
+}
diff --git a/src/index.js b/src/index.js
index 2763260..7fe97a6 100644
--- a/src/index.js
+++ b/src/index.js
@@ -25,6 +25,8 @@ import createLoading from 'dva-loading';
 import 'moment/locale/zh-cn';
 
 import './index.less';
+import './assets/common.less';
+
 // 1. Initialize
 const app = dva({
   history: createHistory(),
diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js
index ead1f91..0efec3f 100644
--- a/src/layouts/BasicLayout.js
+++ b/src/layouts/BasicLayout.js
@@ -203,32 +203,7 @@ class BasicLayout extends React.PureComponent {
     const bashRedirect = this.getBashRedirect();
     const layout = (
       <Layout>
-        <SiderMenu
-          logo={logo}
-          // If you do not have the Authorized parameter
-          // you will be forced to jump to the 403 interface without permission
-          Authorized={Authorized}
-          menuData={getMenuData()}
-          collapsed={collapsed}
-          location={location}
-          onCollapse={this.handleMenuCollapse}
-        />
         <Layout>
-          <GlobalHeader
-            logo={logo}
-            fetching={fetching}
-            notices={notices}
-            collapsed={collapsed}
-            selectedDuration={dSelected}
-            isMonitor={isMonitor}
-            onNoticeClear={this.handleNoticeClear}
-            onCollapse={this.handleMenuCollapse}
-            onMenuClick={this.handleMenuClick}
-            onNoticeVisibleChange={this.handleNoticeVisibleChange}
-            onDurationToggle={this.handleDurationToggle}
-            onDurationReload={this.handleDurationReload}
-            onRedirect={this.handleRedirect}
-          />
           {isMonitor ? (
             <DurationPanel
               selected={dSelected}
diff --git a/src/routes/Application/Application.js b/src/routes/Application/Application.js
new file mode 100644
index 0000000..5b3cde0
--- /dev/null
+++ b/src/routes/Application/Application.js
@@ -0,0 +1,303 @@
+/**
+ * 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 { connect } from 'dva';
+import { Row, Col, Select, Card, Form, Breadcrumb, Table } from 'antd';
+import Server from './Server';
+import { AppTopology } from '../../components/Topology';
+import { Panel } from '../../components/Page';
+import RankList from '../../components/RankList';
+import ControlPanel from '../../components/ControlPanel';
+// import ServerLitePanel from '../../components/ServerLitePanel';
+import { getServerId, redirect } from '../../utils/utils';
+
+const { Option } = Select;
+const { Item: FormItem } = Form;
+
+const middleColResponsiveProps = {
+  xs: 24,
+  sm: 24,
+  md: 12,
+  lg: 12,
+  xl: 12,
+  style: { marginTop: 8 },
+};
+
+@connect(state => ({
+  application: state.application,
+  duration: state.global.duration,
+  globalVariables: state.global.globalVariables,
+}))
+@Form.create({
+  mapPropsToFields(props) {
+    const { variables: { values, labels } } = props.application;
+    return {
+      applicationId: Form.createFormField({
+        value: { key: values.applicationId ? values.applicationId : '', label: labels.applicationId ? labels.applicationId : '' },
+      }),
+    };
+  },
+})
+export default class Application extends PureComponent {
+  componentDidMount() {
+    this.props.dispatch({
+      type: 'application/initOptions',
+      payload: { variables: this.props.globalVariables },
+    });
+  }
+  componentWillUpdate(nextProps) {
+    if (nextProps.globalVariables.duration === this.props.globalVariables.duration) {
+      return;
+    }
+    this.props.dispatch({
+      type: 'application/initOptions',
+      payload: { variables: nextProps.globalVariables },
+    });
+  }
+  handleSelect = (selected) => {
+    this.props.dispatch({
+      type: 'application/saveVariables',
+      payload: {
+        values: { applicationId: selected.key },
+        labels: { applicationId: selected.label },
+      },
+    });
+  }
+  handleChange = (variables) => {
+    const { data: { serverInfo, showServer } } = this.props.application;
+    if (showServer) {
+      this.handleSelectServer(serverInfo.key, serverInfo);
+    } else {
+      this.props.dispatch({
+        type: 'application/fetchData',
+        payload: { variables, reducer: 'saveApplication' },
+      });
+    }
+  }
+  handleGoApplication = () => {
+    this.props.dispatch({
+      type: 'application/hideServer',
+    });
+  }
+  handleGoServer = () => {
+    this.props.dispatch({
+      type: 'application/showServer',
+    });
+  }
+  // get select Server Data
+  handleSelectServer = (serverId, serverInfo) => {
+    const { globalVariables: { duration } } = this.props;
+    this.props.dispatch({
+      type: 'application/fetchServer',
+      payload: { variables: { duration, serverId }, serverInfo },
+    });
+  }
+  renderApp = () => {
+    const columns = [{
+      title: '类型',
+      dataIndex: 'ipv4',
+      render: (text, record) => <a href="#">{`${record.pid}@${text[0]}`}</a>,
+    }, {
+      title: 'host',
+      dataIndex: 'host',
+    },
+    {
+      title: 'Pid',
+      dataIndex: 'pid',
+    },
+    {
+      title: 'OS',
+      dataIndex: 'osName',
+    }, {
+      title: '流量',
+      dataIndex: 'value',
+      render: value => `${value}cpm`,
+    },
+    ];
+    const { getFieldDecorator } = this.props.form;
+    const { variables: { values, options }, data } = this.props.application;
+
+    const { serverInfo } = data;
+    const serverList = data.getServerThroughput;
+    if (!serverInfo.key && serverList.length >= 1) {
+      this.handleSelectServer(serverList[0].key, serverList[0]);
+    }
+
+    const getGoToServerListNode = () => {
+      if (serverList.length < 1 || !serverInfo.key) {
+        return null;
+      }
+      return (
+        <div className="pull-right flex-vertical">
+          <Select
+            value={serverInfo.key}
+            onChange={value =>
+              this.handleSelectServer(value, data.getServerThroughput.find(_ => _.key === value))}
+            style={{ width: 400 }}
+          >
+            {data.getServerThroughput.map(_ =>
+              <Option key={_.key} value={_.key}>{getServerId(_)}</Option>)}
+          </Select>
+          {serverInfo.key ? <a className="pull-right ml-md" onClick={this.handleGoServer}>  Server Detail </a> : null}
+        </div>
+      );
+    };
+
+
+    return (
+      <div>
+        <Form layout="inline">
+          <FormItem>
+            {getFieldDecorator('applicationId')(
+              <Select
+                showSearch
+                optionFilterProp="children"
+                style={{ width: 200 }}
+                placeholder="Select a application"
+                labelInValue
+                onSelect={this.handleSelect.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}
+        >
+          <ControlPanel style={{ marginTop: 15 }} />
+          <Row gutter={0}>
+            <Col {...{ ...middleColResponsiveProps, xl: 24, lg: 24, md: 24 }}>
+              <Card
+                title={<div> Application Map {getGoToServerListNode()} </div>}
+                bordered={false}
+                bodyStyle={{ padding: 0 }}
+              >
+                <AppTopology
+                  elements={data.getApplicationTopology}
+                  height={335}
+                  layout={{
+                    name: 'dagre',
+                    rankDir: 'LR',
+                    minLen: 4,
+                  }}
+                />
+              </Card>
+            </Col>
+            {/* <Col {...{ ...middleColResponsiveProps, xl: 8, lg: 12, md: 24 }}>
+              <Card
+                bordered={false}
+                bodyStyle={{ padding: '10px 10px', height: 391 }}
+              >
+                <ServerLitePanel
+                  data={data}
+                  serverList={data.getServerThroughput}
+                  duration={this.props.duration}
+                  onSelectServer={this.handleSelectServer}
+                  onMoreServer={this.handleGoServer}
+                />
+              </Card>
+            </Col> */}
+          </Row>
+          <Row gutter={8}>
+            <Col {...{ ...middleColResponsiveProps, xl: 24, lg: 24, md: 24 }}>
+              <Card
+                title="Slow Service"
+                bordered={false}
+                bodyStyle={{ padding: '0px 10px' }}
+              >
+                <RankList
+                  listTitles={['类型', '耗时']}
+                  data={data.getSlowService.map(_ => ({ ..._.service, value: _.value }))}
+                  renderValue={_ => `${_.value} ms`}
+                  onClick={(key, item) => redirect(this.props.history, '/monitor/service', { key,
+                    label: item.label,
+                    applicationId: item.applicationId,
+                    applicationName: item.applicationName })}
+                />
+              </Card>
+            </Col>
+            <Col {...{ ...middleColResponsiveProps, xl: 24, lg: 24, md: 24 }}>
+              <Card
+                title="Running Server"
+                bordered={false}
+                bodyStyle={{ padding: 5 }}
+              >
+                <Table className="mt-md" style={{ paddingLeft: 24, paddingRight: 24 }} columns={columns} dataSource={data.getServerThroughput} />
+                {/* <RankList
+                  data={data.getServerThroughput}
+                  renderLabel={getServerId}
+                  renderValue={_ => `${_.value} cpm`}
+                  renderBadge={_ => ([
+                    {
+                      key: 'host',
+                      label: 'Host',
+                      value: _.host,
+                    },
+                    {
+                      key: 'os',
+                      label: 'OS',
+                      value: _.osName,
+                    },
+                  ])}
+                  color="#965fe466"
+                /> */}
+              </Card>
+            </Col>
+          </Row>
+        </Panel>
+      </div>
+    );
+  }
+  render() {
+    const { application, duration } = this.props;
+    const { variables, data } = application;
+    const { showServer, serverInfo } = data;
+    return (
+      <Row type="flex" justify="start">
+        {showServer ? (
+          <Col span={showServer ? 24 : 0}>
+            <Breadcrumb>
+              <Breadcrumb.Item>
+                Application
+              </Breadcrumb.Item>
+              <Breadcrumb.Item>
+                <a onClick={this.handleGoApplication}>{variables.labels.applicationId}</a>
+              </Breadcrumb.Item>
+              <Breadcrumb.Item>{getServerId(serverInfo)}</Breadcrumb.Item>
+            </Breadcrumb>
+            <Panel
+              variables={variables.values}
+              globalVariables={this.props.globalVariables}
+              onChange={this.handleChange}
+            >
+              <Server data={data} duration={duration} />
+            </Panel>
+          </Col>
+         ) : null}
+        <Col span={showServer ? 0 : 24}>
+          {this.renderApp()}
+        </Col>
+      </Row>
+    );
+  }
+}
diff --git a/src/routes/Application/Server.less b/src/routes/Application/Server.less
new file mode 100644
index 0000000..1d3f29a
--- /dev/null
+++ b/src/routes/Application/Server.less
@@ -0,0 +1,18 @@
+.leftTextContainer {
+  float: left;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: flex-end;
+  width: 107px;
+  .data {
+    color: rgba(0, 0, 0, 0.85);
+    font-size: 30px;
+  }
+  .unit {
+    color: rgba(0, 0, 0, 0.45);
+    font-size: 18px;
+  }
+}
+
diff --git a/src/routes/Dashboard/Dashboard.js b/src/routes/Dashboard/Dashboard.js
index 860f09e..781eb63 100644
--- a/src/routes/Dashboard/Dashboard.js
+++ b/src/routes/Dashboard/Dashboard.js
@@ -26,6 +26,7 @@ import { generateDuration, axisMY } from '../../utils/time';
 import { redirect } from '../../utils/utils';
 import { Panel } from '../../components/Page';
 import RankList from '../../components/RankList';
+import ControlPanel from '../../components/ControlPanel';
 
 @connect(state => ({
   dashboard: state.dashboard,
@@ -39,27 +40,32 @@ export default class Dashboard extends PureComponent {
       type: 'dashboard/fetchData',
       payload: { variables },
     });
-  }
+  };
 
   renderAction = (prompt, path) => {
     const { history } = this.props;
     return (
       <Tooltip title={prompt}>
-        <Icon type="info-circle-o" onClick={() => redirect(history, path)} />
+        <Icon type="info-circle-o" onClick={() => redirect(history, path)}/>
       </Tooltip>
     );
-  }
+  };
 
   render() {
     const { dashboard: { data }, globalVariables, duration, history } = this.props;
     return (
       <Panel globalVariables={globalVariables} onChange={this.handleDurationChange}>
+        <Row gutter={8}>
+          <Col xs={24} sm={24} md={24} lg={24} xl={24} style={{ marginBottom: 8 }} >
+            <ControlPanel />
+          </Col>
+        </Row>
         <Row gutter={8}>
           <Col xs={24} sm={24} md={12} lg={6} xl={6}>
             <ChartCard
               title="Service"
               action={this.renderAction('Show service details', '/monitor/service')}
-              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/app.png" alt="service" />}
+              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/app.png" alt="service"/>}
               total={data.getGlobalBrief.numOfService}
             />
           </Col>
@@ -67,22 +73,24 @@ export default class Dashboard extends PureComponent {
             <ChartCard
               title="Endpoint"
               action={this.renderAction('Show endpoint details', '/monitor/endpoint')}
-              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/service.png" alt="endpoint" />}
+              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/service.png"
+                           alt="endpoint"/>}
               total={data.getGlobalBrief.numOfEndpoint}
             />
           </Col>
           <Col xs={24} sm={24} md={12} lg={6} xl={6}>
             <ChartCard
               title="DB & Cache"
-              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/database.png" alt="database" />}
+              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/database.png"
+                           alt="database"/>}
               total={data.getGlobalBrief.numOfDatabase
-                + data.getGlobalBrief.numOfCache}
+              + data.getGlobalBrief.numOfCache}
             />
           </Col>
           <Col xs={24} sm={24} md={12} lg={6} xl={6}>
             <ChartCard
               title="MQ"
-              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/mq.png" alt="mq" />}
+              avatar={<img style={{ width: 56, height: 56 }} src="img/icon/mq.png" alt="mq"/>}
               total={data.getGlobalBrief.numOfMQ}
             />
           </Col>
@@ -97,17 +105,20 @@ export default class Dashboard extends PureComponent {
                 data={data.getThermodynamic}
                 duration={duration}
                 height={200}
-                onClick={(d, responseTimeRange) => redirect(history, '/trace', { values: { duration: generateDuration({
-                  from() {
-                    return d.start;
-                  },
-                  to() {
-                    return d.end;
-                  },
-                }),
-                minTraceDuration: responseTimeRange.min,
-                maxTraceDuration: responseTimeRange.max,
-              } })}
+                onClick={(d, responseTimeRange) => redirect(history, '/trace', {
+                  values: {
+                    duration: generateDuration({
+                      from() {
+                        return d.start;
+                      },
+                      to() {
+                        return d.end;
+                      },
+                    }),
+                    minTraceDuration: responseTimeRange.min,
+                    maxTraceDuration: responseTimeRange.max,
+                  }
+                })}
               />
             </ChartCard>
           </Col>
@@ -117,11 +128,17 @@ export default class Dashboard extends PureComponent {
             <Card
               title="Response Time"
               bordered={false}
-              bodyStyle={{ padding: 5, height: 150}}
+              bodyStyle={{ padding: 5, height: 150 }}
             >
               <Line
-                data={axisMY(duration, [{ title: 'p99', value: data.getP99}, { title: 'p95', value: data.getP95}
-                , { title: 'p90', value: data.getP90}, { title: 'p75', value: data.getP75}, { title: 'p50', value: data.getP50}])}
+                data={axisMY(duration, [{ title: 'p99', value: data.getP99 }, {
+                  title: 'p95',
+                  value: data.getP95
+                }
+                  , { title: 'p90', value: data.getP90 }, {
+                    title: 'p75',
+                    value: data.getP75
+                  }, { title: 'p50', value: data.getP50 }])}
               />
             </Card>
           </Col>
diff --git a/src/routes/Service/Service.js b/src/routes/Service/Service.js
index ce4c149..1326696 100644
--- a/src/routes/Service/Service.js
+++ b/src/routes/Service/Service.js
@@ -184,7 +184,7 @@ export default class Service extends PureComponent {
               >
                 <Line
                   data={axisMY(this.props.duration, [{ title: 'p99', value: data.getP99}, { title: 'p95', value: data.getP95}
-                  , { title: 'p90', value: data.getP90}, { title: 'p75', value: data.getP75}, { title: 'p50', value: data.getP50}])}
+                    , { title: 'p90', value: data.getP90}, { title: 'p75', value: data.getP75}, { title: 'p50', value: data.getP50}])}
                 />
               </Card>
             </Col>
@@ -250,7 +250,7 @@ export default class Service extends PureComponent {
               <ServiceInstance data={data} duration={duration} />
             </Panel>
           </Col>
-         ) : null}
+        ) : null}
         <Col span={showServiceInstance ? 0 : 24}>
           {this.renderApp()}
         </Col>
diff --git a/src/routes/Service/ServiceInstance.js b/src/routes/Service/ServiceInstance.js
index 38197c4..b8a087a 100644
--- a/src/routes/Service/ServiceInstance.js
+++ b/src/routes/Service/ServiceInstance.js
@@ -108,7 +108,7 @@ export default class ServiceInstance extends PureComponent {
                 >
                   <Area
                     data={axisY(duration, this.bytesToMB(noheap.values), ({ x, y }) => ({ x, y, type: 'value' }))
-                    .concat(axisY(duration, this.bytesToMB(maxNoheap.values), ({ x, y }) => ({ x, y, type: 'free' })))}
+                      .concat(axisY(duration, this.bytesToMB(maxNoheap.values), ({ x, y }) => ({ x, y, type: 'free' })))}
                   />
                 </ChartCard>
               </Col>
@@ -139,7 +139,7 @@ export default class ServiceInstance extends PureComponent {
                 >
                   <StackBar
                     data={axisY(duration, youngGCTime.values, ({ x, y }) => ({ x, y, type: 'youngGCTime' }))
-                    .concat(axisY(duration, oldGCTime.values, ({ x, y }) => ({ x, y, type: 'oldGCTime' })))}
+                      .concat(axisY(duration, oldGCTime.values, ({ x, y }) => ({ x, y, type: 'oldGCTime' })))}
                   />
                 </ChartCard>
               </Col>
diff --git a/src/routes/Topology/Topology.js b/src/routes/Topology/Topology.js
index 9b066df..1e559a4 100644
--- a/src/routes/Topology/Topology.js
+++ b/src/routes/Topology/Topology.js
@@ -102,11 +102,11 @@ export default class Topology extends PureComponent {
     dispatch({
       type: 'topology/fetchMetrics',
       payload: { variables: {
-        duration,
-        ids,
-        idsS,
-        idsC,
-      }},
+          duration,
+          ids,
+          idsS,
+          idsC,
+        }},
     });
   }
 
@@ -116,10 +116,10 @@ export default class Topology extends PureComponent {
       dispatch({
         type: 'topology/saveData',
         payload: { appInfo: { ...appInfo,
-          sla: this.findValue(appInfo.id, sla.values),
-          cpm: this.findValue(appInfo.id, nodeCpm.values),
-          avgResponseTime: this.findValue(appInfo.id, nodeLatency.values),
-        } },
+            sla: this.findValue(appInfo.id, sla.values),
+            cpm: this.findValue(appInfo.id, nodeCpm.values),
+            avgResponseTime: this.findValue(appInfo.id, nodeLatency.values),
+          } },
       });
     } else {
       dispatch({
@@ -161,12 +161,12 @@ export default class Topology extends PureComponent {
       <Icon
         type="exception"
         onClick={() => redirect(this.props.history, '/trace',
-        { values: {
-            serviceId: appInfo.id,
-            duration: { ...this.props.duration, input: this.props.globalVariables.duration },
-          },
-          labels: { applicationId: appInfo.name },
-        })}
+          { values: {
+              serviceId: appInfo.id,
+              duration: { ...this.props.duration, input: this.props.globalVariables.duration },
+            },
+            labels: { applicationId: appInfo.name },
+          })}
       />,
       appInfo.isAlarm ? <Icon type="bell" onClick={() => redirect(this.props.history, '/monitor/alarm')} /> : null,
     ];
@@ -229,38 +229,38 @@ export default class Topology extends PureComponent {
           </Col>
           <Col {...{ ...colResponsiveProps, xl: 6, lg: 8 }}>
             {data.appInfo ? (
-              <Card
-                title={data.appInfo.name}
-                bodyStyle={{ height: 568 }}
-                actions={this.renderActions()}
-              >
-                <ApplicationLitePanel appInfo={data.appInfo} />
-              </Card>
-            )
-            : (
-              <Card title="Overview" style={{ height: 672 }}>
-                <Select
-                  mode="tags"
-                  style={{ width: '100%', marginBottom: 20 }}
-                  placeholder="Filter application"
-                  onChange={this.handleFilterApplication}
-                  tokenSeparators={[',']}
-                  value={appFilters}
+                <Card
+                  title={data.appInfo.name}
+                  bodyStyle={{ height: 568 }}
+                  actions={this.renderActions()}
                 >
-                  {data.getGlobalTopology.nodes.filter(_ => _.sla)
-                    .map(_ => <Option key={_.name}>{_.name}</Option>)}
-                </Select>
-                <Popover content={content} title="Info">
-                  <h4>Latency coloring thresholds  <Icon type="info-circle-o" /></h4>
-                </Popover>
-                <Input style={{ width: '100%', marginBottom: 20 }} onChange={this.handleChangeLatencyStyle} value={latencyRange.join(',')} />
-                <h4>Overview</h4>
-                <DescriptionList layout="vertical">
-                  <Description term="Total">{topologData.nodes.length}</Description>
-                  {this.renderNodeType(topologData)}
-                </DescriptionList>
-              </Card>
-            )}
+                  <ApplicationLitePanel appInfo={data.appInfo} />
+                </Card>
+              )
+              : (
+                <Card title="Overview" style={{ height: 672 }}>
+                  <Select
+                    mode="tags"
+                    style={{ width: '100%', marginBottom: 20 }}
+                    placeholder="Filter application"
+                    onChange={this.handleFilterApplication}
+                    tokenSeparators={[',']}
+                    value={appFilters}
+                  >
+                    {data.getGlobalTopology.nodes.filter(_ => _.sla)
+                      .map(_ => <Option key={_.name}>{_.name}</Option>)}
+                  </Select>
+                  <Popover content={content} title="Info">
+                    <h4>Latency coloring thresholds  <Icon type="info-circle-o" /></h4>
+                  </Popover>
+                  <Input style={{ width: '100%', marginBottom: 20 }} onChange={this.handleChangeLatencyStyle} value={latencyRange.join(',')} />
+                  <h4>Overview</h4>
+                  <DescriptionList layout="vertical">
+                    <Description term="Total">{topologData.nodes.length}</Description>
+                    {this.renderNodeType(topologData)}
+                  </DescriptionList>
+                </Card>
+              )}
           </Col>
         </Row>
       </Panel>
diff --git a/src/routes/Topology/Topology.less b/src/routes/Topology/Topology.less
new file mode 100644
index 0000000..ea5b4a9
--- /dev/null
+++ b/src/routes/Topology/Topology.less
@@ -0,0 +1,83 @@
+.topoWrapper {
+  :global(.ant-radio-group.ant-radio-group-normal) {
+    font-size: 18px;
+    float: right;
+    position: relative;
+    z-index: 100;
+    :global(.ant-radio-button-wrapper.ant-radio-button-wrapper-checked) {
+      background-color: #227acb;
+    }
+  }
+}
+.applicationModal {
+  position: fixed;
+  z-index: 999;
+  height: 100%;
+  width: 25%;
+  top: 0;
+  bottom: 0;
+  right: 0;
+  margin-top: 0 !important;
+  padding-right: 0 !important;
+  :global(.ant-card) {
+    height: 100% !important;
+  }
+  :global(.ant-row) {
+    margin-right: 0 !important;
+    margin-left: 0 !important;
+  }
+  .closeIcon {
+    position: fixed;
+    top: 17px;
+    right: 27px;
+    cursor: pointer;
+  }
+  .nodeItem {
+    width: 100%;
+    height: 40px;
+    border: 1px solid #ddd;
+    border-bottom: 0;
+    // margin-bottom: 3px;
+    padding-right: 0 !important;
+    padding-left: 0 !important;
+    .text {
+      width: 49%;
+      display: block;
+      float: left;
+      border-right: 1px solid #ddd;
+      height: 100%;
+      line-height: 40px;
+      background-color: rgb(251, 251, 251);
+      color: rgb(195, 195, 195);
+      padding-left: 10px;
+    }
+    .value {
+      width: 49%;
+      display: block;
+      float: left;
+      padding-left: 15px;
+      height: 100%;
+      line-height: 40px;
+    }
+    &:last-of-type {
+      border-bottom: 1px solid #ddd;
+    }
+  }
+  .hLine {
+    width: calc(100% + 48px);
+    position: relative;
+    left: -24px;
+    margin-top: 40px;
+    border: .5px solid #ddd;
+  }
+}
+.modalShadow {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 900;
+  background-color: rgba(0, 0, 0, .2);
+}
+
diff --git a/src/routes/Trace/Trace.less b/src/routes/Trace/Trace.less
index e6ac825..e0f7b1c 100644
--- a/src/routes/Trace/Trace.less
+++ b/src/routes/Trace/Trace.less
@@ -1,65 +1,96 @@
-/*
- * 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 "~antd/lib/style/themes/default.less";
-@import "../../utils/utils.less";
-
-.tableList {
-  .tableListOperator {
-    margin-bottom: 16px;
-    button {
-      margin-right: 8px;
-    }
-  }
-}
-
-.tableListForm {
-  :global {
-    .ant-form-item {
-      margin-bottom: 24px;
-      margin-right: 0;
-      display: flex;
-      > .ant-form-item-label {
-        width: auto;
-        line-height: 32px;
-        padding-right: 8px;
-      }
-      .ant-form-item-control {
-        line-height: 32px;
-      }
-    }
-    .ant-form-item-control-wrapper {
-      flex: 1;
-    }
-  }
-  .submitButtons {
-    white-space: nowrap;
-    margin-bottom: 24px;
-  }
-}
-
-@media screen and (max-width: @screen-lg) {
-  .tableListForm :global(.ant-form-item) {
-    margin-right: 24px;
-  }
-}
-
-@media screen and (max-width: @screen-md) {
-  .tableListForm :global(.ant-form-item) {
-    margin-right: 8px;
-  }
-}
+/*
+ * 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 "~antd/lib/style/themes/default.less";
+@import "../../utils/utils.less";
+
+.tableList {
+  .tableListOperator {
+    margin-bottom: 16px;
+    button {
+      margin-right: 8px;
+    }
+  }
+}
+
+.tableListForm {
+  :global {
+    .ant-form-item {
+      margin-bottom: 24px;
+      margin-right: 0;
+      display: flex;
+      > .ant-form-item-label {
+        line-height: 32px;
+        padding-right: 8px;
+        min-width: 115px;
+        width: 12%;
+        text-align: left;
+      }
+      .ant-form-item-control {
+        line-height: 32px;
+      }
+    }
+    .ant-form-item-control-wrapper {
+      padding-left: 30px;
+      flex: 1;
+    }
+  }
+  .submitButtons {
+    white-space: nowrap;
+    margin-bottom: 24px;
+  }
+}
+
+@media screen and (max-width: @screen-lg) {
+  .tableListForm :global(.ant-form-item) {
+    margin-right: 24px;
+  }
+}
+
+@media screen and (max-width: @screen-md) {
+  .tableListForm :global(.ant-form-item) {
+    margin-right: 8px;
+  }
+}
+
+.toggleButtonGroup {
+  :global {
+    .ant-btn {
+      &:hover {
+        background-color: rgb(34, 122, 203);
+        color: white;
+      }
+      &.active {
+        background-color: rgb(34, 122, 203);
+        color: white;
+      }
+    }
+  }
+}
+
+.triangleContainer::before {
+  content: '';
+  border: inherit;
+  padding: 0.5em;
+  position: absolute;
+  background: inherit;/** 不加这个的话你会发现 这个伪元素不会将div的border-top给覆盖掉,bg-image默认是none,bg-color默认是transparent */
+  left: 76px;
+  top: -9px;
+  transform: rotate(45deg);
+  border-right: 0;
+  border-bottom: 0;
+}
diff --git a/src/routes/Trace/TraceSearch.js b/src/routes/Trace/TraceSearch.js
index cb48a9b..43dec7c 100644
--- a/src/routes/Trace/TraceSearch.js
+++ b/src/routes/Trace/TraceSearch.js
@@ -235,11 +235,11 @@ export default class Trace extends PureComponent {
           {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>);
-                })}
+                return (
+                  <Option key={service.key ? service.key : -1} value={service.key}>
+                    {service.label}
+                  </Option>);
+              })}
             </Select>
           )}
         </FormItem>
diff --git a/src/routes/Trace/TraceTimeline.js b/src/routes/Trace/TraceTimeline.js
index b97255a..cb5d4de 100644
--- a/src/routes/Trace/TraceTimeline.js
+++ b/src/routes/Trace/TraceTimeline.js
@@ -16,10 +16,11 @@
  */
 
 import React, { PureComponent } from 'react';
-import { Card, Badge, Row, Col, Tag } from 'antd';
+import { Card, Row, Col, Tag } from 'antd';
 import moment from 'moment';
 import { formatDuration } from '../../utils/time';
 import TraceStack from '../../components/TraceStack';
+import styles from './TraceTimeline.less';
 
 const timeFormat = 'YYYY-MM-DD HH:mm:ss';
 
@@ -54,9 +55,12 @@ export default class TraceTimeLine extends PureComponent {
         {
           items.map((_) => {
             return (
-              <Col key={_.name}>
-                <span>{_.name}</span>
-                <Badge count={_.count} style={{ backgroundColor: '#1890FF', marginLeft: 5 }} />
+              <Col key={_.name} className={styles.badge}>
+                {/* <span>{_.name}</span> */}
+                {/* <Badge count={_.count}
+              style={{ backgroundColor: 'rgb(236, 236, 236)', marginLeft: 5 }} /> */}
+                <span className={styles.badgeTitle}>{_.name}</span>
+                <span className={styles.badgeValue}>{_.count}</span>
               </Col>
             );
           })
@@ -89,7 +93,7 @@ export default class TraceTimeLine extends PureComponent {
           ])
         }
       >
-        <Tag style={{ marginBottom: 20 }}>{currentTraceId}</Tag>
+        <Tag className={styles.tag} style={{ marginBottom: 20 }}>{currentTraceId}</Tag>
         <TraceStack spans={spans} />
       </Card>
     );
diff --git a/src/routes/Trace/TraceTimeline.less b/src/routes/Trace/TraceTimeline.less
new file mode 100644
index 0000000..3c9a75c
--- /dev/null
+++ b/src/routes/Trace/TraceTimeline.less
@@ -0,0 +1,25 @@
+.badge {
+  .badgeValue {
+    background-color: rgb(236, 236, 236);
+    display: inline-block;
+    padding: 6px 10px;
+    margin-left: 6px;
+  }
+  .badgeValue, .badgeTitle {
+    font-size: 14px;
+  }
+
+  .badgeTitle {
+    margin-left: 10px;
+    color: rgba(0, 0, 0, 0.65);
+    font-weight: normal;
+  }
+}
+
+.tag {
+  border: none;
+  background-color: rgb(236, 236, 236);
+  padding: 10px 12px;
+  height: auto;
+  border-radius: 19px;
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services