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 ca6c129  Feat: Support topology group (#263)
ca6c129 is described below

commit ca6c1290aa9e7ac5a25a1a450020847336cc6a5e
Author: Allen Wang <[email protected]>
AuthorDate: Mon Mar 9 21:16:41 2020 +0800

    Feat: Support topology group (#263)
    
    Co-authored-by: Wang Yao <[email protected]>
---
 src/components/rk-button.vue                       |  12 ++-
 src/store/index.ts                                 |  19 ++--
 src/store/modules/topology/group/index.ts          | 108 +++++++++++++++++++++
 .../store/modules/topology/group/mutation-types.ts |  28 ++----
 src/store/modules/topology/index.ts                |  42 ++++++++
 src/store/mutation-types.ts                        |   1 +
 vue.config.js => src/utils/genID.ts                |  26 ++---
 .../components/topology/chart/utils/linkElement.js |   2 +-
 .../topology/topo-group/create-group.vue}          |  55 ++++++-----
 .../components/topology/topo-group/group-item.vue  |  88 +++++++++++++++++
 src/views/components/topology/topo-group/index.vue | 100 +++++++++++++++++++
 src/views/containers/dashboard.vue                 |   2 +-
 src/views/containers/topology/topology.vue         |   5 +-
 vue.config.js                                      |   2 +-
 14 files changed, 405 insertions(+), 85 deletions(-)

diff --git a/src/components/rk-button.vue b/src/components/rk-button.vue
index 3ca0942..f824acd 100644
--- a/src/components/rk-button.vue
+++ b/src/components/rk-button.vue
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 <template>
-  <a class="rk-btn" :class="{ size, ghost: ghost }" @click="$emit('click')">
-    <svg class="icon"><use xlink:href="#chevron-left"></use></svg>
+  <a class="rk-btn" :class="{ size, ghost: ghost }" 
@click.stop="$emit('click')">
+    <svg v-if="icon" class="icon"><use :xlink:href="`#${icon}`"></use></svg>
+    <slot/>
   </a>
 </template>
 <script lang="ts">
@@ -26,17 +27,22 @@
   @Component
   export default class RkBtn extends Vue {
     @Prop({ default: '' }) private size!: string;
+    @Prop({ default: '' }) private icon!: string;
     @Prop({ default: false }) private ghost!: boolean;
   }
 </script>
 <style lang="scss">
   .rk-btn {
+    display: inline-block;
     line-height: 26px;
     padding: 0 7px;
     background-color: #448dfe;
     border-radius: 4px;
     color: #fff;
     transition: background-color 0.3s;
+    .icon{
+      margin-top: -2px;
+    }
     &.sm {
       line-height: 24px;
     }
@@ -44,7 +50,7 @@
       line-height: 30px;
     }
     &.ghost {
-      background-color: #555b6b66;
+      background-color: transparent;
     }
     &:hover {
       background-color: #357de9;
diff --git a/src/store/index.ts b/src/store/index.ts
index b9ca56a..63f6b09 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -18,21 +18,14 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import rocketbot, { State as RocketbotState } from './modules/global';
-import rocketOption, {
-  State as DashboardOptionState,
-} from './modules/dashboard/modules/dashboard-option';
-import rocketData, {
-  State as DashboardDataState,
-} from './modules/dashboard/modules/dashboard-data';
-import rocketDashboard, {
-  State as DashboardState,
-} from './modules/dashboard/source';
+import rocketOption, { State as DashboardOptionState } from 
'./modules/dashboard/modules/dashboard-option';
+import rocketData, { State as DashboardDataState } from 
'./modules/dashboard/modules/dashboard-data';
+import rocketDashboard, { State as DashboardState } from 
'./modules/dashboard/source';
 import rocketTopo, { State as TopoState } from '@/store/modules/topology';
+import rocketTopoGroup, { State as TopoGroupState } from 
'@/store/modules/topology/group';
 import rocketTrace, { State as TraceState } from '@/store/modules/trace';
 import rocketAlarm, { State as AlarmState } from '@/store/modules/alarm';
-import comparisonStore, {
-  State as ComparisonState,
-} from '@/store/modules/comparison/comparison-store';
+import comparisonStore, { State as ComparisonState } from 
'@/store/modules/comparison/comparison-store';
 Vue.use(Vuex);
 
 export interface State {
@@ -41,6 +34,7 @@ export interface State {
   rocketData: DashboardDataState;
   rocketDashboard: DashboardState;
   rocketTopo: TopoState;
+  rocketTopoGroup: TopoGroupState;
   rocketTrace: TraceState;
   rocketAlarm: AlarmState;
   comparisonStore: ComparisonState;
@@ -53,6 +47,7 @@ export default new Vuex.Store({
     rocketData,
     rocketDashboard,
     rocketTopo,
+    rocketTopoGroup,
     rocketTrace,
     rocketAlarm,
     comparisonStore,
diff --git a/src/store/modules/topology/group/index.ts 
b/src/store/modules/topology/group/index.ts
new file mode 100644
index 0000000..8246ecd
--- /dev/null
+++ b/src/store/modules/topology/group/index.ts
@@ -0,0 +1,108 @@
+/**
+ * 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 } from 'vuex';
+import { genID } from '@/utils/genID';
+import * as types from './mutation-types';
+
+export interface Group {
+    id: string;
+    name: string;
+    services: string[];
+}
+export interface State {
+  groupId: string;
+  groups: Group[];
+}
+
+const initState: State = {
+  groupId: 'all',
+  groups: [],
+};
+
+// getters
+const getters = {
+  services(state: State) {
+    if (state.groupId === 'all' ) { return []; }
+    const index = state.groups.findIndex((i: Group) => i.id === state.groupId);
+    return state.groups[index].services;
+  },
+};
+
+// mutations
+const mutations: MutationTree<State> = {
+  [types.INIT_GROUPS](state: State): void {
+    const storage = localStorage.getItem('topology-groups');
+    if (storage) {
+      state.groups = JSON.parse(storage);
+    } else {
+      state.groups = [];
+    }
+  },
+  [types.SAVE_GROUPS](state: State): void {
+    localStorage.setItem('topology-groups', JSON.stringify(state.groups));
+  },
+  [types.CREATE_GROUP](state: State, name: string): void {
+    state.groups.push({
+      id: `${genID(5)}`,
+      name, services: [],
+    });
+    localStorage.setItem('topology-groups', JSON.stringify(state.groups));
+  },
+  [types.DELETE_GROUP](state: State, id: string): void {
+    const index = state.groups.findIndex((i: Group) => i.id === id);
+    if (index === -1) { return; }
+    state.groups.splice(index, 1);
+    state.groupId = 'all';
+    localStorage.setItem('topology-groups', JSON.stringify(state.groups));
+  },
+  [types.SELECT_GROUP](state: State, id: string): void {
+    state.groupId = id;
+  },
+  [types.ADD_GROUP_SERVICE](state: State, data: {id: string, serviceId: 
string}): void {
+    const groupIndex = state.groups.findIndex((i: Group) => i.id === data.id);
+    if (groupIndex === -1) { return; }
+    const services =  state.groups[groupIndex].services;
+    const index = services.findIndex((i) => i === data.serviceId);
+    if (index === -1) {
+      services.push(data.serviceId);
+    }
+    localStorage.setItem('topology-groups', JSON.stringify(state.groups));
+  },
+  [types.DELETE_GROUP_SERVICE](state: State, data: {id: string, serviceId: 
string}): void {
+    const groupIndex = state.groups.findIndex((i: Group) => i.id === data.id);
+    if (groupIndex === -1) { return; }
+    const services =  state.groups[groupIndex].services;
+    const index = services.findIndex((i) => i === data.serviceId);
+    if (index !== -1) {
+      services.splice(index, 1);
+    }
+    localStorage.setItem('topology-groups', JSON.stringify(state.groups));
+  },
+};
+
+// actions
+const actions: ActionTree<State, any> = {
+};
+
+export default {
+  namespaced: true,
+  state: initState,
+  getters,
+  actions,
+  mutations,
+};
diff --git a/vue.config.js b/src/store/modules/topology/group/mutation-types.ts
similarity index 64%
copy from vue.config.js
copy to src/store/modules/topology/group/mutation-types.ts
index 38a3e0c..3dde160 100644
--- a/vue.config.js
+++ b/src/store/modules/topology/group/mutation-types.ts
@@ -15,23 +15,11 @@
  * limitations under the License.
  */
 
-module.exports = {
-  devServer: {
-    proxy: {
-      '/graphql': {
-        target: `${process.env.SW_PROXY_TARGET || 
"http://122.112.182.72:8080/"}`,
-        changeOrigin: true,
-      },
-    },
-  },
-  chainWebpack: config => {
-    const svgRule = config.module.rule('svg');
-    svgRule.uses.clear();
-    svgRule
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
-      .options({
-        symbolId: '[name]',
-      });
-  },
-};
+export const INIT_GROUPS = 'INIT_GROUPS';
+export const SAVE_GROUPS = 'SAVE_GROUPS';
+export const CREATE_GROUP = 'CREATE_GROUP';
+export const DELETE_GROUP = 'DELETE_GROUP';
+export const SELECT_GROUP = 'SELECT_GROUP';
+export const ADD_GROUP_SERVICE = 'ADD_GROUP_SERVICE';
+export const DELETE_GROUP_SERVICE = 'DELETE_GROUP_SERVICE';
+export const GET_GROUPS = 'GET_GROUPS';
diff --git a/src/store/modules/topology/index.ts 
b/src/store/modules/topology/index.ts
index c316c70..7aa078c 100644
--- a/src/store/modules/topology/index.ts
+++ b/src/store/modules/topology/index.ts
@@ -51,6 +51,8 @@ export interface State {
   callback: any;
   calls: Call[];
   nodes: Node[];
+  _calls: Call[];
+  _nodes: Node[];
   detectPoints: string[];
   selectedServiceCall: Call | null;
   currentNode: any;
@@ -78,6 +80,8 @@ const initState: State = {
   selectedServiceCall: null,
   calls: [],
   nodes: [],
+  _calls: [],
+  _nodes: [],
   currentNode: {},
   current: {
     key: 'default',
@@ -121,6 +125,10 @@ const mutations = {
     state.calls = data.calls;
     state.nodes = data.nodes;
   },
+  [types.SET_TOPO_COPY](state: State, data: any) {
+    state._calls = data.calls;
+    state._nodes = data.nodes;
+  },
   [types.SET_SELECTED_CALL](state: State, data: any) {
     state.selectedServiceCall = data;
   },
@@ -178,8 +186,36 @@ const mutations = {
 
 // actions
 const actions: ActionTree<State, any> = {
+  FILTER_TOPO(context: { commit: Commit; state: State }, params: {services: 
string[], group: string}) {
+    const tempCalls = [...context.state._calls];
+    const tempNodes = [...context.state._nodes];
+    if (params.group === 'all') {
+      context.commit(types.SET_TOPO, { calls: context.state._calls, nodes: 
context.state._nodes });
+      return;
+    }
+    const nodeInCalls: string[] = [];
+    const resultNodes: Node[] = [];
+    const resultCalls: Call[] = [];
+    tempCalls.forEach((call: any) => {
+      if (
+        params.services.some((i: string) => call.source.id === i) ||
+        params.services.some((i: string) => call.target.id === i)) {
+          nodeInCalls.push(call.source.id);
+          nodeInCalls.push(call.target.id);
+          resultCalls.push(call);
+      }
+    });
+    const setNodes: string[] = Array.from(new Set(nodeInCalls));
+    tempNodes.forEach((node: any) => {
+      if (setNodes.some((i: string) => node.id === i )) {
+        resultNodes.push(node);
+      }
+    });
+    context.commit(types.SET_TOPO, { calls: resultCalls, nodes: resultNodes });
+  },
   CLEAR_TOPO(context: { commit: Commit; state: State }) {
     context.commit(types.SET_TOPO, { calls: [], nodes: [] });
+    context.commit(types.SET_TOPO_COPY, { calls: [], nodes: [] });
   },
   CLEAR_TOPO_INFO(context: { commit: Commit; state: State }) {
     context.commit(types.SET_TOPO_RELATION, {});
@@ -246,6 +282,7 @@ const actions: ActionTree<State, any> = {
           .then((info: AxiosResponse) => {
             const resInfo = info.data.data;
             if (!resInfo.sla) {
+              context.commit(types.SET_TOPO_COPY, { calls, nodes });
               return context.commit(types.SET_TOPO, { calls, nodes });
             }
             for (let i = 0; i < resInfo.sla.values.length; i += 1) {
@@ -253,6 +290,7 @@ const actions: ActionTree<State, any> = {
                 if (nodes[j].id === resInfo.sla.values[i].id) {
                   nodes[j] = {
                     ...nodes[j],
+                    isGroupActive: true,
                     sla: resInfo.sla.values[i].value
                       ? resInfo.sla.values[i].value / 100
                       : -1,
@@ -267,6 +305,7 @@ const actions: ActionTree<State, any> = {
               }
             }
             if (!resInfo.cpmC) {
+              context.commit(types.SET_TOPO_COPY, { calls, nodes });
               return context.commit(types.SET_TOPO, { calls, nodes });
             }
             for (let i = 0; i < resInfo.cpmC.values.length; i += 1) {
@@ -274,6 +313,7 @@ const actions: ActionTree<State, any> = {
                 if (calls[j].id === resInfo.cpmC.values[i].id) {
                   calls[j] = {
                     ...calls[j],
+                    isGroupActive: true,
                     cpm: resInfo.cpmC.values[i]
                       ? resInfo.cpmC.values[i].value
                       : '',
@@ -285,6 +325,7 @@ const actions: ActionTree<State, any> = {
               }
             }
             if (!resInfo.cpmS) {
+              context.commit(types.SET_TOPO_COPY, { calls, nodes });
               return context.commit(types.SET_TOPO, { calls, nodes });
             }
             for (let i = 0; i < resInfo.cpmS.values.length; i += 1) {
@@ -302,6 +343,7 @@ const actions: ActionTree<State, any> = {
                 }
               }
             }
+            context.commit(types.SET_TOPO_COPY, { calls, nodes });
             context.commit(types.SET_TOPO, { calls, nodes });
           });
       });
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index 58efb0e..594c966 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -81,6 +81,7 @@ export const SET_MODE_STATUS = 'SET_MODE_STATUS';
 export const SET_HONEYCOMB_NODE = 'SET_HONEYCOMB_NODE';
 export const SET_SHOW_DIALOG = 'SET_SHOW_DIALOG';
 export const SET_INSTANCE_DEPENDENCY = 'SET_INSTANCE_DEPENDENCY';
+export const SET_TOPO_COPY = 'SET_TOPO_COPY';
 
 // comparison
 export const SET_CHARTVAL = 'SET_CHARTVAL';
diff --git a/vue.config.js b/src/utils/genID.ts
old mode 100644
new mode 100755
similarity index 64%
copy from vue.config.js
copy to src/utils/genID.ts
index 38a3e0c..c8544f2
--- a/vue.config.js
+++ b/src/utils/genID.ts
@@ -14,24 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-module.exports = {
-  devServer: {
-    proxy: {
-      '/graphql': {
-        target: `${process.env.SW_PROXY_TARGET || 
"http://122.112.182.72:8080/"}`,
-        changeOrigin: true,
-      },
-    },
-  },
-  chainWebpack: config => {
-    const svgRule = config.module.rule('svg');
-    svgRule.uses.clear();
-    svgRule
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
-      .options({
-        symbolId: '[name]',
-      });
-  },
+export const genID = (length: number) => {
+  return Number(
+    Math.random()
+      .toString()
+      .substr(3, length) + Date.now(),
+  ).toString(36);
 };
diff --git a/src/views/components/topology/chart/utils/linkElement.js 
b/src/views/components/topology/chart/utils/linkElement.js
index fba197d..783033e 100644
--- a/src/views/components/topology/chart/utils/linkElement.js
+++ b/src/views/components/topology/chart/utils/linkElement.js
@@ -17,7 +17,7 @@
 export const linkElement = (graph) => {
   const linkEnter = graph
     .append('path').attr('class', 'topo-line')
-    .attr('stroke', d => d.cpm ? '#217EF25f' : '#6a6d7777');;
+    .attr('stroke', d => d.cpm ? '#217EF25f' : '#6a6d7777');
   return linkEnter;
 }
 export const anchorElement = (graph, funcs, tip) => {
diff --git a/src/components/rk-button.vue 
b/src/views/components/topology/topo-group/create-group.vue
similarity index 50%
copy from src/components/rk-button.vue
copy to src/views/components/topology/topo-group/create-group.vue
index 3ca0942..d55adc2 100644
--- a/src/components/rk-button.vue
+++ b/src/views/components/topology/topo-group/create-group.vue
@@ -15,39 +15,42 @@
  * limitations under the License.
  */
 <template>
-  <a class="rk-btn" :class="{ size, ghost: ghost }" @click="$emit('click')">
-    <svg class="icon"><use xlink:href="#chevron-left"></use></svg>
-  </a>
+  <div>
+    <div v-if="create">
+      <input class="group-create-input mr-5" placeholder="Group Name" 
v-model="name"/>
+      <RkButton class="mr-5" @click="handleCreateGroup">Confirm</RkButton>
+      <RkButton @click="create = false">Cancel</RkButton>
+    </div>
+    <RkButton v-else icon="add" @click="create = true">Create group</RkButton>
+  </div>
 </template>
 <script lang="ts">
-  import Vue from 'vue';
-  import { Component, Prop } from 'vue-property-decorator';
+  import { Component, Vue } from 'vue-property-decorator';
+  import { Mutation } from 'vuex-class';
 
-  @Component
-  export default class RkBtn extends Vue {
-    @Prop({ default: '' }) private size!: string;
-    @Prop({ default: false }) private ghost!: boolean;
+  @Component({
+    components: {},
+  })
+  export default class TopoGroupCreate extends Vue {
+    @Mutation('rocketTopoGroup/CREATE_GROUP') private CREATE_GROUP: any;
+    private name: string = '';
+    private create: boolean = false;
+
+    private handleCreateGroup() {
+      this.CREATE_GROUP(this.name);
+      this.name = '';
+      this.create = false;
+    }
   }
 </script>
 <style lang="scss">
-  .rk-btn {
+  .group-create-input {
+    border: none;
+    outline: none;
     line-height: 26px;
-    padding: 0 7px;
-    background-color: #448dfe;
+    padding: 0px 8px;
+    color: #ddd;
+    background-color: #2b3037;
     border-radius: 4px;
-    color: #fff;
-    transition: background-color 0.3s;
-    &.sm {
-      line-height: 24px;
-    }
-    &.lg {
-      line-height: 30px;
-    }
-    &.ghost {
-      background-color: #555b6b66;
-    }
-    &:hover {
-      background-color: #357de9;
-    }
   }
 </style>
diff --git a/src/views/components/topology/topo-group/group-item.vue 
b/src/views/components/topology/topo-group/group-item.vue
new file mode 100644
index 0000000..1a98dbc
--- /dev/null
+++ b/src/views/components/topology/topo-group/group-item.vue
@@ -0,0 +1,88 @@
+/**
+ * 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="group-wrapper">
+    <div class="group-item ell" :class="{'active': active}" 
@click="$emit('select', data.id)">
+      <RkButton icon="close" size="sm" class="mr-5" :ghost="true" 
@click="$emit('delete')"/>
+      <span class="mr-5">{{data.name}}</span>
+    </div>
+    <div class="group-services">
+      <div class="ell" v-for="i in servicesMap" :key="i.key">
+        <input type="checkbox" @click="(e) => {
+          !e.target.checked ? DELETE_GROUP_SERVICE({id: data.id, 
serviceId:i.key}) : ADD_GROUP_SERVICE({id: data.id, serviceId:i.key})
+          $emit('select', data.id)
+        }" :checked="data.services.some(service => service === i.key)">
+        <span>{{i.label}}</span>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { Component, Vue, Watch, Prop } from 'vue-property-decorator';
+  import { Action, Getter, Mutation, State } from 'vuex-class';
+  import { State as TopoGroupState } from '@/store/modules/topology/group';
+  @Component
+  export default class TopoGroupItem extends Vue {
+    @Prop() private active!: boolean;
+    @Prop() private data!: any;
+    @Prop() private servicesMap!: any;
+    @Mutation('rocketTopoGroup/ADD_GROUP_SERVICE') private ADD_GROUP_SERVICE: 
any;
+    @Mutation('rocketTopoGroup/DELETE_GROUP_SERVICE') private 
DELETE_GROUP_SERVICE: any;
+  }
+</script>
+<style lang="scss">
+  .topo-group{
+    .group-wrapper{
+      position: relative;
+      margin-bottom: 5px;
+      &:hover{
+        .group-services{
+          display: block;
+        }
+      }
+    }
+    .group-services{
+      display: none;
+      position: absolute;
+      background-color: #252a2f;
+      padding: 10px;
+      left: 110px;
+      bottom: 0;
+      color: #ccc;
+      border-radius: 4px;
+    }
+    .group-item{
+      position: relative;
+      user-select: none;
+      cursor: pointer;
+      background: #252a2f66;
+      color: #ccc;
+      height: 26px;
+      width: 110px;
+      line-height: 26px;
+      padding-right: 10px;
+      border-radius: 4px;
+      &:hover,&.active{
+        color: #fff;
+        background-color: #252a2f;
+      }
+      &.default{
+        padding-left: 10px;
+      }
+    }
+  }
+</style>
diff --git a/src/views/components/topology/topo-group/index.vue 
b/src/views/components/topology/topo-group/index.vue
new file mode 100644
index 0000000..c0052ac
--- /dev/null
+++ b/src/views/components/topology/topo-group/index.vue
@@ -0,0 +1,100 @@
+/**
+ * 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="topo-group">
+    <div v-for="i in rocketTopoGroup.groups">
+      <GroupItem
+      :servicesMap="servicesMap"
+      :active="rocketTopoGroup.groupId === i.id"
+      :key="i.id"
+      @delete="handleDeleteGroup(i.id)"
+      @select="handleSelectGroup"
+      :data="i"/>
+    </div>
+    <div>
+      <div class="group-item default mb-10" @click="handleSelectGroup('all')" 
:class="{'active': rocketTopoGroup.groupId === 
'all'}"><span>Default</span></div>
+    </div>
+    <CreateGroup/>
+  </div>
+</template>
+<script lang="ts">
+  import topo, { State as topoState } from '@/store/modules/topology';
+  import { Component, Vue, Watch } from 'vue-property-decorator';
+  import { Action, Getter, Mutation, State } from 'vuex-class';
+  import { State as TopoGroupState } from '@/store/modules/topology/group';
+  import CreateGroup from './create-group.vue';
+  import GroupItem from './group-item.vue';
+  import Axios, { AxiosResponse } from 'axios';
+  
+  @Component({
+    components: {
+      CreateGroup,
+      GroupItem,
+    },
+  })
+  export default class TopoGroup extends Vue {
+    @State('rocketTopo') private stateTopo!: topoState;
+    @State('rocketTopoGroup') private rocketTopoGroup!: TopoGroupState;
+    @Getter('durationTime') private durationTime: any;
+    @Getter('rocketTopoGroup/services') private services: any;
+    @Mutation('rocketTopoGroup/INIT_GROUPS') private INIT_GROUPS: any;
+    @Mutation('rocketTopoGroup/DELETE_GROUP') private DELETE_GROUP: any;
+    @Mutation('rocketTopoGroup/SELECT_GROUP') private SELECT_GROUP: any;
+    @Action('rocketTopo/FILTER_TOPO') private FILTER_TOPO: any;
+  
+    private servicesMap = [];
+    private handleDeleteGroup(id: string) {
+      const r = confirm('Do you want to delete this group!');
+      if (r === true) {
+         this.DELETE_GROUP(id);
+      }
+    }
+    private handleSelectGroup(id: string) {
+      this.SELECT_GROUP(id);
+      this.FILTER_TOPO({ services: this.services, group: id });
+    }
+    private fetchData() {
+      Axios.post('/graphql', {
+        query: `
+      query queryServices($duration: Duration!) {
+        services: getAllServices(duration: $duration) {
+          key: id
+          label: name
+        }
+      }`,
+        variables: {
+          duration: this.durationTime,
+        },
+      }).then((res: AxiosResponse) => {
+        this.servicesMap = res.data.data.services
+          ? res.data.data.services
+          : [];
+      });
+    }
+    private created() {
+      this.INIT_GROUPS();
+      this.fetchData();
+    }
+  }
+</script>
+<style lang="scss">
+  .topo-group{
+    position: absolute;
+    bottom: 10px;
+    left: 10px;
+  }
+</style>
diff --git a/src/views/containers/dashboard.vue 
b/src/views/containers/dashboard.vue
index e288435..33994e3 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 <template>
-  <div class="flex-v wrapper" style="flex-grow:1;height: 100%;">
+  <div class="flex-v wrapper" style="flex-grow:1;height: 100%;overflow:hidden">
     <ToolGroup :rocketGlobal="rocketGlobal" :rocketComps="rocketComps" />
     <ToolBar
       :rocketGlobal="rocketGlobal"
diff --git a/src/views/containers/topology/topology.vue 
b/src/views/containers/topology/topology.vue
index 912d663..53b6ff0 100644
--- a/src/views/containers/topology/topology.vue
+++ b/src/views/containers/topology/topology.vue
@@ -16,8 +16,9 @@
  */
 <template>
   <div class="rk-topo">
-    <TopoAside />
     <Topo :current="current" @setDialog="(type) => dialog = type" 
@setCurrent="setCurrent" :nodes="stateTopo.nodes" :links="stateTopo.calls"/>
+    <TopoAside />
+    <TopoGroup />
     <rk-sidebox :show="dialog.length" @update:show="dialog = ''" :fixed="true" 
width="80%">
       <window-endpoint
         v-if="dialog === 'endpoint'"
@@ -48,12 +49,14 @@
   import WindowAlarm from '@/views/containers/topology/alarm/index.vue';
   import Topo from '../../components/topology/chart/topo.vue';
   import TopoAside from '../../components/topology/topo-aside.vue';
+  import TopoGroup from '../../components/topology/topo-group/index.vue';
   import { State as topoState } from '@/store/modules/topology';
 
   @Component({
     components: {
       Topo,
       TopoAside,
+      TopoGroup,
       WindowEndpoint,
       WindowInstance,
       WindowTrace,
diff --git a/vue.config.js b/vue.config.js
index 38a3e0c..5d48c85 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -19,7 +19,7 @@ module.exports = {
   devServer: {
     proxy: {
       '/graphql': {
-        target: `${process.env.SW_PROXY_TARGET || 
"http://122.112.182.72:8080/"}`,
+        target: `${process.env.SW_PROXY_TARGET || "http://127.0.0.1:8080"}`,
         changeOrigin: true,
       },
     },

Reply via email to