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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-rocketbot-ui.git


The following commit(s) were added to refs/heads/master by this push:
     new a0ff494  display trace data in table  (#129)
a0ff494 is described below

commit a0ff494b96b3d253a604ba3c7c09e13c2b80c8b2
Author: k3vin <[email protected]>
AuthorDate: Mon Aug 12 21:41:17 2019 +0800

    display trace data in table  (#129)
    
    * add trace-detail display page with table
---
 package-lock.json                                  |   5 +
 src/assets/index.ts                                |   1 +
 src/assets/lang/en.ts                              |   1 +
 src/assets/lang/zh.ts                              |   1 +
 src/assets/svg/table.svg                           |  23 +++
 src/store/modules/global/index.ts                  |   6 +
 src/utils/tooltip.scss                             |   4 +
 src/utils/tooltip.ts                               |   2 +
 .../trace/trace-chart-table/collapse.gif           | Bin 0 -> 846 bytes
 .../components/trace/trace-chart-table/expand.gif  | Bin 0 -> 851 bytes
 .../trace/trace-chart-table/trace-container.vue    |  63 +++++++
 .../trace/trace-chart-table/trace-item.vue         | 184 +++++++++++++++++++++
 .../components/trace/trace-chart-table/trace.scss  |  31 ++++
 .../components/trace/trace-detail-chart-table.vue  | 169 +++++++++++++++++++
 .../components/trace/trace-detail-chart-tree.vue   |   2 +-
 src/views/components/trace/trace-detail.vue        |  27 ++-
 src/views/components/trace/trace-table.vue         |  10 +-
 17 files changed, 521 insertions(+), 8 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 7519b16..76d4816 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7343,6 +7343,11 @@
       "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=",
       "dev": true
     },
+    "noty": {
+      "version": "3.2.0-beta",
+      "resolved": "https://registry.npmjs.org/noty/-/noty-3.2.0-beta.tgz";,
+      "integrity": 
"sha512-a1//Rth1MTQ/GCvGzwBXrZqCwOPyxiIKMdHT1TlcdrDYBYVfb7vzwsU0N4x+j/HeIQTi6/pbP8lRtY9gBz/d3Q=="
+    },
     "npm-run-path": {
       "version": "2.0.2",
       "resolved": 
"http://registry.npm.taobao.org/npm-run-path/download/npm-run-path-2.0.2.tgz";,
diff --git a/src/assets/index.ts b/src/assets/index.ts
index 495b79b..c9856fd 100644
--- a/src/assets/index.ts
+++ b/src/assets/index.ts
@@ -28,6 +28,7 @@ import './svg/clear.svg';
 import './svg/issue-child.svg';
 import './svg/package.svg';
 import './svg/list-bulleted.svg';
+import './svg/table.svg';
 
 import './svg/earth.svg';
 import './svg/epic.svg';
diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index 3420a3d..7d36a8f 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -82,6 +82,7 @@ const m = {
   tags: 'Tags',
   logs: 'Logs',
   component: 'Component',
+  table: 'Table',
   list: 'List',
   tree: 'Tree',
   filterScope: 'Filter Scope',
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index 00c0c47..80ae5ed 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -82,6 +82,7 @@ const m = {
   tags: '标记',
   logs: '日志',
   component: '组件',
+  table: '表格',
   list: '列表',
   tree: '树结构',
   filterScope: '过滤范围',
diff --git a/src/assets/svg/table.svg b/src/assets/svg/table.svg
new file mode 100755
index 0000000..baa32eb
--- /dev/null
+++ b/src/assets/svg/table.svg
@@ -0,0 +1,23 @@
+<!-- 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. -->
+
+
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" 
xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>
+    <g id="table" stroke="none" stroke-width="1" fill="none" 
fill-rule="evenodd">
+        <g id="list-bulleted" fill="#FFFFFF" fill-rule="nonzero">
+            <path d="M1,2 C0.44771525,2 0,1.55228475 0,1 C0,0.44771525 
0.44771525,0 1,0 C1.55228475,0 2,0.44771525 2,1 C2,1.55228475 1.55228475,2 1,2 
Z M11,2 C10.4477153,2 10,1.55228475 10,1 C10,0.44771525 10.4477153,0 11,0 
C11.5522847,0 12,0.44771525 12,1 C12,1.55228475 11.5522847,2 11,2 Z M8,2 
C7.44771525,2 7,1.55228475 7,1 C7,0.44771525 7.44771525,0 8,0 C8.55228475,0 
9,0.44771525 9,1 C9,1.55228475 8.55228475,2 8,2 Z M4,2 C3.44771525,2 
3,1.55228475 3,1 C3,0.44771525 3.44771525,0 4,0 C4 [...]
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/src/store/modules/global/index.ts 
b/src/store/modules/global/index.ts
index 64b585e..f1f30cf 100644
--- a/src/store/modules/global/index.ts
+++ b/src/store/modules/global/index.ts
@@ -19,6 +19,7 @@ import { Commit, ActionTree, MutationTree, GetterTree, Getter 
} from 'vuex';
 import getLocalTime from '@/utils/localtime';
 import { Duration, DurationTime } from '@/types/global';
 import * as types from '@/store/mutation-types';
+import Vue from 'vue';
 
 let timer: any = null;
 
@@ -76,6 +77,7 @@ export interface State {
   edit: boolean;
   lock: boolean;
   utc: string | number;
+  eventHub: any;
 }
 
 const initState: State = {
@@ -89,10 +91,14 @@ const initState: State = {
   edit: false,
   lock: true,
   utc: window.localStorage.getItem('utc') || -(new Date().getTimezoneOffset() 
/ 60),
+  eventHub: new Vue(),
 };
 
 // getters
 const getters = {
+  globalEventHub(state: State): any {
+    return state.eventHub;
+  },
   duration(state: State): Duration {
     return {
       start: getLocalTime(parseInt(state.utc + '', 10), 
state.durationRow.start),
diff --git a/src/utils/tooltip.scss b/src/utils/tooltip.scss
index 33e01b4..0f975e7 100644
--- a/src/utils/tooltip.scss
+++ b/src/utils/tooltip.scss
@@ -53,6 +53,10 @@ $tooltip-bg:               #252a2f !default;
   }
 }
 
+.trace-detail-chart-table .rk-tooltip-popper .rk-tooltip-inner  {
+  max-width: 500px;
+} 
+
 // Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as 
of v3.3.1
 .rk-tooltip-popper {
   &[x-placement^="top"] {
diff --git a/src/utils/tooltip.ts b/src/utils/tooltip.ts
index aaa158f..b6b4133 100644
--- a/src/utils/tooltip.ts
+++ b/src/utils/tooltip.ts
@@ -110,6 +110,8 @@ export default {
 
     const $inner = document.createElement('div');
     $inner.setAttribute('class', 'rk-tooltip-inner');
+
+
     $content.appendChild($inner);
     $popper.appendChild($content);
     if (binding.value) {
diff --git a/src/views/components/trace/trace-chart-table/collapse.gif 
b/src/views/components/trace/trace-chart-table/collapse.gif
new file mode 100644
index 0000000..01e6914
Binary files /dev/null and 
b/src/views/components/trace/trace-chart-table/collapse.gif differ
diff --git a/src/views/components/trace/trace-chart-table/expand.gif 
b/src/views/components/trace/trace-chart-table/expand.gif
new file mode 100644
index 0000000..1b24ef1
Binary files /dev/null and 
b/src/views/components/trace/trace-chart-table/expand.gif differ
diff --git a/src/views/components/trace/trace-chart-table/trace-container.vue 
b/src/views/components/trace/trace-chart-table/trace-container.vue
new file mode 100644
index 0000000..2f2c8c8
--- /dev/null
+++ b/src/views/components/trace/trace-chart-table/trace-container.vue
@@ -0,0 +1,63 @@
+<template>
+    <div class="trace">
+      <div class="trace-header">
+        <div class="method">
+          Method
+        </div>
+        <div class="start-time">
+          Start Time
+        </div>
+        <div class="gap">
+          Gap(ms)
+        </div>
+        <div class="exec-ms">
+          Exec(ms)
+        </div>
+        <div class="exec-percent">
+          Exec(%)
+        </div>
+        <div class="self">
+          Self(ms)
+        </div>
+        <div class="api">
+          API
+        </div>
+        <div class="application">
+          Service
+        </div>
+      </div>
+
+      <slot> </slot>
+    </div>
+</template>
+<style lang="scss" scoped>
+@import './trace.scss';
+.trace {
+    font-size: 12px;
+    height: 100%;
+    overflow: auto;
+  }
+  .trace-header {
+    display: flex;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+  }
+
+  .trace-header div {
+    padding: 0 4px;
+    border: 1px solid transparent;
+    border-right: 1px dotted silver;
+    line-height: 30px;
+    background-color: #f3f4f9;;
+    padding: 0 4px;
+    border: 1px solid transparent;
+    border-right: 1px dotted silver;
+    overflow: hidden;
+    line-height: 30px;
+    overflow:hidden;
+    text-overflow:ellipsis;
+    white-space:nowrap        
+  }
+</style>
+
diff --git a/src/views/components/trace/trace-chart-table/trace-item.vue 
b/src/views/components/trace/trace-chart-table/trace-item.vue
new file mode 100644
index 0000000..1cfc27c
--- /dev/null
+++ b/src/views/components/trace/trace-chart-table/trace-item.vue
@@ -0,0 +1,184 @@
+<template>
+  <div>
+      <div @click="showSelectSpan" :class="['trace-item', 'level'+( data.level 
- 1)]">
+        <div :class="['method', 'level'+( data.level - 1)]" 
:style="{'text-indent': (data.level - 1) * 10 + 'px' }">
+          <span 
+              v-if="data.children && data.children.length > 0" 
+              @click.stop="toggle" 
+              :class="['trace-table-toggle', displayChildren? 'collapse': 
'expand']">
+
+          </span>
+          <span v-tooltip:bottom="{content: data.endpointName, popperCls: 
['trace-table-tooltip']}">
+            {{data.endpointName}}
+          </span>
+        </div>
+        <div class="start-time">
+          {{formatTime(data.startTime)}}
+        </div>
+        <div class="gap">
+          0
+        </div>
+        <div class="exec-ms">
+         {{(data.endTime - data.startTime)?(data.endTime - data.startTime) : 
'0'}} 
+        </div>
+        <div class="exec-percent">
+          <div class="outer-progress_bar" :style="{width: outterPercent}">
+              <div class="inner-progress_bar" :style="{width: 
innerPercent}"></div>
+          </div>
+        </div>
+        <div class="self">
+          {{data.dur ? data.dur + '' : '0'}}
+        </div>
+        <div class="api">
+          <span v-tooltip:bottom="data.component||'-'">{{data.component || 
'-'}}</span>
+        </div>
+        <div class="application">
+          <span 
v-tooltip:bottom="data.serviceCode||'-'">{{data.serviceCode}}</span>
+        </div>
+      </div>      
+    <div v-show="data.children && data.children.length > 0 && displayChildren" 
class="children-trace">
+        <item v-for="(item, index) in data.children" :key="index" 
:data="item"> </item>
+    </div>
+  </div>
+
+</template>
+<style lang="scss" scoped>
+  @import './trace.scss';
+  .trace-item.level0{
+      background: rgba(0, 0, 0, 0.04);;
+      color: #448dfe;
+      &:hover {
+        background: rgba(0, 0, 0, 0.04);;
+        color: #448dfe;
+      }
+      &::before{
+        position: absolute;
+        content: '';
+        width: 5px;
+        height: 100%;
+        background: #448dfe;
+        left: 0;
+      }      
+  }
+
+  .trace-table-toggle {
+    cursor: pointer;
+    height: 12px;
+    width: 12px;
+    display: inline-block;
+    &.collapse {
+      background: url('./collapse.gif') no-repeat;
+      background-size: 12px 12px;
+    }
+
+    &.expand {
+      background: url('./expand.gif') no-repeat;
+      background-size: 12px 12px;
+    }
+  }  
+
+  .trace-item {
+    display: flex;
+    position: relative;
+  }
+  .trace-item.selected {
+    background: rgba(0, 0, 0, 0.04);
+  }
+
+  .trace-item:not(.level0):hover {
+    background: rgba(0, 0, 0, 0.04);
+  }
+
+
+  .trace-item>div {
+    padding: 0 5px;
+    border: 1px solid transparent;
+    border-right: 1px dotted silver;
+    overflow: hidden;
+    line-height: 30px;
+    overflow:hidden;
+    text-overflow:ellipsis;
+    white-space:nowrap
+  }
+  .trace-item>div.method {
+    padding-left: 10px;
+  }
+  .trace-item div.exec-percent {
+    width: 10%;
+    padding-left: 8px;
+    padding-right: 8px;
+    .outer-progress_bar {
+      width: 100%;
+      height: 6px;
+      border-radius: 3px;
+      background: rgb(63, 177, 227);
+      position: relative;
+      margin-top: 11px;
+      border: none;
+    }
+    .inner-progress_bar {
+      position: absolute;
+      background: rgb(110, 64, 170);
+      height: 4px;
+      border-radius: 2px;
+      left: 0;
+      border:none;
+      top: 1px;
+    }
+  }
+
+
+</style>
+<script type="text/javascript">
+import moment from 'dayjs';
+import Popper from 'popper.js';
+export default {
+  name: 'item',
+  props: ['data'],
+  data() {
+    return {
+      displayChildren: true,
+    };
+  },
+  computed: {
+    selfTime() {
+      const {data} = this;
+      return  data.dur ? data.dur : 0;
+    },
+    execTime() {
+      const {data} = this;
+      return  (data.endTime - data.startTime) ? (data.endTime - 
data.startTime) : 0;
+    },
+    outterPercent() {
+      if (this.data.level === 1) {
+        return '100%';
+      } else {
+        const data = this.data;
+        const exec = (data.endTime - data.startTime) ? (data.endTime - 
data.startTime) : 0;
+        let result = (exec / data.totalExec * 100);
+        result = result > 100 ? 100 : result;
+        result = result.toFixed(4) + '%';
+        return result === '0.0000%' ? '0.9%' : result;
+      }
+    },
+    innerPercent() {
+      const result = (this.selfTime / this.execTime) * 100 .toFixed(4) + '%';
+      return result === '0.0000%' ? '0.9%' : result;
+    },
+    eventHub() {
+      return this.$store.getters.globalEventHub;
+    },
+  },
+  methods: {
+    toggle() {
+      this.displayChildren = ! this.displayChildren;
+    },
+    formatTime(timestamp) {
+      return moment(timestamp).format('HH:mm:ss SSS');
+    },
+    showSelectSpan() {
+      this.eventHub.$emit('HANDLE-SELECT-SPAN', this.data);
+    },
+  },
+};
+</script>
diff --git a/src/views/components/trace/trace-chart-table/trace.scss 
b/src/views/components/trace/trace-chart-table/trace.scss
new file mode 100644
index 0000000..10d191b
--- /dev/null
+++ b/src/views/components/trace/trace-chart-table/trace.scss
@@ -0,0 +1,31 @@
+.method {
+  width: 45%;
+}
+.argument {
+  width: 15%;
+}
+.start-time {
+  width: 5%;
+  min-width: 100px;
+}
+.gap {
+  width: 5%;
+}
+.exec-ms {
+  width: 6%;
+}
+.exec-percent {
+  width: 10%;
+}
+.self {
+  width: 5%;
+}
+.api {
+  width: 10%;
+}
+.agent {
+  width: 15%;
+}
+.application {
+  width: 15%;
+}
\ No newline at end of file
diff --git a/src/views/components/trace/trace-detail-chart-table.vue 
b/src/views/components/trace/trace-detail-chart-table.vue
new file mode 100644
index 0000000..d5f588b
--- /dev/null
+++ b/src/views/components/trace/trace-detail-chart-table.vue
@@ -0,0 +1,169 @@
+<template>
+
+  <div class="trace-detail-chart-table">
+    <TraceContainer>
+      <Item v-for="(item, index) in tableData"  :data="item"  :key="'key'+ 
index" /> 
+    </TraceContainer>
+    <rk-sidebox :show.sync="showDetail" :title="$t('spanInfo')">
+      <div class="rk-trace-detail">
+        <h5 class="mb-15">{{$t('tags')}}.</h5>
+        <div class="mb-10 clear"><span class="g-sm-4 
grey">{{$t('endpoint')}}:</span><span class="g-sm-8 
wba">{{this.currentSpan.label}}</span></div>
+        <div class="mb-10 clear"><span class="g-sm-4 
grey">{{$t('spanType')}}:</span><span class="g-sm-8 
wba">{{this.currentSpan.type}}</span></div>
+        <div class="mb-10 clear"><span class="g-sm-4 
grey">{{$t('component')}}:</span><span class="g-sm-8 
wba">{{this.currentSpan.component}}</span></div>
+        <div class="mb-10 clear"><span class="g-sm-4 grey">Peer:</span><span 
class="g-sm-8 wba">{{this.currentSpan.peer||'No Peer'}}</span></div>
+        <div class="mb-10 clear"><span class="g-sm-4 
grey">{{$t('error')}}:</span><span class="g-sm-8 
wba">{{this.currentSpan.isError}}</span></div>
+        <div class="mb-10 clear" v-for="i in this.currentSpan.tags" 
:key="i.key"><span class="g-sm-4 grey">{{i.key}}:</span><span class="g-sm-8 
wba">{{i.value}}</span></div>
+        <h5 class="mb-10" v-if="this.currentSpan.logs" 
v-show="this.currentSpan.logs.length">{{$t('logs')}}.</h5>
+        <div v-for="(i, index) in this.currentSpan.logs" :key="index">
+          <div class="mb-10 sm">
+            <span class="mr-10">{{$t('time')}}:</span>
+            <span class="grey">{{i.time | dateformat}}</span>
+          </div>
+          <div class="mb-15 clear" v-for="(_i, _index) in i.data" 
:key="_index">
+            <div class="mb-10">{{_i.key}}:</div>
+            <pre class="g-sm-8 mt-0 mb-0 sm" 
style="overflow:auto">{{_i.value}}</pre>
+          </div>
+        </div>
+      </div>
+    </rk-sidebox>
+  </div>
+</template>
+<style lang="scss">
+  .rk-tooltip-popper.trace-table-tooltip .rk-tooltip-inner{
+      max-width: 600px;
+  }
+</style>
+
+<script>
+import Item from './trace-chart-table/trace-item';
+import TraceContainer from './trace-chart-table/trace-container';
+/* eslint-disable */
+/* tslint:disable */
+export default {
+  components: {
+    Item,
+    TraceContainer,
+  },
+  props: ['data', 'traceId'],
+  watch: {
+    data(val, oldVal) {
+      if (!this.data.length) {
+        return;
+      }
+      this.tableData = this.formatData(this.changeTree());
+    },
+  },
+  data() {
+    return {
+      tableData: [],
+      diaplay: true,
+      // segmentId: [],
+      showDetail: false,
+      list: [],
+      currentSpan: [],
+    };
+  },
+  computed: {
+    eventHub() {
+      return this.$store.getters.globalEventHub
+    }
+  },
+  methods: {
+    // 给增加层级关系
+    formatData(arr, level = 1, totalExec = null) {
+      for (const item of arr) {
+        item.level = level;
+        totalExec = totalExec || (item.endTime - item.startTime);
+        item.totalExec = totalExec;
+        if (item.children && item.children.length > 0) {
+          this.formatData(item.children, level + 1, totalExec);
+        }
+      }
+      return arr;
+    },
+    traverseTree(node, spanId, segmentId, data) {
+      if (!node) {
+        return;
+      }
+      if (node.spanId === spanId && node.segmentId === segmentId) {
+        node.children.push(data);
+        return;
+      }
+      if (node.children && node.children.length > 0) {
+        for (const item of node.children) {
+          this.traverseTree(item, spanId, segmentId, data);
+        }
+      }
+    },
+    changeTree() {
+      if (this.data.length === 0) {
+        return [];
+      }
+      this.list = Array.from(new Set(this.data.map((i) => i.serviceCode)));
+      this.segmentId = [];
+      const segmentGroup = {};
+      const segmentIdGroup = [];
+      this.data.forEach((i) => {
+        i.label = i.endpointName || 'no operation name';
+        i.children = [];
+        if (segmentGroup[i.segmentId] === undefined) {
+          segmentIdGroup.push(i.segmentId);
+          segmentGroup[i.segmentId] = [];
+          segmentGroup[i.segmentId].push(i);
+        } else {
+          segmentGroup[i.segmentId].push(i);
+        }
+      });
+      segmentIdGroup.forEach((id) => {
+        const currentSegment = segmentGroup[id].sort((a, b) => b.parentSpanId 
- a.parentSpanId);
+        currentSegment.forEach((s) => {
+          const index = currentSegment.findIndex((i) => i.spanId === 
s.parentSpanId);
+          if (index !== -1) {
+            currentSegment[index].children.push(s);
+            currentSegment[index].children.sort((a, b) => a.spanId - b.spanId 
);
+          }
+        });
+        segmentGroup[id] = currentSegment[currentSegment.length - 1];
+      });
+      segmentIdGroup.forEach((id) => {
+        segmentGroup[id].refs.forEach((ref) => {
+          if (ref.traceId === this.traceId) {
+            this.traverseTree(segmentGroup[ref.parentSegmentId],
+              ref.parentSpanId,
+              ref.parentSegmentId,
+              segmentGroup[id]);
+          }
+        });
+        // if(segmentGroup[id].refs.length !==0 ) delete segmentGroup[id];
+      });
+      for (const i in segmentGroup) {
+        if (segmentGroup[i].refs.length === 0) {
+          this.segmentId.push(segmentGroup[i]);
+        }
+      }
+      this.segmentId.forEach((_, i) => {
+        this.collapse(this.segmentId[i]);
+      });
+      return this.segmentId;
+    },
+    collapse(d) {
+      if (d.children) {
+        let dur = d.endTime - d.startTime;
+        d.children.forEach((i) => {
+          dur -= (i.endTime - i.startTime);
+        });
+        d.dur = dur < 0 ? 0 : dur;
+        d.children.forEach((i) => this.collapse(i));
+      }
+    },
+    handleSelectSpan(data) {
+      this.currentSpan = data;
+      this.showDetail = true;
+    },
+  },
+  mounted() {
+    this.tableData = this.formatData(this.changeTree());
+    this.eventHub.$on('HANDLE-SELECT-SPAN', this.handleSelectSpan);
+  },
+};
+</script>
diff --git a/src/views/components/trace/trace-detail-chart-tree.vue 
b/src/views/components/trace/trace-detail-chart-tree.vue
index 5f4353a..0f8a52b 100644
--- a/src/views/components/trace/trace-detail-chart-tree.vue
+++ b/src/views/components/trace/trace-detail-chart-tree.vue
@@ -214,4 +214,4 @@ export default {
      fill: rgba(0,0,0,0.05)
    }
  }
-</style>
+</style>
\ No newline at end of file
diff --git a/src/views/components/trace/trace-detail.vue 
b/src/views/components/trace/trace-detail.vue
index 2a309c8..f6c25b7 100644
--- a/src/views/components/trace/trace-detail.vue
+++ b/src/views/components/trace/trace-detail.vue
@@ -29,22 +29,32 @@
           <option v-for="i in current.traceIds" :value="i" 
:key="i">{{i}}</option>
         </select>
       </div>
-      <a class="rk-btn sm r" :class="{'ghost':mode}" @click="mode = false">
+
+      <a class="rk-btn mr-5 sm r" :class="{'ghost':displayMode !== 'table'}" 
@click="displayMode = 'table'">
+         <svg class="icon vm sm rk-trace-table_svg-icon">
+          <use xlink:href="#table"></use>
+        </svg>
+        {{$t('table')}}</a>          
+      <a class="rk-btn mr-5 sm r" :class="{'ghost':displayMode !== 'tree'}" 
@click="displayMode = 'tree'">
         <svg class="icon vm sm">
           <use xlink:href="#issue-child"></use>
         </svg>
         {{$t('tree')}}</a>
-      <a class="rk-btn mr-5 sm r" :class="{'ghost':!mode}" @click="mode = 
true">
+      <a class="rk-btn mr-5 sm r" :class="{'ghost':displayMode !== 'list'}" 
@click="displayMode = 'list'">
          <svg class="icon vm sm">
           <use xlink:href="#list-bulleted"></use>
         </svg>
         {{$t('list')}}</a>
+
+            
       <div class="rk-tag mr-5">{{this.$t('start')}}</div><span class="mr-15 
sm">{{parseInt(current.start) | dateformat}}</span>
       <div class="rk-tag mr-5">{{this.$t('duration')}}</div><span class="mr-15 
sm">{{current.duration}} ms</span>
       <div class="rk-tag mr-5">{{this.$t('spans')}}</div><span 
class="sm">{{spans.length}}</span>
     </div>
-    <TraceDetailChartList v-if="mode&&current.endpointNames" :data="spans" 
:traceId="current.traceIds[0]"/>
-    <TraceDetailChartTree v-if="!mode&&current.endpointNames" :data="spans" 
:traceId="current.traceIds[0]"/>
+    <TraceDetailChartList v-if="displayMode == 'list'&&current.endpointNames" 
:data="spans" :traceId="current.traceIds[0]"/>
+    <TraceDetailChartTree v-if="displayMode == 'tree'&&current.endpointNames" 
:data="spans" :traceId="current.traceIds[0]"/>    
+    <TraceDetailChartTable v-if="displayMode == 
'table'&&current.endpointNames" :data="spans" :traceId="current.traceIds[0]"/>  
  
+
     <div v-if="!current.endpointNames" class="flex-h container">
       <svg class="icon rk-icon-trace">
         <use xlink:href="#unlink"></use>
@@ -57,16 +67,18 @@
 import { Vue, Component, Prop } from 'vue-property-decorator';
 import TraceDetailChartList from './trace-detail-chart-list.vue';
 import TraceDetailChartTree from './trace-detail-chart-tree.vue';
+import TraceDetailChartTable from './trace-detail-chart-table.vue';
 import { Trace, Span } from '@/types/trace';
 import { Action, State } from 'vuex-class';
 
-@Component({ components: { TraceDetailChartList, TraceDetailChartTree } })
+@Component({ components: { TraceDetailChartList, TraceDetailChartTree, 
TraceDetailChartTable } })
 export default class Header extends Vue {
   @State('rocketbot') private rocketbot: any;
   @Action('rocketTrace/GET_TRACE_SPANS') private GET_TRACE_SPANS: any;
   @Prop() private spans!: Span[];
   @Prop() private current!: Trace;
   private mode: boolean = true;
+  private displayMode: string = 'list';
 }
 </script>
 
@@ -75,6 +87,7 @@ export default class Header extends Vue {
   flex-shrink: 0;
   height: 100%;
   width: 75%;
+  overflow-y:auto;
 }
 .rk-trace-detail-wrapper {
   padding: 8px 30px;
@@ -101,4 +114,8 @@ export default class Header extends Vue {
   margin: 0 auto;
   fill: rgba(46, 47, 51, 0.15);
 }
+.rk-trace-table_svg-icon {
+  width: 11px;
+  height: 11px;
+}
 </style>
diff --git a/src/views/components/trace/trace-table.vue 
b/src/views/components/trace/trace-table.vue
index ef68c95..9a7b029 100644
--- a/src/views/components/trace/trace-table.vue
+++ b/src/views/components/trace/trace-table.vue
@@ -31,7 +31,7 @@
       </div>
       <div class="rk-trace-t-wrapper scroll_hide">
         <table class="rk-trace-t">
-          <tr class="rk-trace-tr cp" v-for="i in rocketTrace.traceList" 
@click="selectTrace(i)">
+          <tr class="rk-trace-tr cp" v-for="(i, index) in 
rocketTrace.traceList" @click="selectTrace(i)" :key="index">
             <td class="rk-trace-td" :class="{
                 'rk-trace-success':!i.isError,
                 'rk-trace-error':i.isError,
@@ -49,7 +49,7 @@
 </template>
 
 <script lang="ts">
-import { Component, Vue, Prop } from 'vue-property-decorator';
+import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
 import { Action, Getter, Mutation, State } from 'vuex-class';
 @Component
 export default class Home extends Vue {
@@ -60,6 +60,12 @@ export default class Home extends Vue {
   @Action('rocketTrace/GET_TRACELIST') private GET_TRACELIST: any;
   @Action('rocketTrace/GET_TRACE_SPANS') private GET_TRACE_SPANS: any;
   private loading: boolean = false;
+  @Watch('rocketTrace.traceList')
+  private onTraceListChange() {
+    if (this.rocketTrace.traceList && this.rocketTrace.traceList.length > 0) {
+      this.selectTrace(this.rocketTrace.traceList[0]);
+    }
+  }
   private selectTrace(i: any) {
     this.SET_CURRENT_TRACE(i);
     if (i.traceIds.length) {

Reply via email to