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 c49ea82  feat: implement Alerts for query errors (#542)
c49ea82 is described below

commit c49ea825b75fd54270da99482897558b548dc5f8
Author: Fine0830 <fine0...@outlook.com>
AuthorDate: Fri Sep 24 20:17:48 2021 +0800

    feat: implement Alerts for query errors (#542)
---
 src/components/index.ts                            |   6 +-
 src/components/rk-alert.vue                        | 131 +++++++++++++++++++++
 src/components/rk-icon.vue                         |   7 +-
 src/components/rk-sidebox.vue                      |   4 +-
 src/graph/index.ts                                 |  26 ++--
 src/store/modules/alarm/index.ts                   |  14 ++-
 .../modules/dashboard/dashboard-data-query.ts      |  10 +-
 src/store/modules/dashboard/dashboard-data.ts      |  23 +++-
 src/store/modules/dashboard/mutation-types.ts      |   2 +
 src/store/modules/event/index.ts                   |  13 +-
 src/store/modules/global/selectors.ts              |  42 ++++++-
 src/store/modules/log/index.ts                     |  11 ++
 src/store/modules/profile/profile-store.ts         |  50 +++++---
 src/store/modules/topology/index.ts                |  57 ++++++++-
 src/store/modules/trace/index.ts                   |  42 ++++++-
 src/store/mutation-types.ts                        |   6 +
 src/utils/tooltip.ts                               |  15 +--
 src/views/components/common/alerts-content.vue     |  72 +++++++++++
 .../components/common}/rk-footer.vue               |   3 +-
 .../components/common}/rk-header.vue               |   2 +-
 .../components/dashboard/charts/chart-edit.vue     |  10 +-
 src/views/components/dashboard/dashboard-item.vue  |   3 +-
 .../components/dashboard/tool-bar/tool-bar.vue     |   8 +-
 src/views/components/dashboard/tool-group.vue      |   1 -
 src/views/components/profile/profile-header.vue    |   5 +-
 src/views/components/profile/profile-task.vue      |   4 +-
 .../components/profile/profile-trace-detail.vue    |  10 +-
 src/views/components/profile/task-list.vue         |   3 +-
 .../components/topology/topo-service-metrics.vue   |   2 +-
 src/views/components/topology/topo-services.vue    |   1 +
 src/views/components/trace/trace-search.vue        |  51 ++++----
 src/views/containers/dashboard.vue                 |   7 +-
 src/views/containers/index.vue                     |  10 +-
 src/views/containers/profile.vue                   |   6 +-
 src/views/containers/topology/alarm/alarm-tool.vue |   2 +
 .../topology/endpoint-dependency/index.vue         |   2 +-
 src/views/containers/trace.vue                     |   2 +-
 37 files changed, 548 insertions(+), 115 deletions(-)

diff --git a/src/components/index.ts b/src/components/index.ts
index a5f02e8..7918f5a 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -16,8 +16,6 @@
  */
 
 import noty from './noty';
-import RkHeader from './rk-header.vue';
-import RkFooter from './rk-footer.vue';
 import RkFooterTime from './rk-footer-time.vue';
 import RkProgress from './rk-progress.vue';
 import RkPage from './rk-page.vue';
@@ -33,10 +31,9 @@ import RkBack from './rk-back.vue';
 import RkButton from './rk-button.vue';
 import RkIcon from './rk-icon.vue';
 import RkRadio from './rk-radio.vue';
+import RkAlert from './rk-alert.vue';
 
 const components: any = {
-  RkHeader,
-  RkFooter,
   RkProgress,
   RkDate,
   RkPanel,
@@ -52,6 +49,7 @@ const components: any = {
   RkButton,
   RkIcon,
   RkRadio,
+  RkAlert,
 };
 
 const componentsName: string[] = Object.keys(components);
diff --git a/src/components/rk-alert.vue b/src/components/rk-alert.vue
new file mode 100644
index 0000000..e2dee68
--- /dev/null
+++ b/src/components/rk-alert.vue
@@ -0,0 +1,131 @@
+<!-- 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 v-if="show" class="rk-alert flex-h" :class="type">
+    <span v-show="closable" @click="closeAlert">
+      <rk-icon icon="clearclose" class="close" />
+    </span>
+    <rk-icon v-show="showIcon" :icon="iconType" class="xll mr-5 tip-icon" />
+    <div class="rk-alert-content">
+      <div class="rk-alert-message">{{ message }}</div>
+      <div class="rk-alert-description">{{ description }}</div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+  import { Vue, Component, Prop } from 'vue-property-decorator';
+  @Component
+  export default class RkAlert extends Vue {
+    @Prop() private message!: string;
+    @Prop() private type!: string;
+    @Prop() private description!: string;
+    @Prop({ default: true }) private showIcon!: boolean;
+    @Prop({ default: true }) private closable!: boolean;
+    @Prop() private show!: boolean;
+
+    private iconType: string = 'error';
+
+    private mounted() {
+      this.iconType =
+        this.type === 'error'
+          ? 'highlight_remove'
+          : this.type === 'warning'
+          ? 'error_outline'
+          : this.type === 'info'
+          ? 'info_outline'
+          : 'sentiment_satisfied_alt';
+      setTimeout(() => {
+        this.$emit('update:show', false);
+      }, 30000);
+    }
+
+    private closeAlert() {
+      this.$emit('update:show', false);
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  .rk-alert {
+    position: relative;
+    display: flex;
+    word-wrap: break-word;
+    width: 580px;
+    z-index: 1000;
+    color: #000;
+    border-radius: 2px;
+    padding: 10px 10px;
+    align-items: flex-start;
+    transition: all 0.7s;
+    margin-bottom: 15px;
+    &.error {
+      border: 1px solid #ffccc7;
+      background-color: #fff2f0;
+    }
+    &.warning {
+      border: 1px solid #ffe58f;
+      background-color: #fffbe6;
+    }
+    &.info {
+      border: 1px solid #91d5ff;
+      background-color: #e6f7ff;
+    }
+    &.success {
+      border: 1px solid #b7eb8f;
+      background-color: #f6ffed;
+    }
+  }
+  .error {
+    .tip-icon {
+      color: #ff4d4f;
+    }
+  }
+  .warning {
+    .tip-icon {
+      color: #faad14;
+    }
+  }
+  .info {
+    .tip-icon {
+      color: #1890ff;
+    }
+  }
+  .success {
+    .tip-icon {
+      color: #52c41a;
+    }
+  }
+  .close {
+    font-size: 20px;
+    color: #00000073;
+    transition: color 0.3s;
+    position: absolute;
+    top: 2px;
+    right: 0;
+    cursor: pointer;
+    z-index: 1001;
+  }
+  .rk-alert-message {
+    font-size: 16px;
+  }
+  .rk-alert-content {
+    flex: 1;
+    min-width: 0;
+  }
+  .rk-alert-description {
+    line-height: 22px;
+  }
+</style>
diff --git a/src/components/rk-icon.vue b/src/components/rk-icon.vue
index 9a224ff..f9f0360 100644
--- a/src/components/rk-icon.vue
+++ b/src/components/rk-icon.vue
@@ -18,6 +18,7 @@ limitations under the License. -->
     :class="{
       sm: size === 'sm',
       lg: size === 'lg',
+      xll: size === 'xll',
       offset: offset,
       loading: loading,
     }"
@@ -46,13 +47,17 @@ limitations under the License. -->
     vertical-align: middle;
     fill: currentColor;
     &.sm {
-      width: 13px;
+      width: 1px;
       height: 13px;
     }
     &.lg {
       width: 18px;
       height: 18px;
     }
+    &.xll {
+      width: 25px;
+      height: 25px;
+    }
     &.offset {
       margin-top: -2px;
     }
diff --git a/src/components/rk-sidebox.vue b/src/components/rk-sidebox.vue
index 55b23a6..7cc1660 100644
--- a/src/components/rk-sidebox.vue
+++ b/src/components/rk-sidebox.vue
@@ -35,7 +35,9 @@ limitations under the License. -->
   export default {
     name: 'RkSidebox',
     props: {
-      show: {},
+      show: {
+        default: false,
+      },
       title: {
         default: '',
       },
diff --git a/src/graph/index.ts b/src/graph/index.ts
index e6fa409..d54560a 100644
--- a/src/graph/index.ts
+++ b/src/graph/index.ts
@@ -44,14 +44,24 @@ class Graph {
     return this;
   }
   public params(variablesData: any): AxiosPromise<void> {
-    return axios.post(
-      '/graphql',
-      {
-        query: query[this.queryData],
-        variables: variablesData,
-      },
-      { cancelToken: cancelToken() },
-    );
+    return axios
+      .post(
+        '/graphql',
+        {
+          query: query[this.queryData],
+          variables: variablesData,
+        },
+        { cancelToken: cancelToken() },
+      )
+      .then((res: any) => {
+        if (res.data.errors) {
+          res.data.errors = res.data.errors.map((e: { message: string }) => 
e.message).join(' ');
+        }
+        return res;
+      })
+      .catch((err) => {
+        throw err;
+      });
   }
 }
 
diff --git a/src/store/modules/alarm/index.ts b/src/store/modules/alarm/index.ts
index 265eb11..5163398 100644
--- a/src/store/modules/alarm/index.ts
+++ b/src/store/modules/alarm/index.ts
@@ -24,11 +24,13 @@ import { Alarm, AlarmParams } from '@/types/alarm';
 export interface State {
   alarmService: Alarm[];
   total: number;
+  alarmErrors: { [key: string]: string };
 }
 
 const initState: State = {
   alarmService: [],
   total: 0,
+  alarmErrors: {},
 };
 
 // getters
@@ -44,15 +46,25 @@ const mutations: MutationTree<State> = {
     state.alarmService = [];
     state.total = 0;
   },
+  [types.SET_ALARM_ERRORS](state: State, data: { msg: string; desc: string }) {
+    state.alarmErrors = {
+      ...state.alarmErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
 const actions: ActionTree<State, any> = {
-  GET_ALARM(context: { commit: Commit; state: State }, params: AlarmParams): 
Promise<void> {
+  GET_ALARM(context: { commit: Commit; state: State }, params: AlarmParams): 
Promise<any> {
     return graph
       .query('queryAlarms')
       .params(params)
       .then((res: AxiosResponse<any>) => {
+        context.commit(types.SET_ALARM_ERRORS, { msg: 'queryAlarms', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          return;
+        }
         if (res.data.data.getAlarm.items) {
           context.commit(types.SET_ALARM, res.data.data.getAlarm);
         }
diff --git a/src/store/modules/dashboard/dashboard-data-query.ts 
b/src/store/modules/dashboard/dashboard-data-query.ts
index 7318cce..1488ed3 100644
--- a/src/store/modules/dashboard/dashboard-data-query.ts
+++ b/src/store/modules/dashboard/dashboard-data-query.ts
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 
-import { Commit, ActionTree, Dispatch } from 'vuex';
+import { Commit, ActionTree, Dispatch, MutationTree } from 'vuex';
 import { AxiosResponse } from 'axios';
+import * as types from './mutation-types';
 import { State } from './dashboard-data';
 import graph from '@/graph';
 import { TopologyType } from '@/constants/constant';
@@ -236,6 +237,13 @@ const actions: ActionTree<State, any> = {
             .query(config.queryMetricType)
             .params(variable)
             .then((res: AxiosResponse) => {
+              if (res.data.errors) {
+                context.commit(types.SET_DASHBOARD_ERRORS, {
+                  msg: variable.condition.name,
+                  desc: res.data.errors,
+                });
+                return;
+              }
               const resData = res.data.data;
 
               return { ...resData, config, metricName: variable.condition.name 
};
diff --git a/src/store/modules/dashboard/dashboard-data.ts 
b/src/store/modules/dashboard/dashboard-data.ts
index 298a96c..da6054c 100644
--- a/src/store/modules/dashboard/dashboard-data.ts
+++ b/src/store/modules/dashboard/dashboard-data.ts
@@ -38,6 +38,7 @@ export interface State {
   enableEvents: boolean;
   eventsPageType: string;
   currentSeriesType: Option[];
+  dashboardErrors: { [key: string]: string };
 }
 
 const initState: State = {
@@ -47,11 +48,12 @@ const initState: State = {
   enableEvents: false,
   eventsPageType: PageEventsType.DASHBOARD_EVENTS,
   currentSeriesType: [],
+  dashboardErrors: {},
   ...dashboardLayout.state,
 };
 
 // mutations
-const mutations: MutationTree<any> = {
+const mutations: MutationTree<State> = {
   ...dashboardLayout.mutations,
   [types.SET_DASHBOARD_EVENTS](state: State, param: { events: Event[]; type: 
string; duration: DurationTime }) {
     const events = param.events.map((d: Event, index: number) => {
@@ -122,6 +124,12 @@ const mutations: MutationTree<any> = {
       item.checked = false;
     }
   },
+  [types.SET_DASHBOARD_ERRORS](state: State, data: { msg: string; desc: string 
}) {
+    state.dashboardErrors = {
+      ...state.dashboardErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -179,6 +187,10 @@ const actions: ActionTree<State, any> = {
           .query('queryTypeOfMetrics')
           .params({ name: item })
           .then((res: AxiosResponse) => {
+            context.commit(types.SET_DASHBOARD_ERRORS, { msg: 
'queryTypeOfMetrics', desc: res.data.errors });
+            if (res.data.errors) {
+              return;
+            }
             return res.data.data;
           });
       }),
@@ -189,7 +201,8 @@ const actions: ActionTree<State, any> = {
       .query('queryGetAllTemplates')
       .params({})
       .then((res: AxiosResponse) => {
-        if (!res.data.data) {
+        context.commit(types.SET_DASHBOARD_ERRORS, { msg: 
'queryGetAllTemplates', desc: res.data.errors });
+        if (res.data.errors) {
           return;
         }
         return res.data.data.getAllTemplates || [];
@@ -200,9 +213,11 @@ const actions: ActionTree<State, any> = {
       .query('queryEvents')
       .params({ condition: params.condition })
       .then((res: AxiosResponse) => {
-        if (!(res.data.data && res.data.data.fetchEvents)) {
+        context.commit(types.SET_DASHBOARD_ERRORS, { msg: 'queryEvents', desc: 
res.data.errors });
+        if (res.data.errors) {
           context.commit('SET_DASHBOARD_EVENTS', { events: [], type: 
params.type, duration: params.condition.time });
-          return [];
+
+          return;
         }
         context.commit('SET_DASHBOARD_EVENTS', {
           events: res.data.data.fetchEvents.events,
diff --git a/src/store/modules/dashboard/mutation-types.ts 
b/src/store/modules/dashboard/mutation-types.ts
index a526130..9d20042 100644
--- a/src/store/modules/dashboard/mutation-types.ts
+++ b/src/store/modules/dashboard/mutation-types.ts
@@ -45,6 +45,8 @@ export const SET_CLEAR_SELECTED_EVENTS = 
'SET_CLEAR_SELECTED_EVENTS';
 export const SET_SERVICE_DEPENDENCY = 'SET_SERVICE_DEPENDENCY';
 export const SET_SERVICE_INSTANCE_DEPENDENCY = 
'SET_SERVICE_INSTANCE_DEPENDENCY';
 export const SET_ENDPOINT_DEPENDENCY = 'SET_ENDPOINT_DEPENDENCY';
+export const SET_SELECTOR_ERRORS = 'SET_SELECTOR_ERRORS';
+export const SET_DASHBOARD_ERRORS = 'SET_DASHBOARD_ERRORS';
 
 // comp
 export const SET_CURRENT_GROUP = 'SET_CURRENT_GROUP';
diff --git a/src/store/modules/event/index.ts b/src/store/modules/event/index.ts
index 03cb2b0..57c4e38 100644
--- a/src/store/modules/event/index.ts
+++ b/src/store/modules/event/index.ts
@@ -27,11 +27,15 @@ const Scopes = ['Service', 'ServiceInstance', 'Endpoint'];
 export interface State {
   currentEvents: Event[];
   totalSize: number;
+  errorMessage: string;
+  eventErrors: { [key: string]: string };
 }
 
 const initState: State = {
   currentEvents: [],
   totalSize: 1,
+  errorMessage: '',
+  eventErrors: {},
 };
 
 // mutations
@@ -46,6 +50,12 @@ const mutations: MutationTree<any> = {
   [types.SET_TOTAL_SIZE](state: State, total: number) {
     state.totalSize = total;
   },
+  [types.SET_EVENT_ERRORS](state: State, data: { msg: string; desc: string }) {
+    state.eventErrors = {
+      ...state.eventErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -55,7 +65,8 @@ const actions: ActionTree<State, any> = {
       .query('queryEvents')
       .params({ condition: params.condition })
       .then((res: AxiosResponse) => {
-        if (!(res.data.data && res.data.data.fetchEvents)) {
+        context.commit(types.SET_EVENT_ERRORS, { msg: 'queryEvents', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
           context.commit('UPDATE_EVENTS', { events: [], duration: 
params.condition.time });
           context.commit('SET_TOTAL_SIZE', 1);
           return [];
diff --git a/src/store/modules/global/selectors.ts 
b/src/store/modules/global/selectors.ts
index 03768ab..e30593c 100644
--- a/src/store/modules/global/selectors.ts
+++ b/src/store/modules/global/selectors.ts
@@ -37,6 +37,7 @@ export interface State {
   destService: Option;
   destInstance: Option;
   destEndpoint: Option;
+  selectorErrors: { [key: string]: string };
 }
 
 const initState: State = {
@@ -53,6 +54,7 @@ const initState: State = {
   destService: { key: '', label: '' },
   destInstance: { key: '', label: '' },
   destEndpoint: { key: '', label: '' },
+  selectorErrors: {},
 };
 
 // mutations
@@ -134,6 +136,12 @@ const mutations: MutationTree<State> = {
     state.destEndpoint = { key: call.destEndpointId, label: 
call.destEndpointName };
     state.updateDashboard = { key: TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY + 
call.id };
   },
+  [types.SET_SELECTOR_ERRORS](state: State, data: { msg: string; desc: string 
}) {
+    state.selectorErrors = {
+      ...state.selectorErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -146,6 +154,11 @@ const actions: ActionTree<State, any> = {
       .query('queryServices')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'serviceErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_SERVICES, []);
+          return;
+        }
         context.commit(types.SET_SERVICES, res.data.data.services);
       });
   },
@@ -167,6 +180,11 @@ const actions: ActionTree<State, any> = {
         keyword: params.keyword,
       })
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'endpointErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_ENDPOINTS, []);
+          return;
+        }
         context.commit(types.SET_ENDPOINTS, res.data.data.getEndpoints);
       });
   },
@@ -179,6 +197,11 @@ const actions: ActionTree<State, any> = {
       .query('queryInstances')
       .params({ serviceId: context.state.currentService.key || '', ...params })
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'instanceErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_INSTANCES, []);
+          return;
+        }
         context.commit(types.SET_INSTANCES, res.data.data.getServiceInstances);
       });
   },
@@ -187,6 +210,11 @@ const actions: ActionTree<State, any> = {
       .query('queryDatabases')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'databaseErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_DATABASES, []);
+          return;
+        }
         context.commit(types.SET_DATABASES, res.data.data.services);
       });
   },
@@ -288,6 +316,10 @@ const actions: ActionTree<State, any> = {
       .query('queryEndpoints')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'itemEndpointErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return [];
+        }
         return res.data.data.getEndpoints;
       });
   },
@@ -296,6 +328,10 @@ const actions: ActionTree<State, any> = {
       .query('queryInstances')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'itemInstanceErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return [];
+        }
         return res.data.data.getServiceInstances;
       });
   },
@@ -307,7 +343,11 @@ const actions: ActionTree<State, any> = {
       .query('queryServices')
       .params(params)
       .then((res: AxiosResponse) => {
-        return res.data.data.services || [];
+        context.commit(types.SET_SELECTOR_ERRORS, { msg: 'itemServiceErrors', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return [];
+        }
+        return res.data.data.services;
       });
   },
 };
diff --git a/src/store/modules/log/index.ts b/src/store/modules/log/index.ts
index 2890f1d..6a61f97 100644
--- a/src/store/modules/log/index.ts
+++ b/src/store/modules/log/index.ts
@@ -30,6 +30,7 @@ export interface State {
   loading: boolean;
   conditions: any;
   supportQueryLogsByKeywords: boolean;
+  logErrors: { [key: string]: string };
 }
 
 const categories: Option[] = [
@@ -63,6 +64,7 @@ const logState: State = {
       : [],
   },
   supportQueryLogsByKeywords: true,
+  logErrors: {},
 };
 
 // mutations
@@ -100,6 +102,12 @@ const mutations: MutationTree<State> = {
     localStorage.removeItem('logTags');
     localStorage.removeItem('logTraceId');
   },
+  [types.SET_LOG_ERRORS](state: State, data: { msg: string; desc: string }) {
+    state.logErrors = {
+      ...state.logErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -112,6 +120,7 @@ const actions: ActionTree<State, any> = {
           .query('queryBrowserErrorLogs')
           .params(params)
           .then((res: AxiosResponse<any>) => {
+            context.commit(types.SET_LOG_ERRORS, { msg: 
'queryBrowserErrorLogs', desc: res.data.errors || '' });
             if (res.data && res.data.errors) {
               context.commit('SET_LOGS', []);
               context.commit('SET_LOGS_TOTAL', 0);
@@ -129,6 +138,7 @@ const actions: ActionTree<State, any> = {
           .query('queryServiceLogs')
           .params(params)
           .then((res: AxiosResponse<any>) => {
+            context.commit(types.SET_LOG_ERRORS, { msg: 'queryServiceLogs', 
desc: res.data.errors || '' });
             if (res.data && res.data.errors) {
               context.commit('SET_LOGS', []);
               context.commit('SET_LOGS_TOTAL', 0);
@@ -150,6 +160,7 @@ const actions: ActionTree<State, any> = {
       .query('queryLogsByKeywords')
       .params({})
       .then((res: AxiosResponse<any>) => {
+        context.commit(types.SET_LOG_ERRORS, { msg: 'queryLogsByKeywords', 
desc: res.data.errors || '' });
         if (res.data && res.data.errors) {
           return;
         }
diff --git a/src/store/modules/profile/profile-store.ts 
b/src/store/modules/profile/profile-store.ts
index 666fd8b..b62bf9b 100644
--- a/src/store/modules/profile/profile-store.ts
+++ b/src/store/modules/profile/profile-store.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-import { Commit, Dispatch } from 'vuex';
+import { Commit, Dispatch, MutationTree } from 'vuex';
 import { AxiosResponse } from 'axios';
 
 import graph from '@/graph';
@@ -41,6 +41,7 @@ export interface State {
   profileAnalyzation: any;
   highlightTop: boolean;
   currentSpan: any;
+  profileErrors: { [key: string]: string };
 }
 const initState: State = {
   headerSource: {
@@ -64,6 +65,7 @@ const initState: State = {
   profileAnalyzation: [],
   highlightTop: true,
   currentSpan: {},
+  profileErrors: {},
 };
 // getters
 const getters = {
@@ -73,7 +75,7 @@ const getters = {
 };
 
 // mutations
-const mutations = {
+const mutations: MutationTree<State> = {
   [types.SET_SERVICES](state: State, data: any[]) {
     state.headerSource.serviceSource = [{ key: 'all', label: 'All' }, ...data];
     state.headerSource.currentService = state.headerSource.serviceSource[0];
@@ -114,6 +116,12 @@ const mutations = {
   [types.SET_HIGHLIGHT_TOP](state: State) {
     state.highlightTop = !state.highlightTop;
   },
+  [types.SET_PROFILE_ERRORS](state: State, data: { msg: string; desc: string 
}) {
+    state.profileErrors = {
+      ...state.profileErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -126,8 +134,9 @@ const actions = {
       .query('queryServices')
       .params(params)
       .then((res: AxiosResponse) => {
-        if (!res.data.data) {
-          return;
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 'serviceErrors', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          return context.commit(types.SET_SERVICES, []);
         }
         context.commit(types.SET_SERVICES, res.data.data.services);
         context.dispatch('GET_TASK_LIST');
@@ -144,17 +153,17 @@ const actions = {
       .query('getProfileTaskList')
       .params(param)
       .then((res: AxiosResponse) => {
-        if (!res.data.data) {
-          return;
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 'getProfileTaskList', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return context.commit(types.SET_TASK_LIST, []);
         }
         context.commit(types.SET_TASK_LIST, res.data.data.getProfileTaskList);
-        return res.data.data.getProfileTaskList;
-      })
-      .then((data: any) => {
-        if (!data) {
+        const list = res.data.data.getProfileTaskList;
+        if (!list.length) {
           return;
         }
-        context.dispatch('GET_SEGMENT_LIST', { taskID: data[0].id });
+        context.dispatch('GET_SEGMENT_LIST', { taskID: list[0].id });
+        return;
       });
   },
   GET_SEGMENT_LIST(context: { commit: Commit; dispatch: Dispatch }, params: { 
taskID: string }) {
@@ -162,8 +171,9 @@ const actions = {
       .query('getProfileTaskSegmentList')
       .params(params)
       .then((res: AxiosResponse) => {
-        if (!res.data.data.getProfileTaskSegmentList) {
-          return;
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 
'getProfileTaskSegmentList', desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return context.commit(types.SET_SEGMENT_LIST, []);
         }
         const { getProfileTaskSegmentList } = res.data.data;
 
@@ -185,6 +195,10 @@ const actions = {
       .query('queryProfileSegment')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 'queryProfileSegment', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return context.commit(types.SET_SEGMENT_SPANS, []);
+        }
         const { getProfiledSegment } = res.data.data;
         if (!getProfiledSegment) {
           return;
@@ -208,9 +222,13 @@ const actions = {
       .query('getProfileAnalyze')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 'getProfileAnalyze', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return context.commit(types.SET_PROFILE_ANALYZATION, []);
+        }
         const { getProfileAnalyze, tip } = res.data.data;
         if (tip) {
-          return tip;
+          return { tip };
         }
         if (!getProfileAnalyze) {
           context.commit(types.SET_PROFILE_ANALYZATION, []);
@@ -243,6 +261,10 @@ const actions = {
       .query('saveProfileTask')
       .params({ creationRequest })
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_PROFILE_ERRORS, { msg: 'saveProfileTask', 
desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return;
+        }
         if (res.data.data && res.data.data.createTask && 
res.data.data.createTask.errorReason) {
           return res.data.data.createTask;
         }
diff --git a/src/store/modules/topology/index.ts 
b/src/store/modules/topology/index.ts
index 2288f39..d1b84e9 100644
--- a/src/store/modules/topology/index.ts
+++ b/src/store/modules/topology/index.ts
@@ -55,6 +55,11 @@ export interface State {
   instanceDependencyMode: string;
   editDependencyMetrics: boolean;
   topoTemplatesType: { [key: string]: any };
+  endpointErrors: string;
+  getTopoErrors: string;
+  endpointTopoErrors: string;
+  instanceTopoErrors: string;
+  topoErrors: { [key: string]: string };
 }
 
 const DefaultConfig = {
@@ -98,6 +103,11 @@ const initState: State = {
   editDependencyMetrics: false,
   topoEndpointDependency: {},
   topoTemplatesType: JSON.parse(localStorage.getItem('topoTemplateTypes') || 
JSON.stringify({})),
+  endpointErrors: '',
+  getTopoErrors: '',
+  endpointTopoErrors: '',
+  instanceTopoErrors: '',
+  topoErrors: {},
 };
 
 // getters
@@ -552,6 +562,12 @@ const mutations = {
     state.topoTemplatesType = data;
     localStorage.setItem('topoTemplateTypes', JSON.stringify(data));
   },
+  [types.SET_TOPO_ERRORS](state: State, data: { msg: string; desc: string }) {
+    state.topoErrors = {
+      ...state.topoErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -564,6 +580,10 @@ const actions: ActionTree<State, any> = {
       .query('queryServices')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TOPO_ERRORS, { msg: 'serviceErrors', desc: 
res.data.errors });
+        if (res.data.errors) {
+          return [];
+        }
         return res.data.data.services || [];
       });
   },
@@ -578,6 +598,10 @@ const actions: ActionTree<State, any> = {
       .query('queryEndpoints')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TOPO_ERRORS, { msg: 'endpointErrors', desc: 
res.data.errors });
+        if (res.data.errors) {
+          return [];
+        }
         return res.data.data.getEndpoints || [];
       });
   },
@@ -599,6 +623,7 @@ const actions: ActionTree<State, any> = {
       .query(query)
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TOPO_ERRORS, { msg: query, desc: 
res.data.errors || '' });
         if (res.data.errors) {
           context.commit(types.SET_TOPO, { calls: [], nodes: [] });
           return;
@@ -612,6 +637,11 @@ const actions: ActionTree<State, any> = {
           .query('queryTopoInfo')
           .params({ ...params, ids, idsC, idsS })
           .then((info: AxiosResponse) => {
+            context.commit(types.SET_TOPO_ERRORS, { msg: 'queryTopoInfo', 
desc: info.data.errors || '' });
+            if (info.data.errors) {
+              context.commit(types.SET_TOPO, { calls: [], nodes: [] });
+              return;
+            }
             const resInfo = info.data.data;
             if (!resInfo.sla) {
               return context.commit(types.SET_TOPO, { calls, nodes });
@@ -732,6 +762,9 @@ const actions: ActionTree<State, any> = {
       .post('/graphql', { query: querys, variables: { duration: 
params.duration } }, { cancelToken: cancelToken() })
       .then((res: AxiosResponse) => {
         if (res.data.errors) {
+          const msg = res.data.errors.map((e: { message: string }) => 
e.message).join(' ');
+
+          context.commit(types.SET_TOPO_ERRORS, { msg: 
'endpointDependencyError', desc: msg });
           context.commit(types.SET_ENDPOINT_DEPENDENCY, { calls: [], nodes: [] 
});
           return;
         }
@@ -743,6 +776,7 @@ const actions: ActionTree<State, any> = {
           nodes.push(...topo[key].nodes);
         }
         if (!nodes.length) {
+          context.commit(types.SET_TOPO_ERRORS, { msg: 
'endpointDependencyError', desc: '' });
           context.commit(types.SET_ENDPOINT_DEPENDENCY, { calls: [], nodes: [] 
});
           return;
         }
@@ -795,9 +829,13 @@ const actions: ActionTree<State, any> = {
           .post('/graphql', { query, variables: { duration: params.duration } 
}, { cancelToken: cancelToken() })
           .then((json: AxiosResponse<any>) => {
             if (json.data.errors) {
+              const msg = json.data.errors.map((e: { message: string }) => 
e.message).join(' ');
+
+              context.commit(types.SET_TOPO_ERRORS, { msg: 
'endpointDependencyError', desc: msg });
               context.commit(types.SET_ENDPOINT_DEPENDENCY, { calls: [], 
nodes: [] });
               return;
             }
+            context.commit(types.SET_TOPO_ERRORS, { msg: 
'endpointDependencyError', desc: '' });
             const cpms = json.data.data;
             const keys = Object.keys(cpms);
             for (const key of keys) {
@@ -823,8 +861,9 @@ const actions: ActionTree<State, any> = {
       .query('queryTopoInstanceDependency')
       .params(params)
       .then((res: AxiosResponse) => {
-        if (!(res.data && res.data.data)) {
-          return;
+        context.commit(types.SET_TOPO_ERRORS, { msg: 
'queryTopoInstanceDependency', desc: res.data.errors || '' });
+        if (res.data.errors) {
+          return [];
         }
         const clientIdsC = [] as string[];
         const serverIdsC = [] as string[];
@@ -846,6 +885,13 @@ const actions: ActionTree<State, any> = {
               duration: params.duration,
             })
             .then((json: AxiosResponse) => {
+              context.commit(types.SET_TOPO_ERRORS, {
+                msg: 'queryDependencyInstanceClientMetric',
+                desc: json.data.errors || '',
+              });
+              if (json.data.errors) {
+                return [];
+              }
               const clientCalls = [] as string[];
               for (const call of topoCalls) {
                 for (const cpm of json.data.data.cpmC.values) {
@@ -870,6 +916,13 @@ const actions: ActionTree<State, any> = {
               duration: params.duration,
             })
             .then((jsonResp: AxiosResponse) => {
+              context.commit(types.SET_TOPO_ERRORS, {
+                msg: 'queryDependencyInstanceServerMetric',
+                desc: jsonResp.data.errors || '',
+              });
+              if (jsonResp.data.errors) {
+                return [];
+              }
               const serverCalls = [] as string[];
               for (const call of topoCalls) {
                 for (const cpm of jsonResp.data.data.cpmC.values) {
diff --git a/src/store/modules/trace/index.ts b/src/store/modules/trace/index.ts
index 2fbdd3d..fd430d4 100644
--- a/src/store/modules/trace/index.ts
+++ b/src/store/modules/trace/index.ts
@@ -33,6 +33,10 @@ export interface State {
   currentTrace: Trace;
   traceSpanLogs: any[];
   traceSpanLogsTotal: number;
+  traceListErrors: string;
+  traceSpanErrors: string;
+  traceSpanLogErrors: string;
+  traceErrors: { [key: string]: string };
 }
 
 const initState: State = {
@@ -56,6 +60,10 @@ const initState: State = {
   },
   traceSpanLogs: [],
   traceSpanLogsTotal: 0,
+  traceListErrors: '',
+  traceSpanErrors: '',
+  traceSpanLogErrors: '',
+  traceErrors: {},
 };
 
 // mutations
@@ -119,6 +127,12 @@ const mutations: MutationTree<State> = {
   [types.SET_TRACE_SPAN_LOGS_TOTAL](state: State, data: number) {
     state.traceSpanLogsTotal = data;
   },
+  [types.SET_TRACE_ERRORS](state: State, data: { msg: string; desc: string }) {
+    state.traceErrors = {
+      ...state.traceErrors,
+      [data.msg]: data.desc,
+    };
+  },
 };
 
 // actions
@@ -131,6 +145,11 @@ const actions: ActionTree<State, any> = {
       .query('queryServices')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'serviceError', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_SERVICES, []);
+          return;
+        }
         context.commit(types.SET_SERVICES, res.data.data.services);
       });
   },
@@ -139,6 +158,11 @@ const actions: ActionTree<State, any> = {
       .query('queryServiceInstance')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'instanceError', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_INSTANCES, []);
+          return;
+        }
         context.commit(types.SET_INSTANCES, res.data.data.instanceId);
       });
   },
@@ -147,6 +171,11 @@ const actions: ActionTree<State, any> = {
       .query('queryEndpoints')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'endpointError', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_ENDPOINTS, []);
+          return;
+        }
         context.commit(types.SET_ENDPOINTS, res.data.data.getEndpoints);
       });
   },
@@ -159,6 +188,12 @@ const actions: ActionTree<State, any> = {
       .query('queryTraces')
       .params({ condition: context.state.traceForm })
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'queryTraces', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_TRACELIST, []);
+          context.commit(types.SET_TRACELIST_TOTAL, 0);
+          return;
+        }
         context.commit(types.SET_TRACELIST, res.data.data.data.traces);
         context.commit(types.SET_TRACELIST_TOTAL, res.data.data.data.total);
       });
@@ -169,6 +204,11 @@ const actions: ActionTree<State, any> = {
       .query('queryTrace')
       .params(params)
       .then((res: AxiosResponse) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'queryTraceSpan', desc: 
res.data.errors || '' });
+        if (res.data.errors) {
+          context.commit(types.SET_TRACE_SPANS, []);
+          return;
+        }
         context.commit(types.SET_TRACE_SPANS, res.data.data.trace.spans);
       });
   },
@@ -177,10 +217,10 @@ const actions: ActionTree<State, any> = {
       .query('queryServiceLogs')
       .params(params)
       .then((res: AxiosResponse<any>) => {
+        context.commit(types.SET_TRACE_ERRORS, { msg: 'queryServiceLogs', 
desc: res.data.errors || '' });
         if (res.data && res.data.errors) {
           context.commit('SET_TRACE_SPAN_LOGS', []);
           context.commit('SET_TRACE_SPAN_LOGS_TOTAL', 0);
-
           return;
         }
         context.commit('SET_TRACE_SPAN_LOGS', res.data.data.queryLogs.logs);
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index a348f5e..be751d7 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -59,6 +59,7 @@ export const SET_INSTANCE_INFO = 'SET_INSTANCE_INFO';
 // alarm
 export const SET_ALARM = 'SET_ALARM';
 export const CLEAR_ALARM = 'CLEAR_ALARM';
+export const SET_ALARM_ERRORS = 'SET_ALARM_ERRORS';
 
 // trace
 export const SET_TRACELIST = 'SET_TRACELIST';
@@ -72,6 +73,7 @@ export const SET_TRACE_LOGS = 'SET_TRACE_LOGS';
 export const SET_TRACE_LOGS_TOTAL = 'SET_TRACE_LOGS_TOTAL';
 export const SET_TRACE_SPAN_LOGS_TOTAL = 'SET_TRACE_SPAN_LOGS_TOTAL';
 export const SET_TRACE_SPAN_LOGS = 'SET_TRACE_SPAN_LOGS';
+export const SET_TRACE_ERRORS = 'SET_TRACE_ERRORS';
 
 // topo
 export const SET_TOPO = 'SET_TOPO';
@@ -121,6 +123,7 @@ export const ADD_TOPO_ENDPOINT_DEPENDENCY_COMP = 
'ADD_TOPO_ENDPOINT_DEPENDENCY_C
 export const EDIT_ENDPOINT_DEPENDENCY_CONFIG = 
'EDIT_ENDPOINT_DEPENDENCY_CONFIG';
 export const DELETE_TOPO_ENDPOINT_DEPENDENCY = 
'DELETE_TOPO_ENDPOINT_DEPENDENCY';
 export const UPDATE_TOPO_TEMPLATE_TYPES = 'UPDATE_TOPO_TEMPLATE_TYPES';
+export const SET_TOPO_ERRORS = 'SET_TOPO_ERRORS';
 
 // profile
 export const SET_TASK_OPTIONS = 'SET_TASK_OPTIONS';
@@ -133,6 +136,7 @@ export const SET_CURRENT_SEGMENT = 'SET_CURRENT_SEGMENT';
 export const SET_PROFILE_ANALYZATION = 'SET_PROFILE_ANALYZATION';
 export const SET_HIGHLIGHT_TOP = 'SET_HIGHLIGHT_TOP';
 export const SET_CURRENT_SPAN = 'SET_CURRENT_SPAN';
+export const SET_PROFILE_ERRORS = 'SET_PROFILE_ERRORS';
 
 // Log
 export const SELECT_LOG_TYPE = 'SELECT_LOG_TYPE';
@@ -149,10 +153,12 @@ export const SET_CURRENT_LOG_INSTANCE = 
'SET_CURRENT_LOG_INSTANCE';
 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';
+export const SET_LOG_ERRORS = 'SET_LOG_ERRORS';
 
 // Event
 export const UPDATE_EVENTS = 'UPDATE_EVENTS';
 export const SET_TOTAL_SIZE = 'SET_TOTAL_SIZE';
+export const SET_EVENT_ERRORS = 'SET_EVENT_ERRORS';
 
 // debug
 export const SET_TAB_TYPE = 'SET_TAB_TYPE';
diff --git a/src/utils/tooltip.ts b/src/utils/tooltip.ts
index 3ce60aa..e0e10fd 100644
--- a/src/utils/tooltip.ts
+++ b/src/utils/tooltip.ts
@@ -47,9 +47,7 @@ function setAttributes($inner: any, el: any) {
     return;
   }
   const isShow =
-    !popper._disabled &&
-    (popper._visible || popper._always) &&
-    (!popper._ellipsis || isEllipsisTooltip(el));
+    !popper._disabled && (popper._visible || popper._always) && 
(!popper._ellipsis || isEllipsisTooltip(el));
 
   if (popper._appendToBody) {
     if (isShow && popper.popper.parentNode !== document.body) {
@@ -82,13 +80,11 @@ function handleClosePopper(e: any) {
   }
 }
 
-// 添加事件
 function addEvent(el: any) {
   el.addEventListener('mouseenter', handleShowPopper);
   el.addEventListener('mouseleave', handleClosePopper);
 }
 
-// 移除事件
 function removeEvent(el: any) {
   el.removeEventListener('mouseenter', handleShowPopper);
   el.removeEventListener('mouseleave', handleClosePopper);
@@ -122,9 +118,7 @@ export default {
         $popper.style.display = 'none';
         el.appendChild($popper);
       } else {
-        $popper.className += ` append-to-body ${
-          binding.value.popperCls ? binding.value.popperCls.join(' ') : ''
-        }`;
+        $popper.className += ` append-to-body ${binding.value.popperCls ? 
binding.value.popperCls.join(' ') : ''}`;
       }
     }
 
@@ -145,10 +139,7 @@ export default {
       if (el.popper.popper) {
         el.removeChild(el.popper.popper);
       }
-    } else if (
-      el.popper.popper &&
-      el.popper.popper.parentNode === document.body
-    ) {
+    } else if (el.popper.popper && el.popper.popper.parentNode === 
document.body) {
       document.body.removeChild(el.popper.popper);
     }
   },
diff --git a/src/views/components/common/alerts-content.vue 
b/src/views/components/common/alerts-content.vue
new file mode 100644
index 0000000..9fdc638
--- /dev/null
+++ b/src/views/components/common/alerts-content.vue
@@ -0,0 +1,72 @@
+<!-- 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="alert-content">
+    <rk-alert
+      v-for="(msg, index) in Object.keys(allAlerts)"
+      :key="msg + index"
+      :show.sync="allAlerts[msg]"
+      type="error"
+      :message="msg"
+      :description="allAlerts[msg]"
+    />
+  </div>
+</template>
+
+<script lang="ts">
+  import { Component, Vue } from 'vue-property-decorator';
+  import { State } from 'vuex-class';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as rocketData } from 
'@/store/modules/dashboard/dashboard-data';
+  import { State as topoState } from '@/store/modules/topology';
+  import { State as profileState } from 
'@/store/modules/profile/profile-store';
+  import { State as logState } from '@/store/modules/log';
+  import { State as alarmState } from '@/store/modules/alarm';
+  import { State as EventState } from '@/store/modules/event';
+  import { State as traceState } from '@/store/modules/trace/index';
+
+  @Component
+  export default class AlertsContent extends Vue {
+    @State('rocketOption') private stateOption!: optionState;
+    @State('rocketData') private rocketData!: rocketData;
+    @State('rocketTopo') private stateTopo!: topoState;
+    @State('profileStore') private stateProfile!: profileState;
+    @State('rocketLog') private rocketLog!: logState;
+    @State('rocketAlarm') private rocketAlarm!: alarmState;
+    @State('rocketEvent') private rocketEvent!: EventState;
+    @State('rocketTrace') private rocketTrace!: traceState;
+
+    private get allAlerts() {
+      return {
+        ...this.rocketEvent.eventErrors,
+        ...this.stateOption.selectorErrors,
+        ...this.rocketData.dashboardErrors,
+        ...this.stateTopo.topoErrors,
+        ...this.stateProfile.profileErrors,
+        ...this.rocketLog.logErrors,
+        ...this.rocketAlarm.alarmErrors,
+        ...this.rocketTrace.traceErrors,
+      };
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  .alert-content {
+    position: fixed;
+    top: 60px;
+    right: 5px;
+    z-index: 1000;
+  }
+</style>
diff --git a/src/components/rk-footer.vue 
b/src/views/components/common/rk-footer.vue
similarity index 96%
rename from src/components/rk-footer.vue
rename to src/views/components/common/rk-footer.vue
index 0b24274..8a4074c 100644
--- a/src/components/rk-footer.vue
+++ b/src/views/components/common/rk-footer.vue
@@ -27,9 +27,8 @@ limitations under the License. -->
 </template>
 
 <script lang="ts">
-  import { Duration } from '@/types/global';
   import { Vue, Component, Watch } from 'vue-property-decorator';
-  import { State, Action, Mutation } from 'vuex-class';
+  import { State, Action } from 'vuex-class';
 
   @Component
   export default class Footerssd extends Vue {
diff --git a/src/components/rk-header.vue 
b/src/views/components/common/rk-header.vue
similarity index 99%
rename from src/components/rk-header.vue
rename to src/views/components/common/rk-header.vue
index 84d9a20..842e876 100644
--- a/src/components/rk-header.vue
+++ b/src/views/components/common/rk-header.vue
@@ -55,7 +55,7 @@ limitations under the License. -->
 
 <script lang="ts">
   import { Vue, Component } from 'vue-property-decorator';
-  import { Action, State, Getter } from 'vuex-class';
+  import { Action, Getter } from 'vuex-class';
   import { routes } from '@/router';
   import timeFormat from '@/utils/timeFormat';
 
diff --git a/src/views/components/dashboard/charts/chart-edit.vue 
b/src/views/components/dashboard/charts/chart-edit.vue
index a1170f2..998243a 100755
--- a/src/views/components/dashboard/charts/chart-edit.vue
+++ b/src/views/components/dashboard/charts/chart-edit.vue
@@ -480,9 +480,13 @@ limitations under the License. -->
           return;
         }
         if (data.length > 1) {
-          const length = data.filter((d: { typeOfMetrics: string }) => 
d.typeOfMetrics !== MetricsType.REGULAR_VALUE)
-            .length;
-          if (length) {
+          let len = 0;
+          for (const d of data) {
+            if (d.typeOfMetrics !== MetricsType.REGULAR_VALUE) {
+              len++;
+            }
+          }
+          if (len) {
             this.$emit('updateStatus', 'metricType', MetricsType.UNKNOWN);
             return;
           }
diff --git a/src/views/components/dashboard/dashboard-item.vue 
b/src/views/components/dashboard/dashboard-item.vue
index 27a9177..57cb87c 100644
--- a/src/views/components/dashboard/dashboard-item.vue
+++ b/src/views/components/dashboard/dashboard-item.vue
@@ -173,8 +173,7 @@ limitations under the License. -->
           this.itemConfig = {};
           return;
         }
-        this.itemConfig = params[0].config;
-
+        this.itemConfig = params[0] && params[0].config;
         const { queryMetricType } = this.itemConfig;
         let data = params;
         if (queryMetricType === QueryTypes.ReadMetricsValue) {
diff --git a/src/views/components/dashboard/tool-bar/tool-bar.vue 
b/src/views/components/dashboard/tool-bar/tool-bar.vue
index 8b2eab0..7105da3 100644
--- a/src/views/components/dashboard/tool-bar/tool-bar.vue
+++ b/src/views/components/dashboard/tool-bar/tool-bar.vue
@@ -152,13 +152,7 @@ limitations under the License. -->
     private dialogAttributesVisible: boolean = false;
     private dashboardType = DASHBOARDTYPE;
     private pageEventsType = PageEventsType;
-    get lastKey() {
-      const current = 
this.rocketComps.tree[this.rocketComps.group].children[this.rocketComps.current].children;
-      if (!current.length) {
-        return 0;
-      }
-      return current[current.length - 1].k;
-    }
+
     private selectService(i: Option) {
       if (!this.rocketComps.enableEvents) {
         this.SELECT_SERVICE({ service: i, duration: this.durationTime });
diff --git a/src/views/components/dashboard/tool-group.vue 
b/src/views/components/dashboard/tool-group.vue
index 67588a3..a30349e 100644
--- a/src/views/components/dashboard/tool-group.vue
+++ b/src/views/components/dashboard/tool-group.vue
@@ -69,7 +69,6 @@ limitations under the License. -->
   export default class ToolGroup extends Vue {
     @Prop() private rocketGlobal: any;
     @Prop() private rocketComps: any;
-    @Mutation('SET_COMPS_TREE') private SET_COMPS_TREE: any;
     @Mutation('DELETE_COMPS_GROUP') private DELETE_COMPS_GROUP: any;
     @Mutation('ADD_COMPS_GROUP') private ADD_COMPS_GROUP: any;
     @Action('MIXHANDLE_CHANGE_GROUP') private MIXHANDLE_CHANGE_GROUP: any;
diff --git a/src/views/components/profile/profile-header.vue 
b/src/views/components/profile/profile-header.vue
index 704de77..3506de0 100644
--- a/src/views/components/profile/profile-header.vue
+++ b/src/views/components/profile/profile-header.vue
@@ -48,7 +48,7 @@ limitations under the License. -->
 <script lang="ts">
   import { Duration, Option } from '@/types/global';
   import { Component, Prop, Vue } from 'vue-property-decorator';
-  import { Mutation } from 'vuex-class';
+  import { Mutation, Action } from 'vuex-class';
   import { CommonSelector } from '../common/index';
   import ProfileTask from './profile-task.vue';
 
@@ -58,6 +58,7 @@ limitations under the License. -->
     @Prop() private newTaskFields: any;
     @Prop() private taskFieldSource: any;
     @Mutation('profileStore/SET_HEADER_SOURCE') private SET_HEADER_SOURCE: any;
+    @Action('profileStore/GET_TASK_LIST') private GET_TASK_LIST: any;
 
     private endpointName: string = '';
     private dialogVisible = false;
@@ -69,7 +70,7 @@ limitations under the License. -->
 
     private searchTask() {
       this.SET_HEADER_SOURCE({ endpointName: this.endpointName });
-      this.$store.dispatch('profileStore/GET_TASK_LIST');
+      this.GET_TASK_LIST();
     }
 
     private created() {
diff --git a/src/views/components/profile/profile-task.vue 
b/src/views/components/profile/profile-task.vue
index 8015b21..72ea7a5 100644
--- a/src/views/components/profile/profile-task.vue
+++ b/src/views/components/profile/profile-task.vue
@@ -76,7 +76,7 @@ limitations under the License. -->
 </template>
 
 <script lang="ts">
-  import { Duration, Option } from '@/types/global';
+  import { Duration } from '@/types/global';
   import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
 
@@ -103,7 +103,7 @@ limitations under the License. -->
     }
 
     private createTask() {
-      this.CREATE_PROFILE_TASK({ startTime: this.time.getTime() }).then((res: 
any) => {
+      this.CREATE_PROFILE_TASK({ startTime: this.time.getTime() }).then((res: 
{ errorReason?: string }) => {
         if (res.errorReason) {
           this.message = res.errorReason;
           return;
diff --git a/src/views/components/profile/profile-trace-detail.vue 
b/src/views/components/profile/profile-trace-detail.vue
index e6ac009..89a4158 100644
--- a/src/views/components/profile/profile-trace-detail.vue
+++ b/src/views/components/profile/profile-trace-detail.vue
@@ -133,11 +133,11 @@ limitations under the License. -->
         segmentId: this.currentSegment.segmentId,
         timeRanges: this.timeRange,
       })
-        .then((result: string) => {
-          this.message = result;
-        })
-        .catch((err: any) => {
-          throw err;
+        .then((result: { tip: string }) => {
+          if (!result) {
+            return;
+          }
+          this.message = result.tip;
         })
         .finally(() => {
           this.loading = false;
diff --git a/src/views/components/profile/task-list.vue 
b/src/views/components/profile/task-list.vue
index c364df0..e68fe12 100644
--- a/src/views/components/profile/task-list.vue
+++ b/src/views/components/profile/task-list.vue
@@ -127,7 +127,6 @@ limitations under the License. -->
 </template>
 
 <script lang="ts">
-  import { Duration, Option } from '@/types/global';
   import { Component, Prop, Vue } from 'vue-property-decorator';
   import { Action, Mutation } from 'vuex-class';
 
@@ -136,8 +135,8 @@ limitations under the License. -->
     @Prop() private taskListSource: any;
     @Prop() private segmentList: any;
     @Prop() private headerSource: any;
-    @Action('profileStore/GET_SEGMENT_LIST') private GET_SEGMENT_LIST: any;
     @Mutation('profileStore/SET_CURRENT_SEGMENT') private SET_CURRENT_SEGMENT: 
any;
+    @Action('profileStore/GET_SEGMENT_LIST') private GET_SEGMENT_LIST: any;
     @Action('profileStore/GET_SEGMENT_SPANS') private GET_SEGMENT_SPANS: any;
     private selectedKey: string = '';
     private selectedTask: any = {};
diff --git a/src/views/components/topology/topo-service-metrics.vue 
b/src/views/components/topology/topo-service-metrics.vue
index 292cb51..e34e7e5 100644
--- a/src/views/components/topology/topo-service-metrics.vue
+++ b/src/views/components/topology/topo-service-metrics.vue
@@ -60,7 +60,7 @@ limitations under the License. -->
     private default = DEFAULT;
     private type: string = '';
 
-    private beforeMount() {
+    private mounted() {
       this.type = TopologyType.TOPOLOGY_SERVICE;
       this.height = document.body.clientHeight - 230;
       this.setServiceTemplates();
diff --git a/src/views/components/topology/topo-services.vue 
b/src/views/components/topology/topo-services.vue
index 3071f80..5e67803 100644
--- a/src/views/components/topology/topo-services.vue
+++ b/src/views/components/topology/topo-services.vue
@@ -36,6 +36,7 @@ limitations under the License. -->
     private service = { key: '', label: 'All services' };
     private groups = [{ key: '', label: 'All groups' }];
     private group = { key: '', label: 'All groups' };
+    private showServiceErrors: boolean = false;
 
     private created() {
       this.fetchData(true);
diff --git a/src/views/components/trace/trace-search.vue 
b/src/views/components/trace/trace-search.vue
index 1882460..5514353 100644
--- a/src/views/components/trace/trace-search.vue
+++ b/src/views/components/trace/trace-search.vue
@@ -140,24 +140,26 @@ limitations under the License. -->
       this.time = [this.rocketbotGlobal.durationRow.start, 
this.rocketbotGlobal.durationRow.end];
     }
     private mounted() {
-      this.GET_SERVICES({ duration: this.durationTime })
-        .then(() => {
-          if (this.serviceName) {
-            for (const s of this.rocketTrace.services) {
-              if (s.label === this.serviceName) {
-                this.service = s;
-                break;
-              }
+      this.GET_SERVICES({ duration: this.durationTime }).then(() => {
+        if (this.serviceName) {
+          for (const s of this.rocketTrace.services) {
+            if (s.label === this.serviceName) {
+              this.service = s;
+              break;
             }
           }
-          this.getTraceList();
-          if (this.service && this.service.key) {
-            this.GET_INSTANCES({
-              duration: this.durationTime,
-              serviceId: this.service.key,
-            });
-          }
-        });
+        }
+        this.getTraceList();
+        if (this.service && this.service.key) {
+          this.getInstance();
+        }
+      });
+    }
+    private getInstance(serviceId?: string) {
+      this.GET_INSTANCES({
+        duration: this.durationTime,
+        serviceId: serviceId || this.service.key,
+      });
     }
     private globalTimeFormat(time: Date[]) {
       const step = 'SECOND';
@@ -180,21 +182,18 @@ limitations under the License. -->
         this.SET_ENDPOINTS([]);
         return;
       }
-      this.GET_INSTANCES({ duration: this.durationTime, serviceId: i.key });
+      this.getInstance(i.key);
       this.SET_ENDPOINTS([]);
-      this.GET_ITEM_ENDPOINTS({
-        serviceId: i.key,
-        keyword: '',
-        duration: this.durationTime,
-      });
+      this.getItemEndpoints(i.key, '');
     }
     private searchEndpoint(search: string) {
+      this.getItemEndpoints(this.service.key, search);
+    }
+    private getItemEndpoints(serviceId: string, keyword?: string) {
       this.GET_ITEM_ENDPOINTS({
-        serviceId: this.service.key,
-        keyword: search,
+        serviceId,
+        keyword,
         duration: this.durationTime,
-      }).then((endpoints: Array<{ key: string; label: string }>) => {
-        this.SET_ENDPOINTS(endpoints);
       });
     }
     private chooseStatus(i: Option) {
diff --git a/src/views/containers/dashboard.vue 
b/src/views/containers/dashboard.vue
index b53ecec..b973bdc 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -83,6 +83,7 @@ limitations under the License. -->
     @Mutation('SET_TEMPLATES') private SET_TEMPLATES: any;
 
     private isRouterAlive: boolean = true;
+    private templatesErrors: boolean = false;
     public reload(): void {
       this.isRouterAlive = false;
       this.$nextTick(() => {
@@ -105,13 +106,13 @@ limitations under the License. -->
       });
     }
     private beforeMount() {
-      this.GET_ALL_TEMPLATES().then((allTemplate: ITemplate[]) => {
-        const dashboardTemplate = allTemplate.filter((item: ITemplate) => 
item.type === 'DASHBOARD');
+      this.GET_ALL_TEMPLATES().then((templateResp: ITemplate[]) => {
+        const dashboardTemplate = templateResp.filter((item: ITemplate) => 
item.type === 'DASHBOARD');
         const templatesConfig = dashboardTemplate.map((item: ITemplate) => 
JSON.parse(item.configuration)).flat(1);
         this.SET_TEMPLATES(templatesConfig);
         if (window.localStorage.getItem('version') !== '8.0') {
           window.localStorage.removeItem('dashboard');
-          const template = allTemplate.filter((item: ITemplate) => item.type 
=== 'DASHBOARD' && item.activated);
+          const template = templateResp.filter((item: ITemplate) => item.type 
=== 'DASHBOARD' && item.activated);
           const templatesConfiguration = template.map((item: ITemplate) => 
JSON.parse(item.configuration)).flat(1);
           this.SET_COMPS_TREE(templatesConfiguration || []);
           window.localStorage.setItem('version', '8.0');
diff --git a/src/views/containers/index.vue b/src/views/containers/index.vue
index fa6e51d..8d6fe9c 100644
--- a/src/views/containers/index.vue
+++ b/src/views/containers/index.vue
@@ -17,21 +17,27 @@ limitations under the License. -->
     <RkHeader @reloadFooter="reloadFooter" />
     <router-view></router-view>
     <RkFooter ref="footer" />
+    <AlertsContent />
   </div>
 </template>
 
 <script lang="ts">
   import { Component, Vue } from 'vue-property-decorator';
-  import RkHeader from '@/components/rk-header.vue';
-  import RkFooter from '@/components/rk-footer.vue';
+  import { State } from 'vuex-class';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import RkHeader from '@/views/components/common/rk-header.vue';
+  import RkFooter from '@/views/components/common/rk-footer.vue';
+  import AlertsContent from '@/views/components/common/alerts-content.vue';
 
   @Component({
     components: {
       RkHeader,
       RkFooter,
+      AlertsContent,
     },
   })
   export default class RouterIndex extends Vue {
+    @State('rocketOption') private stateDashboardOption!: optionState;
     private isRouterAlive: boolean = true;
     public reloadFooter(timeArray: Date[]): void {
       const footer: any = this.$refs.footer;
diff --git a/src/views/containers/profile.vue b/src/views/containers/profile.vue
index d341901..c032ed7 100644
--- a/src/views/containers/profile.vue
+++ b/src/views/containers/profile.vue
@@ -39,8 +39,8 @@ limitations under the License. -->
 
 <script lang="ts">
   import { Component, Vue } from 'vue-property-decorator';
-  import { State, Getter, Mutation } from 'vuex-class';
-  import { DurationTime } from '@/types/global';
+  import { State, Getter } from 'vuex-class';
+  import { State as profileState } from 
'@/store/modules/profile/profile-store';
   import ProfileHeader from '@/views/components/profile/profile-header.vue';
   import ProfileTaskList from '@/views/components/profile/task-list.vue';
   import ProfileTraceDetail from 
'@/views/components/profile/profile-trace-detail.vue';
@@ -49,7 +49,7 @@ limitations under the License. -->
     components: { ProfileHeader, ProfileTaskList, ProfileTraceDetail },
   })
   export default class Profile extends Vue {
-    @State('profileStore') private profile: any;
+    @State('profileStore') private profile!: profileState;
     @Getter('durationTime') private durationTime: any;
 
     private beforeMount() {
diff --git a/src/views/containers/topology/alarm/alarm-tool.vue 
b/src/views/containers/topology/alarm/alarm-tool.vue
index 19dd5d6..5bdb556 100644
--- a/src/views/containers/topology/alarm/alarm-tool.vue
+++ b/src/views/containers/topology/alarm/alarm-tool.vue
@@ -46,6 +46,8 @@ limitations under the License. -->
     @Prop() private total!: number;
     @Prop() private keyword!: string;
     private pageNum: number = 1;
+    private alarmErrors: boolean = false;
+    private alarmErrorsDesc: string = '';
     private handleFetch(pageNum: number) {
       this.pageNum = pageNum;
       this.GET_ALARM({
diff --git a/src/views/containers/topology/endpoint-dependency/index.vue 
b/src/views/containers/topology/endpoint-dependency/index.vue
index c064fad..80dd4b7 100644
--- a/src/views/containers/topology/endpoint-dependency/index.vue
+++ b/src/views/containers/topology/endpoint-dependency/index.vue
@@ -37,7 +37,7 @@ limitations under the License. -->
 
 <script lang="ts">
   import Vue from 'vue';
-  import { Component, Watch, Prop } from 'vue-property-decorator';
+  import { Component, Prop } from 'vue-property-decorator';
   import { Action, Getter, State, Mutation } from 'vuex-class';
   import ToolBarSelect from 
'@/views/components/dashboard/tool-bar/tool-bar-select.vue';
   import ToolBarEndpointSelect from 
'@/views/components/dashboard/tool-bar/tool-bar-endpoint-select.vue';
diff --git a/src/views/containers/trace.vue b/src/views/containers/trace.vue
index 16d7842..207e42a 100644
--- a/src/views/containers/trace.vue
+++ b/src/views/containers/trace.vue
@@ -25,7 +25,7 @@ limitations under the License. -->
 <script lang="ts">
   import { Option } from '@/types/global';
   import { Component, Vue, Prop } from 'vue-property-decorator';
-  import { State, Action, Mutation } from 'vuex-class';
+  import { State, Mutation } 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';

Reply via email to