feat: Implement a timeline for Events in a new page (#515)

diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index fac7849..8529304 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -36,6 +36,7 @@
   topology: 'Topology',
   trace: 'Trace',
   alarm: 'Alarm',
+  event: 'Event',
   auto: 'Auto',
   reload: 'Reload',
   usermode: 'User Mode',
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index 75b8d94..84ec613 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -36,6 +36,7 @@
   topology: '拓扑图',
   trace: '追踪',
   alarm: '告警',
+  event: '事件',
   auto: '自动',
   reload: '刷新',
   usermode: '用户模式',
diff --git a/src/constants/constant.ts b/src/constants/constant.ts
index f1c77cd..caaad35 100644
--- a/src/constants/constant.ts
+++ b/src/constants/constant.ts
@@ -40,5 +40,6 @@
   DASHBOARD = 'Dashboard',
   LOG = 'Log',
   TOPOLOGY = 'Topology',
+  EVENT = 'Event',
 }
 export const DEFAULT = 'default';
diff --git a/src/router.ts b/src/router.ts
index 7f8a651..5eff998 100644
--- a/src/router.ts
+++ b/src/router.ts
@@ -65,6 +65,11 @@
         component: () => import('./views/containers/alarm.vue'),
         meta: { icon: 'spam', title: 'alarm', exact: false },
       },
+      {
+        path: 'event',
+        component: () => import('./views/containers/event.vue'),
+        meta: { icon: 'storage', title: 'event', exact: false },
+      },
     ],
   },
 ];
diff --git a/src/store/index.ts b/src/store/index.ts
index 0e907fa..0610eee 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -26,6 +26,7 @@
 import rocketAlarm, { State as AlarmState } from '@/store/modules/alarm';
 import profileStore, { State as ProfileState } from '@/store/modules/profile/profile-store';
 import rocketLog, { State as LogState } from '@/store/modules/log';
+import rocketEvent, { State as EventState } from '@/store/modules/event';
 
 Vue.use(Vuex);
 
@@ -39,6 +40,7 @@
   rocketAlarm: AlarmState;
   profileStore: ProfileState;
   logStore: LogState;
+  eventStore: EventState;
 }
 
 export default new Vuex.Store({
@@ -52,5 +54,6 @@
     rocketAlarm,
     profileStore,
     rocketLog,
+    rocketEvent,
   },
 });
diff --git a/src/store/modules/event/index.ts b/src/store/modules/event/index.ts
new file mode 100644
index 0000000..03cb2b0
--- /dev/null
+++ b/src/store/modules/event/index.ts
@@ -0,0 +1,78 @@
+/**
+ * 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 { ActionTree, MutationTree, Commit } from 'vuex';
+import { Event } from '@/types/dashboard';
+import { AxiosResponse } from 'axios';
+import graph from '@/graph';
+import { QueryEventCondition } from '../../../types/dashboard';
+import { DurationTime } from '@/types/global';
+import * as types from '../../mutation-types';
+
+const Scopes = ['Service', 'ServiceInstance', 'Endpoint'];
+export interface State {
+  currentEvents: Event[];
+  totalSize: number;
+}
+
+const initState: State = {
+  currentEvents: [],
+  totalSize: 1,
+};
+
+// mutations
+const mutations: MutationTree<any> = {
+  [types.UPDATE_EVENTS](state: State, param: { events: Event[]; duration: DurationTime }) {
+    const events = param.events.map((d: Event) => {
+      d.scope = d.source.endpoint ? Scopes[2] : d.source.serviceInstance ? Scopes[1] : Scopes[0];
+      return d;
+    });
+    state.currentEvents = events;
+  },
+  [types.SET_TOTAL_SIZE](state: State, total: number) {
+    state.totalSize = total;
+  },
+};
+
+// actions
+const actions: ActionTree<State, any> = {
+  FETCH_EVENTS(context: { commit: Commit }, params: { condition: QueryEventCondition }) {
+    return graph
+      .query('queryEvents')
+      .params({ condition: params.condition })
+      .then((res: AxiosResponse) => {
+        if (!(res.data.data && res.data.data.fetchEvents)) {
+          context.commit('UPDATE_EVENTS', { events: [], duration: params.condition.time });
+          context.commit('SET_TOTAL_SIZE', 1);
+          return [];
+        }
+        context.commit('UPDATE_EVENTS', {
+          events: res.data.data.fetchEvents.events,
+          duration: params.condition.time,
+        });
+        context.commit('SET_TOTAL_SIZE', res.data.data.fetchEvents.total);
+
+        return res.data.data.fetchEvents.events || [];
+      });
+  },
+};
+
+export default {
+  state: initState,
+  actions,
+  mutations,
+};
diff --git a/src/store/modules/global/selectors.ts b/src/store/modules/global/selectors.ts
index 605317f..d200875 100644
--- a/src/store/modules/global/selectors.ts
+++ b/src/store/modules/global/selectors.ts
@@ -58,12 +58,14 @@
 // mutations
 const mutations: MutationTree<State> = {
   [types.SET_SERVICES](state: State, data: Option[]) {
-    state.services = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    const pageTypes = [PageTypes.LOG, PageTypes.EVENT] as string[];
+    state.services = pageTypes.includes(state.pageType) ? [{ label: 'All', key: '' }, ...data] : data;
     state.currentService = state.services[0] || {};
   },
   [types.SET_CURRENT_SERVICE](state: State, service: Option) {
     state.currentService = service;
-    if (state.pageType === PageTypes.LOG) {
+    const pageTypes = [PageTypes.LOG, PageTypes.EVENT] as string[];
+    if (pageTypes.includes(state.pageType)) {
       state.updateDashboard = service;
     }
   },
@@ -73,7 +75,8 @@
   },
 
   [types.SET_ENDPOINTS](state: State, data: Option[]) {
-    state.endpoints = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    const pageTypes = [PageTypes.LOG, PageTypes.EVENT] as string[];
+    state.endpoints = pageTypes.includes(state.pageType) ? [{ label: 'All', key: '' }, ...data] : data;
     if (!state.endpoints.length) {
       state.currentEndpoint = { key: '', label: '' };
       return;
@@ -85,7 +88,8 @@
     state.updateDashboard = endpoint;
   },
   [types.SET_INSTANCES](state: State, data: Option[]) {
-    state.instances = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    const pageTypes = [PageTypes.LOG, PageTypes.EVENT] as string[];
+    state.instances = pageTypes.includes(state.pageType) ? [{ label: 'All', key: '' }, ...data] : data;
     if (!state.instances.length) {
       state.currentInstance = { key: '', label: '' };
       return;
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index c23f013..f7baa67 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -149,3 +149,7 @@
 export const SET_LOG_CONDITIONS = 'SET_LOG_CONDITIONS';
 export const SET_SUPPORT_QUERY_LOGS_KEYWORDS = 'SET_SUPPORT_QUERY_LOGS_KEYWORDS';
 export const CLEAR_LOG_CONDITIONS = 'CLEAR_LOG_CONDITIONS';
+
+// Event
+export const UPDATE_EVENTS = 'UPDATE_EVENTS';
+export const SET_TOTAL_SIZE = 'SET_TOTAL_SIZE';
diff --git a/src/types/dashboard.d.ts b/src/types/dashboard.d.ts
index a96a432..050f9e6 100644
--- a/src/types/dashboard.d.ts
+++ b/src/types/dashboard.d.ts
@@ -75,7 +75,7 @@
   type: EventType;
   time: Duration;
   order: string;
-  size: number;
+  paging: { pageNum: number; pageSize: number; needTotal: boolean };
 }
 
 type SourceInput = {
@@ -99,4 +99,5 @@
   endTime: number | string;
   entityType?: string;
   checked?: boolean;
+  scope?: string;
 };
diff --git a/src/views/components/alarm/alarm-table.vue b/src/views/components/alarm/alarm-table.vue
index d52ecb9..917b12d 100644
--- a/src/views/components/alarm/alarm-table.vue
+++ b/src/views/components/alarm/alarm-table.vue
@@ -13,17 +13,17 @@
 See the License for the specific language governing permissions and
 limitations under the License. -->
 <template>
-  <div class="rk-alarm-table clear">
-    <div v-for="(i, index) in data" :key="index" class="mb-10 clear alarm-item" @click="showDetails(i)">
-      <div class="g-sm-3 grey sm hide-xs rk-alarm-time-line tr">
+  <div class="rk-timeline-table clear">
+    <div v-for="(i, index) in data" :key="index" class="mb-10 clear timeline-item" @click="showDetails(i)">
+      <div class="g-sm-3 grey sm hide-xs rk-time-line tr">
         {{ parseInt(i.startTime) | dateformat }}
       </div>
-      <div class="rk-alarm-table-i g-sm-9">
+      <div class="rk-timeline-table-i g-sm-9">
         <div class="message mb-5 b">
           {{ i.message }}
         </div>
         <div
-          class="rk-alarm-table-i-scope mr-10 l sm"
+          class="rk-timeline-table-i-scope mr-10 l sm"
           :class="{
             blue: i.scope === 'Service',
             green: i.scope === 'Endpoint',
@@ -100,7 +100,8 @@
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
   import { Alarm, Event } from '@/types/alarm';
-  import { EventsDetailHeaders, AlarmDetailCol, AlarmEventsDetailKeys } from './constant';
+  import { EventsDetailHeaders, AlarmDetailCol } from './constant';
+  import { EventsDetailKeys } from '../common/constant';
 
   @Component
   export default class AlarmTable extends Vue {
@@ -118,7 +119,7 @@
     private alarmTags: string[] = [];
     private AlarmDetailCol = AlarmDetailCol;
     private eventsHeaders = EventsDetailHeaders;
-    private eventsDetailKeys = AlarmEventsDetailKeys;
+    private eventsDetailKeys = EventsDetailKeys;
     private currentEvents: Event[] = [];
     private currentEvent: Event = {
       startTime: 0,
@@ -147,80 +148,5 @@
 </script>
 
 <style lang="scss" scoped>
-  .rk-alarm-table {
-    padding: 30px 20px 20px 40px;
-    flex-grow: 1;
-    overflow: auto;
-    height: 100%;
-  }
-  .rk-alarm-time-line {
-    padding: 14px 30px;
-    min-height: 63px;
-    max-width: 132px;
-  }
-  .rk-alarm-table-i {
-    padding: 10px 15px;
-    border-left: 4px solid rgba(46, 47, 51, 0.05);
-    position: relative;
-    &:after {
-      content: '';
-      display: inline-block;
-      position: absolute;
-      width: 7px;
-      height: 7px;
-      left: -23px;
-      top: 25px;
-      border-radius: 4px;
-      background-color: #448dfe;
-    }
-    &:before {
-      content: '';
-      display: inline-block;
-      position: absolute;
-      width: 1px;
-      height: calc(100% + 11px);
-      top: 0;
-      left: -20px;
-      border-radius: 5px;
-      background-color: #448dfe99;
-    }
-  }
-  .rk-alarm-table-i-scope {
-    display: inline-block;
-    padding: 0px 8px;
-    border: 1px solid;
-    margin-top: -1px;
-    border-radius: 4px;
-  }
-  .alarm-item {
-    cursor: pointer;
-  }
-  ul {
-    min-height: 100px;
-    overflow: auto;
-    margin-bottom: 20px;
-  }
-  li {
-    cursor: pointer;
-    > span {
-      width: 160px;
-      height: 20px;
-      line-height: 20px;
-      text-align: center;
-      display: inline-block;
-      border-bottom: 1px solid #ccc;
-      overflow: hidden;
-    }
-    .uuid {
-      width: 280px;
-    }
-  }
-  .keys {
-    font-weight: bold;
-    display: inline-block;
-    width: 120px;
-  }
-  .source > div {
-    padding-left: 120px;
-  }
+  @import '../common/index.scss';
 </style>
diff --git a/src/views/components/alarm/alarm-tool.vue b/src/views/components/alarm/alarm-tool.vue
index 408d6d0..16d3370 100644
--- a/src/views/components/alarm/alarm-tool.vue
+++ b/src/views/components/alarm/alarm-tool.vue
@@ -15,7 +15,7 @@
 <template>
   <nav class="rk-alarm-tool flex-h">
     <div class="flex-h alarm-conditions">
-      <AlarmSelect
+      <CommonSelector
         :title="$t('filterScope')"
         :value="alarmOption"
         @input="
@@ -51,11 +51,10 @@
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
   import { Action, Mutation, Getter } from 'vuex-class';
-  import AlarmSelect from './alarm-select.vue';
   import { Option, DurationTime } from '@/types/global';
-  import { ConditionTags } from '../common/index';
+  import { ConditionTags, CommonSelector } from '../common/index';
 
-  @Component({ components: { AlarmSelect, ConditionTags } })
+  @Component({ components: { CommonSelector, ConditionTags } })
   export default class AlarmTool extends Vue {
     @Getter('durationTime') private durationTime!: DurationTime;
     @Mutation('SET_EVENTS') private SET_EVENTS: any;
diff --git a/src/views/components/alarm/constant.ts b/src/views/components/alarm/constant.ts
index 40c9540..d163c4f 100644
--- a/src/views/components/alarm/constant.ts
+++ b/src/views/components/alarm/constant.ts
@@ -23,16 +23,6 @@
   { text: 'endTime', class: 'endTime' },
 ];
 
-export const AlarmEventsDetailKeys = [
-  { text: 'eventID', class: 'uuid' },
-  { text: 'eventName', class: 'name' },
-  { text: 'eventsType', class: 'type' },
-  { text: 'startTime', class: 'startTime' },
-  { text: 'endTime', class: 'endTime' },
-  { text: 'eventsMessage', class: 'message' },
-  { text: 'eventSource', class: 'source' },
-];
-
 export const AlarmDetailCol = [
   {
     label: 'scope',
diff --git a/src/views/components/alarm/alarm-select.vue b/src/views/components/common/common-selector.vue
similarity index 72%
rename from src/views/components/alarm/alarm-select.vue
rename to src/views/components/common/common-selector.vue
index 7d5fb8c..78dc60c 100644
--- a/src/views/components/alarm/alarm-select.vue
+++ b/src/views/components/common/common-selector.vue
@@ -14,7 +14,7 @@
 limitations under the License. -->
 <template>
   <div
-    class="rk-alarm-select cp flex-h"
+    class="rk-common-select cp flex-h"
     v-clickout="
       () => {
         visible = false;
@@ -23,33 +23,34 @@
     "
     :class="{ active: visible }"
   >
-    <div class="rk-alarm-bar-i flex-h" @click="visible = !visible">
-      <div class="mr-15 rk-alarm-bar-i-text">
+    <div class="rk-common-bar-i flex-h" @click="visible = !visible">
+      <rk-icon :icon="`${icon}`" class="icon lg mr-15" />
+      <div class="mr-15 rk-common-bar-i-text">
         <div class="sm grey">{{ title }}</div>
-        <div class="ell" v-tooltip:right.ellipsis="$t(value.label.toLowerCase()) || ''">
-          {{ $t(value.label.toLowerCase()) || '' }}
+        <div class="ell" v-tooltip:right.ellipsis="value.label || ''">
+          {{ value.label || '' }}
         </div>
       </div>
       <svg class="icon lg trans" :style="`transform: rotate(${visible ? 180 : 0}deg)`">
         <use xlink:href="#arrow-down"></use>
       </svg>
     </div>
-    <div class="rk-alarm-sel" v-if="visible">
+    <div class="rk-common-sel" v-if="visible">
       <div v-if="hasSearch">
-        <input type="text" class="rk-alarm-sel-search" v-model="search" placeholder="Search..." />
+        <input type="text" class="rk-common-sel-search" v-model="search" placeholder="Search..." />
         <svg class="icon sm close" @click="search = ''" v-if="search">
           <use xlink:href="#clear"></use>
         </svg>
       </div>
-      <div class="rk-alarm-opt-wrapper scroll_bar_style">
+      <div class="rk-common-opt-wrapper scroll_bar_style">
         <div
-          class="rk-alarm-opt ell"
+          class="rk-common-opt ell"
           @click="handleSelect(i)"
           :class="{ active: i.key === value.key }"
           v-for="i in filterData"
           :key="i.key"
         >
-          {{ $t(i.label.toLowerCase()) }}
+          {{ i.label || '' }}
         </div>
       </div>
     </div>
@@ -59,13 +60,16 @@
 <script lang="ts">
   import { Vue, Component, Prop } from 'vue-property-decorator';
   @Component
-  export default class AlarmSelect extends Vue {
-    @Prop() public data!: any;
-    @Prop() public value!: any;
-    @Prop() public title!: string;
-    @Prop({ default: false }) public hasSearch!: boolean;
-    public search: string = '';
-    public visible: boolean = false;
+  export default class CommonSelector extends Vue {
+    @Prop() private icon!: string;
+    @Prop() private data!: any;
+    @Prop() private value!: any;
+    @Prop() private title!: string;
+    @Prop({ default: false }) private hasSearch!: boolean;
+
+    private search: string = '';
+    private visible: boolean = false;
+
     get filterData() {
       return this.data.filter((i: any) => i.label.toUpperCase().indexOf(this.search.toUpperCase()) !== -1);
     }
@@ -80,7 +84,7 @@
 </script>
 
 <style lang="scss" scoped>
-  .rk-alarm-select {
+  .rk-common-select {
     position: relative;
     z-index: 1;
     height: 100%;
@@ -92,16 +96,16 @@
       flex-shrink: 0;
     }
   }
-  .rk-alarm-bar-i-text {
+  .rk-common-bar-i-text {
     max-width: 150px;
     min-width: 80px;
   }
-  .rk-alarm-bar-i {
+  .rk-common-bar-i {
     height: 100%;
     padding: 0 15px;
     border-right: 2px solid #252a2f;
   }
-  .rk-alarm-sel {
+  .rk-common-sel {
     position: absolute;
     top: 50px;
     box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
@@ -119,14 +123,14 @@
       }
     }
   }
-  .rk-alarm-opt {
+  .rk-common-opt {
     padding: 7px 15px;
     &.active,
     &:hover {
       background-color: #40454e;
     }
   }
-  .rk-alarm-sel-search {
+  .rk-common-sel-search {
     width: calc(100% - 4px);
     border: 0;
     background-color: #333840;
@@ -135,7 +139,7 @@
     padding: 7px 25px 7px 10px;
     margin: 2px;
   }
-  .rk-alarm-opt-wrapper {
+  .rk-common-opt-wrapper {
     overflow: auto;
     max-height: 200px;
     padding-bottom: 2px;
diff --git a/src/views/components/common/constant.ts b/src/views/components/common/constant.ts
new file mode 100644
index 0000000..91692dc
--- /dev/null
+++ b/src/views/components/common/constant.ts
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+
+export const EventsDetailKeys = [
+  { text: 'eventID', class: 'uuid' },
+  { text: 'eventName', class: 'name' },
+  { text: 'eventsType', class: 'type' },
+  { text: 'startTime', class: 'startTime' },
+  { text: 'endTime', class: 'endTime' },
+  { text: 'eventsMessage', class: 'message' },
+  { text: 'eventSource', class: 'source' },
+];
diff --git a/src/views/components/common/index.scss b/src/views/components/common/index.scss
new file mode 100644
index 0000000..b5c879a
--- /dev/null
+++ b/src/views/components/common/index.scss
@@ -0,0 +1,93 @@
+/**
+ * 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.
+ */
+ 
+ .rk-timeline-table {
+  padding: 30px 20px 20px 40px;
+  flex-grow: 1;
+  overflow: auto;
+  height: 100%;
+  ul {
+    min-height: 100px;
+    overflow: auto;
+    margin-bottom: 20px;
+  }
+  li {
+    cursor: pointer;
+    > span {
+      width: 160px;
+      height: 20px;
+      line-height: 20px;
+      text-align: center;
+      display: inline-block;
+      border-bottom: 1px solid #ccc;
+      overflow: hidden;
+    }
+    .uuid {
+      width: 280px;
+    }
+  }
+  .keys {
+    font-weight: bold;
+    display: inline-block;
+    width: 120px;
+  }
+  .source > div {
+    padding-left: 120px;
+  }
+}
+.rk-time-line {
+  padding: 14px 30px;
+  min-height: 63px;
+  max-width: 132px;
+}
+.rk-timeline-table-i {
+  padding: 10px 15px;
+  border-left: 4px solid rgba(46, 47, 51, 0.05);
+  position: relative;
+  &:after {
+    content: '';
+    display: inline-block;
+    position: absolute;
+    width: 7px;
+    height: 7px;
+    left: -23px;
+    top: 25px;
+    border-radius: 4px;
+    background-color: #448dfe;
+  }
+  &:before {
+    content: '';
+    display: inline-block;
+    position: absolute;
+    width: 1px;
+    height: calc(100% + 11px);
+    top: 0;
+    left: -20px;
+    border-radius: 5px;
+    background-color: #448dfe99;
+  }
+}
+.rk-timeline-table-i-scope {
+  display: inline-block;
+  padding: 0px 8px;
+  border: 1px solid;
+  margin-top: -1px;
+  border-radius: 4px;
+}
+.timeline-item {
+  cursor: pointer;
+}
\ No newline at end of file
diff --git a/src/views/components/common/index.ts b/src/views/components/common/index.ts
index b6eaf3a..d271566 100644
--- a/src/views/components/common/index.ts
+++ b/src/views/components/common/index.ts
@@ -18,5 +18,6 @@
 import TraceDetailChartTable from './trace-detail-chart-table.vue';
 import TraceDetailStatisticsTable from './trace-detail-statistics-table.vue';
 import ConditionTags from './condition-tags.vue';
+import CommonSelector from './common-selector.vue';
 
-export { TraceDetailChartTable, ConditionTags, TraceDetailStatisticsTable };
+export { TraceDetailChartTable, ConditionTags, TraceDetailStatisticsTable, CommonSelector };
diff --git a/src/views/components/common/trace-select.vue b/src/views/components/common/trace-select.vue
deleted file mode 100644
index 0efb27e..0000000
--- a/src/views/components/common/trace-select.vue
+++ /dev/null
@@ -1,154 +0,0 @@
-<!-- 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. -->
-<template>
-  <div
-    class="rk-trace-sel-wrapper flex-h"
-    v-clickout="
-      () => {
-        visible = false;
-        search = '';
-      }
-    "
-    :class="{ cp: !readonly, active: visible }"
-  >
-    <div class="rk-trace-bar-i flex-h" @click="visible = !visible && !readonly">
-      <div class="mr-15 rk-trace-bar-i-text">
-        <div class="sm grey">{{ title }}</div>
-        <div v-tooltip:right.ellipsis="value.label || ''">
-          {{ value.label || '' }}
-        </div>
-      </div>
-      <svg v-if="!readonly" class="icon lg trans" :style="`transform: rotate(${visible ? 180 : 0}deg)`">
-        <use xlink:href="#arrow-down"></use>
-      </svg>
-    </div>
-    <div class="rk-trace-sel" v-if="visible">
-      <div v-if="hasSearch">
-        <input
-          type="text"
-          class="rk-trace-sel-search"
-          v-model="search"
-          @keyup.enter="handlerEnter"
-          :placeholder="`${$t('search')}...`"
-        />
-        <svg class="icon sm close" @click="search = ''" v-if="search">
-          <use xlink:href="#clear"></use>
-        </svg>
-      </div>
-      <div class="rk-trace-opt-wrapper scroll_bar_style">
-        <div
-          class="rk-trace-opt ell"
-          @click="handleSelect(i)"
-          :class="{ active: i.key === value.key }"
-          v-for="(i, index) in filterData"
-          :key="i.key + index"
-        >
-          {{ i.label }}
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-  import { Vue, Component, Prop } from 'vue-property-decorator';
-  import { Option } from '@/types/global';
-  @Component
-  export default class TraceSelect extends Vue {
-    @Prop() public data!: Option[];
-    @Prop() public value!: Option;
-    @Prop() public title!: string;
-    @Prop({ default: false }) public hasSearch!: boolean;
-    @Prop({ default: false })
-    public readonly!: boolean;
-    public search: string = '';
-    public visible: boolean = false;
-    get filterData() {
-      return this.data.filter((i: Option) => i.label.toUpperCase().includes(this.search.toUpperCase()));
-    }
-    public handleSelect(i: any) {
-      this.$emit('input', i);
-      this.visible = false;
-    }
-    public handlerEnter() {
-      this.$emit('search', this.search);
-    }
-  }
-</script>
-
-<style lang="scss" scoped>
-  .rk-trace-sel-wrapper {
-    position: relative;
-    z-index: 2;
-    height: 100%;
-    justify-content: space-between;
-    .sm {
-      line-height: 13px;
-    }
-    .icon {
-      flex-shrink: 0;
-    }
-  }
-  .rk-trace-bar-i-text {
-    max-width: 350px;
-    min-width: 100px;
-    word-wrap: break-word;
-    word-break: break-all;
-  }
-  .rk-trace-bar-i {
-    height: 100%;
-    padding: 0 15px;
-    border-right: 2px solid #252a2f;
-  }
-  .rk-trace-sel {
-    position: absolute;
-    top: 44px;
-    box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
-    background-color: #252a2f;
-    width: 100%;
-    border-radius: 3px;
-    overflow: hidden;
-    .close {
-      position: absolute;
-      right: 10px;
-      top: 12px;
-      opacity: 0.6;
-      &:hover {
-        opacity: 1;
-      }
-    }
-  }
-  .rk-trace-opt {
-    padding: 7px 15px;
-    &.active,
-    &:hover {
-      background-color: #40454e;
-    }
-  }
-  .rk-trace-sel-search {
-    width: calc(100% - 4px);
-    border: 0;
-    background-color: #333840;
-    color: #eee;
-    outline: 0;
-    padding: 7px 25px 7px 10px;
-    margin: 2px;
-  }
-  .rk-trace-opt-wrapper {
-    overflow: auto;
-    max-height: 200px;
-    padding-bottom: 2px;
-  }
-</style>
diff --git a/src/views/components/dashboard/tool-bar/dashboard-events.vue b/src/views/components/dashboard/tool-bar/dashboard-events.vue
index 313c321..a6fdfa7 100644
--- a/src/views/components/dashboard/tool-bar/dashboard-events.vue
+++ b/src/views/components/dashboard/tool-bar/dashboard-events.vue
@@ -290,7 +290,11 @@
       return this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboard.currentService.label,
           },
@@ -303,7 +307,11 @@
       return this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboard.currentService.label,
             serviceInstance: this.stateDashboard.currentInstance.label,
@@ -317,7 +325,11 @@
       return this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboard.currentService.label,
             endpoint: this.stateDashboard.currentEndpoint.label,
diff --git a/src/views/components/dashboard/tool-bar/tool-bar-select.vue b/src/views/components/dashboard/tool-bar/tool-bar-select.vue
index 10289f9..9afa3f8 100644
--- a/src/views/components/dashboard/tool-bar/tool-bar-select.vue
+++ b/src/views/components/dashboard/tool-bar/tool-bar-select.vue
@@ -24,9 +24,7 @@
     :class="{ active: visible, cp: selectable, cd: !selectable }"
   >
     <div class="rk-dashboard-bar-i flex-h" @click="selectable && (visible = !visible)">
-      <svg class="icon lg mr-15">
-        <use :xlink:href="`#${icon}`"></use>
-      </svg>
+      <rk-icon :icon="`${icon}`" class="icon lg mr-15" />
       <div class="mr-15 rk-dashboard-bar-i-text">
         <div class="sm grey">{{ title }}</div>
         <div class="selector-ell" v-tooltip:right.ellipsis="current.label || ''">
diff --git a/src/views/components/dashboard/tool-bar/tool-bar.vue b/src/views/components/dashboard/tool-bar/tool-bar.vue
index 30a78a4..8b2eab0 100644
--- a/src/views/components/dashboard/tool-bar/tool-bar.vue
+++ b/src/views/components/dashboard/tool-bar/tool-bar.vue
@@ -168,7 +168,11 @@
       this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: i.label,
           },
@@ -184,7 +188,11 @@
       this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboard.currentService.label,
             endpoint: i.label,
@@ -203,7 +211,11 @@
       this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboard.currentService.label,
             serviceInstance: i.label,
diff --git a/src/views/components/event/event-search.vue b/src/views/components/event/event-search.vue
new file mode 100644
index 0000000..008be3b
--- /dev/null
+++ b/src/views/components/event/event-search.vue
@@ -0,0 +1,183 @@
+<!-- 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. -->
+<template>
+  <nav class="rk-event-tool flex-h">
+    <div class="flex-h event-selector">
+      <CommonSelector
+        :hasSearch="true"
+        :title="$t('currentService')"
+        @input="selectService"
+        :value="rocketOption.currentService"
+        :data="rocketOption.services"
+        icon="package"
+      />
+      <CommonSelector
+        :hasSearch="true"
+        :title="$t('currentInstance')"
+        :value="rocketOption.currentInstance"
+        :data="rocketOption.instances"
+        @input="selectInstance"
+        icon="disk"
+      />
+      <CommonSelector
+        :hasSearch="true"
+        :title="$t('currentEndpoint')"
+        @input="selectEndpoint"
+        :value="rocketOption.currentEndpoint"
+        :data="rocketOption.endpoints"
+        icon="code"
+      />
+      <CommonSelector
+        :title="$t('eventsType')"
+        :value="eventType"
+        @input="chooseStatus"
+        :data="[
+          { label: 'All', key: '' },
+          { label: 'Normal', key: 'Normal' },
+          { label: 'Error', key: 'Error' },
+        ]"
+        icon="equalizer"
+      />
+    </div>
+    <div class="flex-h rk-right">
+      <a class="rk-event-search-btn bg-blue" @click="queryEvents">
+        <rk-icon icon="search" class="mr-5" />
+        <span class="vm">{{ $t('search') }}</span>
+      </a>
+      <RkPage :currentSize="pageSize" :currentPage="pageNum" @changePage="updatePage" :total="rocketEvent.totalSize" />
+    </div>
+  </nav>
+</template>
+
+<script lang="ts">
+  import Vue from 'vue';
+  import { Component } from 'vue-property-decorator';
+  import { Action, Getter, State, Mutation } from 'vuex-class';
+  import { Option, DurationTime } from '@/types/global';
+  import { CommonSelector } from '../common/index';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as EventState } from '@/store/modules/event';
+  import { PageTypes } from '@/constants/constant';
+
+  @Component({ components: { CommonSelector } })
+  export default class EventSearch extends Vue {
+    @Action('SELECT_SERVICE') private SELECT_SERVICE: any;
+    @Action('SELECT_ENDPOINT') private SELECT_ENDPOINT: any;
+    @Action('SELECT_INSTANCE') private SELECT_INSTANCE: any;
+    @Getter('durationTime') private durationTime!: DurationTime;
+    @Mutation('SET_EVENTS') private SET_EVENTS: any;
+    @State('rocketOption') private rocketOption!: optionState;
+    @State('rocketEvent') private rocketEvent!: EventState;
+    @Action('MIXHANDLE_GET_OPTION') private MIXHANDLE_GET_OPTION: any;
+    @Action('FETCH_EVENTS') private FETCH_EVENTS: any;
+
+    private eventType: Option = { label: 'All', key: '' };
+    private pageSize: number = 20;
+    private pageNum: number = 1;
+
+    private beforeMount() {
+      this.MIXHANDLE_GET_OPTION({
+        compType: 'service',
+        duration: this.durationTime,
+        pageType: PageTypes.EVENT,
+      }).then(() => {
+        this.queryEvents();
+      });
+      this.SET_EVENTS([
+        () => {
+          this.queryEvents();
+        },
+      ]);
+    }
+
+    private selectService(i: { key: string; label: string }) {
+      this.SELECT_SERVICE({ service: i, duration: this.durationTime });
+    }
+    private selectEndpoint(i: { key: string; label: string }) {
+      this.SELECT_ENDPOINT({ endpoint: i, duration: this.durationTime });
+    }
+
+    private selectInstance(i: { key: string; label: string }) {
+      this.SELECT_INSTANCE({ instance: i, duration: this.durationTime });
+    }
+
+    private chooseStatus(i: Option) {
+      this.eventType = i;
+    }
+
+    private updatePage(pageNum: string) {
+      this.pageNum = Number(pageNum);
+      this.queryEvents();
+    }
+
+    private queryEvents() {
+      const { currentService, currentEndpoint, currentInstance } = this.rocketOption;
+
+      this.FETCH_EVENTS({
+        condition: {
+          time: this.durationTime,
+          paging: {
+            pageNum: this.pageNum,
+            pageSize: this.pageSize,
+            needTotal: true,
+          },
+          source: {
+            service: currentService.key ? currentService.label : '',
+            endpoint: currentEndpoint.key ? currentEndpoint.label : '',
+            serviceInstance: currentInstance.key ? currentInstance.label : '',
+          },
+          type: this.eventType.key || undefined,
+        },
+      });
+    }
+    private beforeDestroy() {
+      this.SET_EVENTS([]);
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .rk-event-tool {
+    flex-shrink: 0;
+    background-color: #333840;
+    color: #eee;
+    width: 100%;
+    height: 52px;
+    -webkit-box-pack: justify;
+    -ms-flex-pack: justify;
+    justify-content: space-between;
+  }
+  .event-selector {
+    height: 52px;
+  }
+  .rk-event-search-btn {
+    padding: 2px 9px;
+    background-color: #484b55;
+    border-radius: 4px;
+    margin-right: 20px;
+    &.bg-blue {
+      background-color: #448dfe;
+    }
+  }
+  .rk-event-tool-input {
+    border-style: unset;
+    outline: 0;
+    padding: 2px 5px;
+    border-radius: 3px;
+  }
+  .event-conditions {
+    height: 100%;
+  }
+</style>
diff --git a/src/views/components/event/event-timeline.vue b/src/views/components/event/event-timeline.vue
new file mode 100644
index 0000000..a64b76c
--- /dev/null
+++ b/src/views/components/event/event-timeline.vue
@@ -0,0 +1,106 @@
+<!-- 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. -->
+
+<template>
+  <div class="rk-timeline-table clear">
+    <div
+      v-for="(i, index) in rocketEvent.currentEvents"
+      :key="index"
+      class="mb-10 clear timeline-item"
+      @click="showEventDetails(i)"
+    >
+      <div class="g-sm-3 grey sm hide-xs rk-time-line tr">
+        {{ parseInt(i.startTime) | dateformat }}
+      </div>
+      <div class="rk-timeline-table-i g-sm-9">
+        <div class="message mb-5 b">
+          {{ i.message }}
+        </div>
+        <div
+          class="rk-timeline-table-i-scope mr-10 l sm"
+          :class="{
+            blue: i.scope === 'Service',
+            green: i.scope === 'Endpoint',
+            yellow: i.scope === 'ServiceInstance',
+          }"
+        >
+          {{ $t(i.scope.toLowerCase()) }}
+        </div>
+        <div class="grey sm show-xs">
+          {{ parseInt(i.startTime) | dateformat }}
+        </div>
+      </div>
+    </div>
+    <rk-sidebox :width="'90%'" :show.sync="showDetails" :title="$t('eventDetail')">
+      <div class="event-detail">
+        <div class="mb-10 rk-flex" v-for="(eventKey, index) in eventsDetailKeys" :key="index">
+          <span class="keys">{{ $t(eventKey.text) }}</span>
+          <span v-if="eventKey.class === 'parameters'">
+            <span v-for="(d, index) of currentEvent[d.class]" :key="index">{{ d.key }}={{ d.value }}; </span>
+          </span>
+          <span v-else-if="eventKey.class === 'startTime' || eventKey.class === 'endTime'">{{
+            currentEvent[eventKey.class] | dateformat
+          }}</span>
+          <span v-else-if="eventKey.class === 'source'" class="source">
+            <div>{{ $t('currentService') }}: {{ currentEvent[eventKey.class].service }}</div>
+            <div v-show="currentEvent[eventKey.class].endpoint">
+              {{ $t('currentEndpoint') }}: {{ currentEvent[eventKey.class].endpoint }}
+            </div>
+            <div v-show="currentEvent[eventKey.class].serviceInstance">
+              {{ $t('currentInstance') }}: {{ currentEvent[eventKey.class].serviceInstance }}
+            </div>
+          </span>
+          <span v-else>{{ currentEvent[eventKey.class] }}</span>
+        </div>
+      </div>
+    </rk-sidebox>
+  </div>
+</template>
+<script lang="ts">
+  import Vue from 'vue';
+  import { Component } from 'vue-property-decorator';
+  import { State } from 'vuex-class';
+  import { State as EventState } from '@/store/modules/event';
+  import { Event } from '@/types/dashboard';
+  import { EventsDetailKeys } from '../common/constant';
+
+  @Component({ components: {} })
+  export default class EventTimeline extends Vue {
+    @State('rocketEvent') private rocketEvent!: EventState;
+    private showDetails: boolean = false;
+    private currentEvent: any = {
+      startTime: 0,
+      endTime: 0,
+      message: '',
+      name: '',
+      type: '',
+      uuid: '',
+      source: {
+        service: '',
+        endpoint: '',
+        serviceInstance: '',
+      },
+    };
+    private eventsDetailKeys = EventsDetailKeys;
+
+    private showEventDetails(item: Event) {
+      this.showDetails = true;
+      this.currentEvent = item;
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  @import '../common/index.scss';
+</style>
diff --git a/src/views/components/log/log-bar.vue b/src/views/components/log/log-bar.vue
index 5e4f5d8..4042c8e 100644
--- a/src/views/components/log/log-bar.vue
+++ b/src/views/components/log/log-bar.vue
@@ -78,7 +78,7 @@
 <script lang="ts">
   import { Component, Vue } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
-  import TraceSelect from '../common/trace-select.vue';
+  import { CommonSelector } from '../common/index';
   import ToolBarSelect from '../dashboard/tool-bar/tool-bar-select.vue';
   import ToolBarEndpointSelect from '../dashboard/tool-bar/tool-bar-endpoint-select.vue';
   import LogConditions from './log-conditions.vue';
@@ -87,7 +87,7 @@
   import { PageTypes } from '@/constants/constant';
 
   @Component({
-    components: { TraceSelect, ToolBarSelect, ToolBarEndpointSelect, LogConditions },
+    components: { CommonSelector, ToolBarSelect, ToolBarEndpointSelect, LogConditions },
   })
   export default class Bar extends Vue {
     @State('rocketLog') private logState!: logState;
diff --git a/src/views/components/profile/profile-header.vue b/src/views/components/profile/profile-header.vue
index 809bd8c..704de77 100644
--- a/src/views/components/profile/profile-header.vue
+++ b/src/views/components/profile/profile-header.vue
@@ -26,7 +26,7 @@
         <span class="vm">{{ $t('search') }}</span>
       </a>
       <div class="flex-h">
-        <TraceSelect
+        <CommonSelector
           :hasSearch="true"
           :title="$t('service')"
           :value="headerSource.currentService"
@@ -49,10 +49,10 @@
   import { Duration, Option } from '@/types/global';
   import { Component, Prop, Vue } from 'vue-property-decorator';
   import { Mutation } from 'vuex-class';
-  import TraceSelect from '../common/trace-select.vue';
+  import { CommonSelector } from '../common/index';
   import ProfileTask from './profile-task.vue';
 
-  @Component({ components: { TraceSelect, ProfileTask } })
+  @Component({ components: { CommonSelector, ProfileTask } })
   export default class ProfileHeader extends Vue {
     @Prop() private headerSource: any;
     @Prop() private newTaskFields: any;
diff --git a/src/views/components/trace/trace-search.vue b/src/views/components/trace/trace-search.vue
index eb7cc52..c1322a4 100644
--- a/src/views/components/trace/trace-search.vue
+++ b/src/views/components/trace/trace-search.vue
@@ -35,15 +35,15 @@
         <span class="vm">{{ $t('clear') }}</span>
       </a>
       <div class="flex-h trace-select">
-        <TraceSelect
+        <CommonSelector
           :hasSearch="true"
           :title="$t('service')"
           :value="service"
           @input="chooseService"
           :data="rocketTrace.services"
         />
-        <TraceSelect :hasSearch="true" :title="$t('instance')" v-model="instance" :data="rocketTrace.instances" />
-        <TraceSelect
+        <CommonSelector :hasSearch="true" :title="$t('instance')" v-model="instance" :data="rocketTrace.instances" />
+        <CommonSelector
           :title="$t('status')"
           :value="traceState"
           @input="chooseStatus"
@@ -53,7 +53,7 @@
             { label: 'Error', key: 'ERROR' },
           ]"
         />
-        <TraceSelect
+        <CommonSelector
           :hasSearch="true"
           :title="$t('endpointName')"
           :value="endpoint"
@@ -91,12 +91,11 @@
   import { Duration, Option } from '@/types/global';
   import { Component, Vue, Watch } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
-  import TraceSelect from '../common/trace-select.vue';
-  import { ConditionTags } from '../common/index';
+  import { ConditionTags, CommonSelector } from '../common/index';
   import { State as traceState } from '@/store/modules/trace/index';
   import { State as globalState } from '@/store/modules/global/index';
   import dateFormatStep from '@/utils/dateFormat';
-  @Component({ components: { TraceSelect, ConditionTags } })
+  @Component({ components: { CommonSelector, ConditionTags } })
   export default class TraceSearch extends Vue {
     @State('rocketbot') private rocketbotGlobal!: globalState;
     @State('rocketTrace') private rocketTrace!: traceState;
diff --git a/src/views/containers/dashboard.vue b/src/views/containers/dashboard.vue
index 52ed14e..b53ecec 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -76,7 +76,6 @@
     @State('rocketData') private rocketComps!: dataState;
     @Action('MIXHANDLE_GET_OPTION') private MIXHANDLE_GET_OPTION: any;
     @Action('GET_ALL_TEMPLATES') private GET_ALL_TEMPLATES: any;
-    @Action('GET_EVENT') private GET_EVENT: any;
     @Getter('durationTime') private durationTime: any;
     @Mutation('SET_COMPS_TREE') private SET_COMPS_TREE: any;
     @Mutation('ADD_COMP') private ADD_COMP: any;
diff --git a/src/views/containers/event.vue b/src/views/containers/event.vue
new file mode 100644
index 0000000..50961f5
--- /dev/null
+++ b/src/views/containers/event.vue
@@ -0,0 +1,40 @@
+<!-- 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. -->
+<template>
+  <div class="rk-event flex-v">
+    <EventSearch />
+    <EventTimeline />
+  </div>
+</template>
+
+<script lang="ts">
+  import Vue from 'vue';
+  import Component from 'vue-class-component';
+  import EventSearch from '../components/event/event-search.vue';
+  import EventTimeline from '../components/event/event-timeline.vue';
+
+  @Component({
+    components: { EventSearch, EventTimeline },
+  })
+  export default class Event extends Vue {}
+</script>
+
+<style lang="scss" scoped>
+  .rk-event {
+    flex-grow: 1;
+    height: 100%;
+    min-height: 0;
+  }
+</style>
diff --git a/src/views/containers/topology/endpoint/index.vue b/src/views/containers/topology/endpoint/index.vue
index 0a578dc..0007292 100644
--- a/src/views/containers/topology/endpoint/index.vue
+++ b/src/views/containers/topology/endpoint/index.vue
@@ -155,7 +155,11 @@
       this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboardOption.currentService.label,
             endpoint: i.label,
diff --git a/src/views/containers/topology/instance/index.vue b/src/views/containers/topology/instance/index.vue
index 968fc23..7e8acb2 100644
--- a/src/views/containers/topology/instance/index.vue
+++ b/src/views/containers/topology/instance/index.vue
@@ -188,7 +188,11 @@
       this.GET_EVENT({
         condition: {
           time: this.durationTime,
-          size: 20,
+          paging: {
+            pageNum: 1,
+            pageSize: 20,
+            needTotal: true,
+          },
           source: {
             service: this.stateDashboardOption.currentService.label,
             serviceInstance: i.label,
diff --git a/src/views/containers/topology/trace/index.vue b/src/views/containers/topology/trace/index.vue
index f2e1633..7296b12 100644
--- a/src/views/containers/topology/trace/index.vue
+++ b/src/views/containers/topology/trace/index.vue
@@ -24,8 +24,8 @@
 
 <script lang="ts">
   import { Option } from '@/types/global';
-  import { Component, Vue, Prop, PropSync, Watch } from 'vue-property-decorator';
-  import { State, Action, Mutation } from 'vuex-class';
+  import { Component, Vue, Prop } from 'vue-property-decorator';
+  import { State } from 'vuex-class';
   import TraceSearch from '@/views/components/trace/trace-search.vue';
   import TraceTable from '@/views/components/trace/trace-table.vue';
   import TraceDetail from '@/views/components/trace/trace-detail.vue';
diff --git a/src/views/containers/topology/trace/trace-select.vue b/src/views/containers/topology/trace/trace-select.vue
deleted file mode 100644
index 6c37e26..0000000
--- a/src/views/containers/topology/trace/trace-select.vue
+++ /dev/null
@@ -1,144 +0,0 @@
-<!-- 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. -->
-<template>
-  <div
-    class="rk-trace-sel-wrapper flex-h"
-    v-clickout="
-      () => {
-        visible = false;
-        search = '';
-      }
-    "
-    :class="{ cp: !readonly, active: visible }"
-  >
-    <div class="rk-trace-bar-i flex-h" @click="visible = !visible && !readonly">
-      <div class="mr-15 rk-trace-bar-i-text">
-        <div class="sm grey">{{ title }}</div>
-        <div v-tooltip:right.ellipsis="value.label || ''">
-          {{ value.label || '' }}
-        </div>
-      </div>
-      <svg v-if="!readonly" class="icon lg trans" :style="`transform: rotate(${visible ? 180 : 0}deg)`">
-        <use xlink:href="#arrow-down"></use>
-      </svg>
-    </div>
-    <div class="rk-trace-sel" v-if="visible">
-      <div v-if="hasSearch">
-        <input type="text" class="rk-trace-sel-search" v-model="search" :placeholder="`${$t('search')}...`" />
-        <svg class="icon sm close" @click="search = ''" v-if="search">
-          <use xlink:href="#clear"></use>
-        </svg>
-      </div>
-      <div class="rk-trace-opt-wrapper scroll_bar_style">
-        <div
-          class="rk-trace-opt ell"
-          @click="handleSelect(i)"
-          :class="{ active: i.key === value.key }"
-          v-for="i in filterData"
-          :key="i.key"
-        >
-          {{ i.label }}
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts">
-  import { Vue, Component, Prop } from 'vue-property-decorator';
-  @Component
-  export default class TraceSelect extends Vue {
-    @Prop() public data!: any;
-    @Prop() public value!: any;
-    @Prop() public title!: string;
-    @Prop({ default: false }) public hasSearch!: boolean;
-    @Prop({ default: false })
-    public readonly!: boolean;
-    public search: string = '';
-    public visible: boolean = false;
-    get filterData() {
-      return this.data.filter((i: any) => i.label.toUpperCase().indexOf(this.search.toUpperCase()) !== -1);
-    }
-    public handleSelect(i: any) {
-      this.$emit('input', i);
-      this.visible = false;
-    }
-  }
-</script>
-
-<style lang="scss" scoped>
-  .rk-trace-sel-wrapper {
-    position: relative;
-    z-index: 2;
-    height: 100%;
-    justify-content: space-between;
-    .sm {
-      line-height: 13px;
-    }
-    .icon {
-      flex-shrink: 0;
-    }
-  }
-  .rk-trace-bar-i-text {
-    max-width: 350px;
-    min-width: 100px;
-    word-wrap: break-word;
-    word-break: break-all;
-  }
-  .rk-trace-bar-i {
-    height: 100%;
-    padding: 0 15px;
-    border-right: 2px solid #252a2f;
-  }
-  .rk-trace-sel {
-    position: absolute;
-    top: 44px;
-    box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
-    background-color: #252a2f;
-    width: 100%;
-    border-radius: 3px;
-    overflow: hidden;
-    .close {
-      position: absolute;
-      right: 10px;
-      top: 12px;
-      opacity: 0.6;
-      &:hover {
-        opacity: 1;
-      }
-    }
-  }
-  .rk-trace-opt {
-    padding: 7px 15px;
-    &.active,
-    &:hover {
-      background-color: #40454e;
-    }
-  }
-  .rk-trace-sel-search {
-    width: calc(100% - 4px);
-    border: 0;
-    background-color: #333840;
-    color: #eee;
-    outline: 0;
-    padding: 7px 25px 7px 10px;
-    margin: 2px;
-  }
-  .rk-trace-opt-wrapper {
-    overflow: auto;
-    max-height: 200px;
-    padding-bottom: 2px;
-  }
-</style>