Support namespace page (#113)



* ### Motivation
Add related pages about namespace
Namespace contains a large number of policies,  In order to configure these policies, a page is added to update them.

### Modifications
* On the namespaceInfo page, include three tab => overview, topics and policies
* On the overview page, statistics can be seen and bundle can be configured.
* On the policies page, contains configuration of policies
* On the topics page, Including statistical information on all topics under this namespace

### Verifying this change
Add Unit Test For Backend

diff --git a/build.gradle b/build.gradle
index d78f921..723e0e9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -71,6 +71,7 @@
     compile group: 'com.github.pagehelper', name: 'pagehelper-spring-boot-starter', version: pageHelperVersion
     compile group: 'org.mockito', name: 'mockito-core', version: mockitoVersion
     compile group: 'com.google.guava', name: 'guava', version: guavaVersion
+    compile group: 'com.google.code.gson', name: 'gson', version: gsonVersion
     compile group: 'org.apache.pulsar', name: 'pulsar-client', version: pulsarVersion
     compile group: 'org.apache.pulsar', name: 'pulsar-common', version: pulsarVersion
     compile group: 'io.springfox', name: 'springfox-swagger2', version: swagger2Version
diff --git a/front-end/src/api/brokerStats.js b/front-end/src/api/brokerStats.js
new file mode 100644
index 0000000..eb66f1d
--- /dev/null
+++ b/front-end/src/api/brokerStats.js
@@ -0,0 +1,23 @@
+/*
+ * Licensed 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 request from '@/utils/request'
+
+const BASE_URL_V2 = '/admin/v2'
+
+export function fetchBrokerStats() {
+  return request({
+    url: BASE_URL_V2 + `/broker-stats/topics`,
+    method: 'get'
+  })
+}
diff --git a/front-end/src/api/namespaces.js b/front-end/src/api/namespaces.js
index 25ab87b..e1c399a 100644
--- a/front-end/src/api/namespaces.js
+++ b/front-end/src/api/namespaces.js
@@ -13,11 +13,13 @@
  */
 import request from '@/utils/request'
 
+const SPRING_BASE_URL_V2 = '/pulsar-manager/admin/v2'
+
 const BASE_URL_V2 = '/admin/v2'
 
 export function fetchNamespaces(tenant, query) {
   return request({
-    url: BASE_URL_V2 + `/namespaces/${tenant}`,
+    url: SPRING_BASE_URL_V2 + `/namespaces/${tenant}`,
     method: 'get',
     params: { query }
   })
@@ -101,6 +103,14 @@
   })
 }
 
+export function getPersistence(tenantNamespace) {
+  return request({
+    headers: { 'Content-Type': 'application/json' },
+    url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/persistence`,
+    method: 'get'
+  })
+}
+
 export function setPersistence(tenantNamespace, data) {
   return request({
     headers: { 'Content-Type': 'application/json' },
@@ -145,6 +155,14 @@
   })
 }
 
+export function getRetention(tenantNamespace) {
+  return request({
+    headers: { 'Content-Type': 'application/json' },
+    url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/retention`,
+    method: 'get'
+  })
+}
+
 export function setRetention(tenantNamespace, data) {
   return request({
     headers: { 'Content-Type': 'application/json' },
@@ -188,6 +206,24 @@
   })
 }
 
+export function setSubscribeRate(tenantNamespace, data) {
+  return request({
+    headers: { 'Content-Type': 'application/json' },
+    url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/subscribeRate`,
+    method: 'post',
+    data
+  })
+}
+
+export function setSubscriptionDispatchRate(tenantNamespace, data) {
+  return request({
+    headers: { 'Content-Type': 'application/json' },
+    url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/subscriptionDispatchRate`,
+    method: 'post',
+    data
+  })
+}
+
 export function clearBacklog(tenantNamespace) {
   return request({
     headers: { 'Content-Type': 'application/json' },
@@ -308,3 +344,12 @@
     data
   })
 }
+
+export function setSchemaValidationEnforced(tenantNamespace, data) {
+  return request({
+    headers: { 'Content-Type': 'application/json' },
+    url: BASE_URL_V2 + `/namespaces/${tenantNamespace}/schemaValidationEnforced`,
+    method: 'post',
+    data
+  })
+}
diff --git a/front-end/src/api/topics.js b/front-end/src/api/topics.js
index 1a88ecc..caa6f59 100644
--- a/front-end/src/api/topics.js
+++ b/front-end/src/api/topics.js
@@ -13,6 +13,8 @@
  */
 import request from '@/utils/request'
 
+const SPRING_BASE_URL_V2 = '/pulsar-manager/admin/v2'
+
 const BASE_URL_V2 = '/admin/v2'
 
 export function fetchTopics(tenant, namespace, query) {
@@ -23,6 +25,14 @@
   })
 }
 
+export function fetchTopicsByPulsarManager(tenant, namespace, query) {
+  return request({
+    url: SPRING_BASE_URL_V2 + `/topics/${tenant}/${namespace}`,
+    method: 'get',
+    params: { query }
+  })
+}
+
 export function fetchPersistentPartitonsTopics(tenant, namespace) {
   return request({
     url: BASE_URL_V2 + `/persistent/${tenant}/${namespace}/partitioned`,
diff --git a/front-end/src/components/MDinput/index.vue b/front-end/src/components/MDinput/index.vue
new file mode 100644
index 0000000..eba7733
--- /dev/null
+++ b/front-end/src/components/MDinput/index.vue
@@ -0,0 +1,356 @@
+<template>
+  <div :class="computedClasses" class="material-input__component">
+    <div :class="{iconClass:icon}">
+      <i v-if="icon" :class="['el-icon-' + icon]" class="el-input__icon material-input__icon" />
+      <input
+        v-if="type === 'email'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :required="required"
+        type="email"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <input
+        v-if="type === 'url'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :required="required"
+        type="url"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <input
+        v-if="type === 'number'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :step="step"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :max="max"
+        :min="min"
+        :minlength="minlength"
+        :maxlength="maxlength"
+        :required="required"
+        type="number"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <input
+        v-if="type === 'password'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :max="max"
+        :min="min"
+        :required="required"
+        type="password"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <input
+        v-if="type === 'tel'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :required="required"
+        type="tel"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <input
+        v-if="type === 'text'"
+        v-model="currentValue"
+        :name="name"
+        :placeholder="fillPlaceHolder"
+        :readonly="readonly"
+        :disabled="disabled"
+        :autocomplete="autoComplete"
+        :minlength="minlength"
+        :maxlength="maxlength"
+        :required="required"
+        type="text"
+        class="material-input"
+        @focus="handleMdFocus"
+        @blur="handleMdBlur"
+        @input="handleModelInput"
+      >
+      <span class="material-input-bar" />
+      <label class="material-label">
+        <slot />
+      </label>
+    </div>
+  </div>
+</template>
+
+<script>
+// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
+export default {
+  name: 'MdInput',
+  props: {
+    /* eslint-disable */
+    icon: String,
+    name: String,
+    type: {
+      type: String,
+      default: 'text'
+    },
+    value: [String, Number],
+    placeholder: String,
+    readonly: Boolean,
+    disabled: Boolean,
+    min: String,
+    max: String,
+    step: String,
+    minlength: Number,
+    maxlength: Number,
+    required: {
+      type: Boolean,
+      default: true
+    },
+    autoComplete: {
+      type: String,
+      default: 'off'
+    },
+    validateEvent: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      currentValue: this.value,
+      focus: false,
+      fillPlaceHolder: null
+    }
+  },
+  computed: {
+    computedClasses() {
+      return {
+        'material--active': this.focus,
+        'material--disabled': this.disabled,
+        'material--raised': Boolean(this.focus || this.currentValue) // has value
+      }
+    }
+  },
+  watch: {
+    value(newValue) {
+      this.currentValue = newValue
+    }
+  },
+  methods: {
+    handleModelInput(event) {
+      const value = event.target.value
+      this.$emit('input', value)
+      if (this.$parent.$options.componentName === 'ElFormItem') {
+        if (this.validateEvent) {
+          this.$parent.$emit('el.form.change', [value])
+        }
+      }
+      this.$emit('change', value)
+    },
+    handleMdFocus(event) {
+      this.focus = true
+      this.$emit('focus', event)
+      if (this.placeholder && this.placeholder !== '') {
+        this.fillPlaceHolder = this.placeholder
+      }
+    },
+    handleMdBlur(event) {
+      this.focus = false
+      this.$emit('blur', event)
+      this.fillPlaceHolder = null
+      if (this.$parent.$options.componentName === 'ElFormItem') {
+        if (this.validateEvent) {
+          this.$parent.$emit('el.form.blur', [this.currentValue])
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  // Fonts:
+  $font-size-base: 16px;
+  $font-size-small: 18px;
+  $font-size-smallest: 12px;
+  $font-weight-normal: normal;
+  $font-weight-bold: bold;
+  $apixel: 1px;
+  // Utils
+  $spacer: 12px;
+  $transition: 0.2s ease all;
+  $index: 0px;
+  $index-has-icon: 30px;
+  // Theme:
+  $color-white: white;
+  $color-grey: #9E9E9E;
+  $color-grey-light: #E0E0E0;
+  $color-blue: #2196F3;
+  $color-red: #F44336;
+  $color-black: black;
+  // Base clases:
+  %base-bar-pseudo {
+    content: '';
+    height: 1px;
+    width: 0;
+    bottom: 0;
+    position: absolute;
+    transition: $transition;
+  }
+  // Mixins:
+  @mixin slided-top() {
+    top: - ($font-size-base + $spacer);
+    left: 0;
+    font-size: $font-size-base;
+    font-weight: $font-weight-bold;
+  }
+  // Component:
+  .material-input__component {
+    margin-top: 36px;
+    position: relative;
+    * {
+      box-sizing: border-box;
+    }
+    .iconClass {
+      .material-input__icon {
+        position: absolute;
+        left: 0;
+        line-height: $font-size-base;
+        color: $color-blue;
+        top: $spacer;
+        width: $index-has-icon;
+        height: $font-size-base;
+        font-size: $font-size-base;
+        font-weight: $font-weight-normal;
+        pointer-events: none;
+      }
+      .material-label {
+        left: $index-has-icon;
+      }
+      .material-input {
+        text-indent: $index-has-icon;
+      }
+    }
+    .material-input {
+      font-size: $font-size-base;
+      padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2;
+      display: block;
+      width: 100%;
+      border: none;
+      line-height: 1;
+      border-radius: 0;
+      &:focus {
+        outline: none;
+        border: none;
+        border-bottom: 1px solid transparent; // fixes the height issue
+      }
+    }
+    .material-label {
+      font-weight: $font-weight-normal;
+      position: absolute;
+      pointer-events: none;
+      left: $index;
+      top: 0;
+      transition: $transition;
+      font-size: $font-size-small;
+    }
+    .material-input-bar {
+      position: relative;
+      display: block;
+      width: 100%;
+      &:before {
+        @extend %base-bar-pseudo;
+        left: 50%;
+      }
+      &:after {
+        @extend %base-bar-pseudo;
+        right: 50%;
+      }
+    }
+    // Disabled state:
+    &.material--disabled {
+      .material-input {
+        border-bottom-style: dashed;
+      }
+    }
+    // Raised state:
+    &.material--raised {
+      .material-label {
+        @include slided-top();
+      }
+    }
+    // Active state:
+    &.material--active {
+      .material-input-bar {
+        &:before,
+        &:after {
+          width: 50%;
+        }
+      }
+    }
+  }
+  .material-input__component {
+    background: $color-white;
+    .material-input {
+      background: none;
+      color: $color-black;
+      text-indent: $index;
+      border-bottom: 1px solid $color-grey-light;
+    }
+    .material-label {
+      color: $color-grey;
+    }
+    .material-input-bar {
+      &:before,
+      &:after {
+        background: $color-blue;
+      }
+    }
+    // Active state:
+    &.material--active {
+      .material-label {
+        color: $color-blue;
+      }
+    }
+    // Errors:
+    &.material--has-errors {
+      &.material--active .material-label {
+        color: $color-red;
+      }
+      .material-input-bar {
+        &:before,
+        &:after {
+          background: transparent;
+        }
+      }
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/front-end/src/router/index.js b/front-end/src/router/index.js
index 4e46ac1..ab638bb 100644
--- a/front-end/src/router/index.js
+++ b/front-end/src/router/index.js
@@ -153,10 +153,10 @@
         hidden: true
       },
       {
-        path: 'namespaces/:tenant/:namespace/policies',
-        component: () => import('@/views/management/namespaces/policies'),
-        name: 'NamespacesPolicies',
-        meta: { title: 'NamespacesPolicies', noCache: true },
+        path: 'namespaces/:tenant/:namespace/namespace',
+        component: () => import('@/views/management/namespaces/namespace'),
+        name: 'NamespacesInfo',
+        meta: { title: 'NamespacesInfo', noCache: true },
         hidden: true
       },
       {
diff --git a/front-end/src/views/management/namespaces/index.vue b/front-end/src/views/management/namespaces/index.vue
index 2e25b20..ad00189 100644
--- a/front-end/src/views/management/namespaces/index.vue
+++ b/front-end/src/views/management/namespaces/index.vue
@@ -1,53 +1,22 @@
 <template>
   <div class="app-container">
     <div class="createPost-container">
-      <el-form ref="postForm" :model="postForm" class="form-container">
-        <div class="createPost-main-container">
-          <el-row>
-            <el-col :span="12">
-              <div class="postInfo-container">
-                <el-row>
-                  <el-col :span="8">
-                    <el-form-item class="postInfo-container-item">
-                      <el-select v-model="postForm.tenant" placeholder="select tenant" @change="getNamespacesList(postForm.tenant)">
-                        <el-option v-for="(item,index) in tenantsListOptions" :key="item+index" :label="item" :value="item"/>
-                      </el-select>
-                    </el-form-item>
-                  </el-col>
-                </el-row>
-              </div>
-            </el-col>
-          </el-row>
-        </div>
+      <el-form :inline="true" :model="postForm" class="form-container">
+        <el-form-item class="postInfo-container-item" label="Tenant">
+          <el-select v-model="postForm.tenant" placeholder="select tenant" @change="getNamespacesList(postForm.tenant)">
+            <el-option v-for="(item,index) in tenantsListOptions" :key="item+index" :label="item" :value="item"/>
+          </el-select>
+        </el-form-item>
       </el-form>
     </div>
     <div class="filter-container">
       <el-input :placeholder="$t('table.namespace')" v-model="listQuery.namespace" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
       <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
       <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('table.add') }}</el-button>
-      <el-dropdown @command="handleCommand">
-        <el-button class="filter-item" style="margin-left: 10px;" type="primary">{{ $t('table.quotas') }}<i class="el-icon-arrow-down el-icon--right"/>
-        </el-button>
-        <el-dropdown-menu slot="dropdown">
-          <el-dropdown-item command="quotas-get">get</el-dropdown-item>
-          <el-dropdown-item command="quotas-set">set</el-dropdown-item>
-          <el-dropdown-item command="quotas-reset">reset</el-dropdown-item>
-        </el-dropdown-menu>
-      </el-dropdown>
-      <el-autocomplete
-        v-model="postForm.otherOptions"
-        :fetch-suggestions="querySearch"
-        class="filter-item inline-input"
-        style="margin-left: 10px; width:400px"
-        placeholder="select options"
-        clearable
-        @select="moreListOptionsChange"
-      />
     </div>
-
     <div>
-      <el-row :gutter="8">
-        <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 14}" :xl="{span: 14}" style="padding-right:8px;margin-bottom:30px;">
+      <el-row :gutter="24">
+        <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 24}" :xl="{span: 24}" style="padding-right:8px;margin-bottom:30px;">
           <el-table
             v-loading="listLoading"
             :key="tableKey"
@@ -55,18 +24,15 @@
             border
             fit
             highlight-current-row
-            style="width: 100%;"
-            @row-click="getCurrentRow">
+            style="width: 100%;">
             <el-table-column :label="$t('table.namespace')" min-width="50px" align="center">
               <template slot-scope="scope">
-                <router-link :to="'/management/tenantNamespace/' + scope.row.namespace" class="link-type">
-                  <span>{{ scope.row.namespace }}</span>
-                </router-link>
+                <span>{{ scope.row.namespace }}</span>
               </template>
             </el-table-column>
-            <el-table-column :label="$t('table.stats')" min-width="30px" align="center">
+            <el-table-column label="topics" min-width="30px" align="center">
               <template slot-scope="scope">
-                <span class="link-type" @click="getNamespacePolicies(scope.row.namespace)">stats</span>
+                <span>{{ scope.row.topics }}</span>
               </template>
             </el-table-column>
             <div v-if="monitorEnable">
@@ -78,17 +44,16 @@
             </div>
             <el-table-column :label="$t('table.actions')" align="center" width="150" class-name="small-padding fixed-width">
               <template slot-scope="scope">
+                <router-link :to="'/management/namespaces/' + scope.row.tenant +'/' + scope.row.namespace + '/namespace'">
+                  <el-button type="primary" size="mini">{{ $t('table.edit') }}</el-button>
+                </router-link>
                 <el-button v-if="scope.row.status!='deleted'" size="mini" type="danger" @click="handleDelete(scope.row)">{{ $t('table.delete') }}</el-button>
               </template>
             </el-table-column>
           </el-table>
           <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getNamespaces" />
         </el-col>
-        <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 10}" :xl="{span: 10}" style="margin-bottom:30px;">
-          <jsonEditor :value="jsonValue"/>
-        </el-col>
       </el-row>
-
     </div>
 
     <el-dialog :visible.sync="dialogFormVisible">
@@ -98,292 +63,8 @@
             <el-input v-model="temp.namespace" placeholder="Please input namespace"/>
           </el-form-item>
         </div>
-        <div v-else-if="dialogStatus==='grant-permission'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item :label="$t('table.grant')" prop="grant">
-            <el-drag-select v-model="temp.actions" style="width:300px;" multiple placeholder="Please select consumer or produce">
-              <el-option v-for="item in actionsListOptions" :label="item.label" :value="item.value" :key="item.value" />
-            </el-drag-select>
-          </el-form-item>
-          <el-form-item :label="$t('table.role')" prop="role">
-            <el-input v-model="temp.role" style="width:300px;" />
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='revoke-permission'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item :label="$t('table.role')" prop="role">
-            <el-input v-model="temp.role"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-clusters'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item :label="$t('table.clusters')" prop="clusters">
-            <el-drag-select v-model="temp.clusters" style="width:330px;" multiple placeholder="Please select clusters">
-              <el-option v-for="item in clusterListOptions" :label="item.label" :value="item.value" :key="item.value" />
-            </el-drag-select>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-backlog-quota'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item :label="$t('table.limit')" prop="limit">
-            <el-input v-model="temp.limit" placeholder="Please select limit"/>
-          </el-form-item>
-          <el-form-item :label="$t('table.policies')" prop="policy">
-            <el-select v-model="temp.policy" placeholder="Please select polices">
-              <el-option v-for="item in policiesListOptions" :label="item.label" :value="item.value" :key="item.value" />
-            </el-select>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='remove-backlog-quota'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-persistence'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="ackQuorum" prop="ackQuorum">
-            <el-input v-model="temp.ackQuorum"/>
-          </el-form-item>
-          <el-form-item label="ensemble" prop="ensemble">
-            <el-input v-model="temp.ensemble"/>
-          </el-form-item>
-          <el-form-item label="writeQuorum" prop="writeQuorum">
-            <el-input v-model="temp.writeQuorum"/>
-          </el-form-item>
-          <el-form-item label="deleteMaxRate" prop="deleteMaxRate">
-            <el-input v-model="temp.deleteMaxRate"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-message-ttl'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="messageTTL" prop="messageTTL">
-            <el-input v-model="temp.messageTTL"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-anti-affinity-group'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="group" prop="group">
-            <el-input v-model="temp.group" placeholder="Please input group"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='delete-anti-affinity-group'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-deduplication'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="deduplication">
-            <el-switch
-              v-model="temp.deduplication"
-              active-color="#13ce66"
-              inactive-color="#ff4949"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-retention'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="retentionSize" prop="retentionSize">
-            <el-input v-model="temp.retentionSize" placeholder="Please input retentionSize"/>
-          </el-form-item>
-          <el-form-item label="retentionTime" prop="retentionTime">
-            <el-input v-model="temp.retentionTime" placeholder="Please input retentionTime"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-dispatch-rate'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="byteDispatchRate" prop="byteDispatchRate">
-            <el-input v-model="temp.byteDispatchRate"/>
-          </el-form-item>
-          <el-form-item label="dispatchRatePeriod" prop="dispatchRatePeriod">
-            <el-input v-model="temp.dispatchRatePeriod"/>
-          </el-form-item>
-          <el-form-item label="msgDispatchRate" prop="msgDispatchRate">
-            <el-input v-model="temp.msgDispatchRate"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='unsubscribe'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="unsubBundle" prop="unsubBundle">
-            <el-input v-model="temp.unsubBundle"/>
-          </el-form-item>
-          <el-form-item label="subName" prop="subName">
-            <el-input v-model="temp.subName" placeholder="Please input subName"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-encryption-required'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="encryption">
-            <el-switch
-              v-model="temp.encryption"
-              active-color="#13ce66"
-              inactive-color="#ff4949"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-subscription-auth-mode'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="auth-mode" prop="subscriptionAuthMode">
-            <el-select v-model="temp.subscriptionAuthMode" style="width:330px;" placeholder="Please select authMode">
-              <el-option v-for="item in authModeListOptions" :label="item.label" :value="item.value" :key="item.value" />
-            </el-select>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-max-producers-per-topic'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="Topic" prop="maxProducersPerTopic">
-            <el-input v-model="temp.maxProducersPerTopic" placeholder="maxProducersPerTopic for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-max-consumers-per-topic'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="Topic" prop="maxConsumersPerTopic">
-            <el-input v-model="temp.maxConsumersPerTopic" placeholder="maxConsumersPerTopic for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-max-consumers-per-subscription'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="subName" prop="maxConsumersPerSub">
-            <el-input v-model="temp.maxConsumersPerSub" placeholder="Get maxConsumersPerSubscription for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-compaction-threshold'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="threshold" prop="threshold">
-            <el-input v-model="temp.threshold" placeholder="Set compactionThreshold for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-offload-threshold'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="thresholdSize" prop="thresholdSize">
-            <el-input v-model="temp.thresholdSize" placeholder="Set offloadThreshold for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-offload-deletion-lag'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="deletionLag" prop="deletionLag">
-            <el-input v-model="temp.deletionLag" placeholder="Get offloadDeletionLag, in minutes, for a namespace"/>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='clear-offload-deletion-lag'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='set-schema-autoupdate-strategy'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-          <el-form-item label="compatibility" prop="compatibility">
-            <el-select v-model="temp.compatibility" style="width:330px;" placeholder="Please select">
-              <el-option v-for="item in compatibilityListOptions" :label="item.label" :value="item.value" :key="item.value" />
-            </el-select>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='clear-backlog'">
-          <el-form-item :label="$t('table.namespace')">
-            <span>{{ currentNamespace }}</span>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='quotas-get'||dialogStatus==='quotas-reset'||dialogStatus==='unload'||dialogStatus==='split-bundle'">
-          <div v-if="dialogStatus==='unload'">
-            <el-form-item :label="$t('table.namespace')">
-              <span>{{ currentNamespace }}</span>
-            </el-form-item>
-          </div>
-          <div v-else-if="dialogStatus==='split-bundle'">
-            <el-form-item :label="$t('table.namespace')">
-              <span>{{ currentNamespace }}</span>
-            </el-form-item>
-            <!-- <el-form-item label="splitBundle" prop="splitBundle">
-              <el-input v-model="temp.splitBundle"/>
-            </el-form-item> -->
-            <el-form-item label="splitUnload">
-              <el-switch
-                v-model="temp.splitUnload"
-                active-color="#13ce66"
-                inactive-color="#ff4949"/>
-            </el-form-item>
-          </div>
-          <el-form-item label="startBundle" prop="startBundle">
-            <el-select v-model="temp.startBundle" style="width:330px;" placeholder="Please select startBundle" @focus="getBundleList()">
-              <el-option v-for="(item,index) in startBundleListOptions" :key="item+index" :label="item" :value="item"/>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="stopBundle" prop="stopBundle">
-            <el-select v-model="temp.stopBundle" style="width:330px;" placeholder="Please select stopBundle" @focus="getBundleList()">
-              <el-option v-for="(item,index) in stopBundleListOptions" :key="item+index" :label="item" :value="item"/>
-            </el-select>
-          </el-form-item>
-        </div>
-        <div v-else-if="dialogStatus==='quotas-set'">
-          <el-form-item label="startBundle" prop="setStartBundle">
-            <el-select v-model="temp.setStartBundle" style="width:330px;" placeholder="Please select startBundle" @focus="getBundleList()">
-              <el-option v-for="(item,index) in startBundleListOptions" :key="item+index" :label="item" :value="item"/>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="stopBundle" prop="setsStopBundle">
-            <el-select v-model="temp.setStopBundle" style="width:330px;" placeholder="Please select stopBundle" @focus="getBundleList()">
-              <el-option v-for="(item,index) in stopBundleListOptions" :key="item+index" :label="item" :value="item"/>
-            </el-select>
-          </el-form-item>
-          <el-form-item label="dynamic">
-            <el-switch
-              v-model="temp.dynamic"
-              active-color="#13ce66"
-              inactive-color="#ff4949"/>
-          </el-form-item>
-          <el-form-item label="bandwidthIn" prop="bandwidthIn">
-            <el-input v-model="temp.bandwidthIn" placeholder="expected inbound bandwidth (bytes/second)"/>
-          </el-form-item>
-          <el-form-item label="bandwidthOut" prop="bandwidthOut">
-            <el-input v-model="temp.bandwidthOut" placeholder="expected outbound bandwidth (bytes/second)"/>
-          </el-form-item>
-          <el-form-item label="memory" prop="memory">
-            <el-input v-model="temp.memory" placeholder="expected memory usage (Mbytes)"/>
-          </el-form-item>
-          <el-form-item label="msgRateIn" prop="msgRateIn">
-            <el-input v-model="temp.msgRateIn" placeholder="expected incoming messages per second"/>
-          </el-form-item>
-          <el-form-item label="msgRateOut" prop="msgRateOut">
-            <el-input v-model="temp.msgRateOut" placeholder="expected outgoing messages per second"/>
-          </el-form-item>
+        <div v-if="dialogStatus==='delete'">
+          <h4>Are you sure you want to delete this namespace {{ temp.tenant }}/{{ temp.namespace }}?</h4>
         </div>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -398,63 +79,24 @@
 <script>
 import {
   fetchNamespaces,
-  fetchNamespacePolicies,
   putNamespace,
-  deleteNamespace,
-  grantPermissions,
-  revokePermissions,
-  setClusters,
-  setBacklogQuota,
-  removeBacklogQuota,
-  setPersistence,
-  setMessageTtl,
-  setAntiAffinityGroup,
-  deleteAntiAffinityGroup,
-  setDeduplication,
-  setRetention,
-  unloadBundle,
-  splitBundle,
-  setDispatchRate,
-  clearBacklog,
-  unsubscribe,
-  unsubscribeByBundle,
-  setEncryptionRequired,
-  setSubscriptionAuthMode,
-  setMaxProducersPerTopic,
-  setMaxConsumersPerTopic,
-  setMaxConsumersPerSubscription,
-  setCompactionThreshold,
-  setOffloadThreshold,
-  setOffloadDeletionLag,
-  clearOffloadDeletionLag,
-  setSchemaAutoupdateStrategy
+  deleteNamespace
 } from '@/api/namespaces'
-import {
-  getResourceQuotasByNamespace,
-  getResourceQuotas,
-  setResourceQuotas,
-  setResourceQuotasByNamespace,
-  removeResourceQuotasByNamespace
-} from '@/api/resource-quotas'
-import { grafanaSearch } from '@/api/grafana'
 import { fetchTenants } from '@/api/tenants'
 import { fetchClusters } from '@/api/clusters'
 import waves from '@/directive/waves' // Waves directive
 import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
-import jsonEditor from '@/components/JsonEditor'
+// import jsonEditor from '@/components/JsonEditor'
 import { validateEmpty } from '@/utils/validate'
 import ElDragSelect from '@/components/DragSelect' // base on element-ui
-
 const defaultForm = {
   tenant: '',
   otherOptions: ''
 }
-
 export default {
   name: 'Namespaces',
   components: {
     Pagination,
-    jsonEditor,
     ElDragSelect
   },
   directives: { waves },
@@ -465,8 +107,6 @@
       clusters: [],
       clusterListOptions: [],
       tenantsListOptions: [],
-      policiesListOptions: [],
-      actionsListOptions: [],
       authModeListOptions: [],
       moreListOptions: [],
       startBundleListOptions: [],
@@ -478,7 +118,6 @@
       localList: [],
       searchList: [],
       total: 0,
-      jsonValue: {},
       listLoading: true,
       policiesListLoading: false,
       currentNamespace: '',
@@ -497,116 +136,34 @@
         namespace: '',
         limit: '',
         actions: [],
-        clusters: [],
-        subscriptionAuthMode: '',
-        policy: '',
-        ackQuorum: 0,
-        ensemble: 0,
-        writeQuorum: 0,
-        deleteMaxRate: 0.0,
-        messageTTL: 0,
-        group: '',
-        deduplication: false,
-        retentionSize: '',
-        retentionTime: '',
-        unloadBundle: '',
-        splitBundle: '',
-        splitUnload: false,
-        byteDispatchRate: -1,
-        dispatchRatePeriod: 1,
-        msgDispatchRate: 1,
-        clearBundle: '',
-        clearForce: false,
-        clearSub: '',
-        unsubBundle: '',
-        encryption: false,
-        maxProducersPerTopic: 0,
-        maxConsumersPerTopic: 0,
-        maxConsumersPerSub: 0,
-        threshold: 0,
-        thresholdSize: -1,
-        deletionLag: -1,
-        compatibility: 0,
-        startBundle: '0x00000000',
-        stopBundle: '0x40000000',
-        setStartBundle: '0x00000000',
-        setStopBundle: '0x40000000',
-        bandwidthIn: 0,
-        bandwidthOut: 0,
-        memory: '',
-        msgRateIn: 0,
-        msgRateOut: 0,
-        dynamic: false,
-        subName: ''
+        clusters: []
       },
       dialogFormVisible: false,
       dialogStatus: '',
       rules: {
         namespace: [{ required: true, message: 'namespace is required', trigger: 'blur' }],
         grant: [{ required: true, message: 'grant is required', trigger: 'blur' }],
-        clusters: [{ required: true, message: 'clusters is required', trigger: 'blur' }],
-        limit: [{ required: true, message: 'limit is required', trigger: 'blur' }],
-        policy: [{ required: true, message: 'policy is required', trigger: 'blur' }],
-        role: [{ required: true, message: 'role is required', trigger: 'blur' }],
-        ackQuorum: [{ required: true, message: 'ackQuorum is required', trigger: 'blur' }],
-        ensemble: [{ required: true, message: 'ensemble is required', trigger: 'blur' }],
-        writeQuorum: [{ required: true, message: 'writeQuorum is required', trigger: 'blur' }],
-        deleteMaxRate: [{ required: true, message: 'deleteMaxRate is required', trigger: 'blur' }],
-        messageTTL: [{ required: true, message: 'messageTTL is required', trigger: 'blur' }],
-        group: [{ required: true, message: 'group is required', trigger: 'blur' }],
-        retentionSize: [{ required: true, message: 'retentionSize is required', trigger: 'blur' }],
-        retentionTime: [{ required: true, message: 'retentionTime is required', trigger: 'blur' }],
-        stopBundle: [{ required: true, message: 'stopBundle is required', trigger: 'blur' }],
-        startBundle: [{ required: true, message: 'startBundle is required', trigger: 'blur' }],
-        bandwidthIn: [{ required: true, message: 'bandwidthIn is required', trigger: 'blur' }],
-        bandwidthOut: [{ required: true, message: 'bandwidthOut is required', trigger: 'blur' }],
-        memory: [{ required: true, message: 'memory is required', trigger: 'blur' }],
-        msgRateIn: [{ required: true, message: 'msgRateIn is required', trigger: 'blur' }],
-        msgRateOut: [{ required: true, message: 'msgRateOut is required', trigger: 'blur' }],
-        subName: [{ required: true, message: 'subName is required', trigger: 'blur' }],
-        subscriptionAuthMode: [{ required: true, message: 'subscriptionAuthMode is required', trigger: 'blur' }],
-        maxProducersPerTopic: [{ required: true, message: 'maxProducersPerTopic is required', trigger: 'blur' }],
-        maxConsumersPerTopic: [{ required: true, message: 'maxConsumersPerTopic is required', trigger: 'blur' }],
-        maxConsumersPerSub: [{ required: true, message: 'maxConsumersPerTopic is required', trigger: 'blur' }],
-        threshold: [{ required: true, message: 'threshold is required', trigger: 'blur' }],
-        thresholdSize: [{ required: true, message: 'thresholdSize is required', trigger: 'blur' }],
-        deletionLag: [{ required: true, message: 'deletionLag is required', trigger: 'blur' }]
+        clusters: [{ required: true, message: 'clusters is required', trigger: 'blur' }]
       }
     }
   },
   created() {
+    this.tenant = this.$route.params && this.$route.params.tenant
     if (process.env.GRAFANA_ENABLE) {
-      this.getGrafanaSearch()
+      // this.getGrafanaSearch()
     } else {
       this.getNamespaces()
     }
-    this.tenant = this.$route.params && this.$route.params.tenant
+    this.postForm.tenant = this.tenant
     this.getRemoteTenantsList()
   },
   mounted() {
-    this.moreListOptions = this.loadAllOptions()
-    this.actionsListOptions = [{ value: 'produce', label: 'produce' }, { value: 'consume', label: 'consume' }]
     this.clusterListOptions = []
     fetchClusters(this.listQuery).then(response => {
       for (var i = 0; i < response.data.length; i++) {
         this.clusterListOptions.push({ 'value': response.data[i], 'label': response.data[i] })
       }
     })
-    this.policiesListOptions = [
-      { value: 'producer_request_hold', label: 'producer_request_hold' },
-      { value: 'producer_exception', label: 'producer_exception' },
-      { value: 'consumer_backlog_eviction', label: 'consumer_backlog_eviction' }
-    ]
-    this.compatibilityListOptions = [
-      { value: 0, label: 'AutoUpdateDisabled' },
-      { value: 1, label: 'Backward' },
-      { value: 2, label: 'Forward' },
-      { value: 3, label: 'Full' }
-    ]
-    this.authModeListOptions = [
-      { value: 0, label: 'None' },
-      { value: 1, label: 'Prefix' }
-    ]
   },
   methods: {
     getNamespaces() {
@@ -620,12 +177,21 @@
           this.tenant = 'public'
         }
         fetchNamespaces(this.tenant, this.listQuery).then(response => {
-          for (var i = 0; i < response.data.length; i++) {
+          for (var i = 0; i < response.data.data.length; i++) {
             if (this.monitorEnable) {
-              const monitorUrl = process.env.GRAFANA_ADDRESS + this.grafanaUrl + '?refresh=1m&' + 'var-namespace=' + response.data[i]
-              this.localList.push({ 'namespace': response.data[i], 'monitor': monitorUrl })
+              const monitorUrl = process.env.GRAFANA_ADDRESS + this.grafanaUrl + '?refresh=1m&' + 'var-namespace=' + response.data.data[i].namespace
+              this.localList.push({
+                'tenant': this.tenant,
+                'namespace': response.data.data[i].namespace,
+                'topics': response.data.data[i].topics,
+                'monitor': monitorUrl
+              })
             } else {
-              this.localList.push({ 'namespace': response.data[i] })
+              this.localList.push({
+                'tenant': this.tenant,
+                'namespace': response.data.data[i].namespace,
+                'topics': response.data.data[i].topics
+              })
             }
           }
           this.total = this.localList.length
@@ -654,16 +220,6 @@
       }
       this.listLoading = false
     },
-    getNamespacePolicies(namespace) {
-      // this.policiesListLoading = true
-      fetchNamespacePolicies(namespace).then(response => {
-        this.jsonValue = response.data
-        // Just to simulate the time of the request
-        setTimeout(() => {
-          this.policiesListLoading = false
-        }, 1.5 * 1000)
-      })
-    },
     handleFilter() {
       this.getNamespaces()
     },
@@ -672,47 +228,7 @@
         namespace: '',
         limit: '',
         actions: [],
-        clusters: [],
-        subscriptionAuthMode: '',
-        policy: '',
-        ackQuorum: 0,
-        ensemble: 0,
-        writeQuorum: 0,
-        deleteMaxRate: 0.0,
-        messageTTL: 0,
-        group: '',
-        deduplication: false,
-        retentionSize: '',
-        retentionTime: '',
-        unloadBundle: '',
-        splitBundle: '',
-        splitUnload: false,
-        byteDispatchRate: -1,
-        dispatchRatePeriod: 1,
-        msgDispatchRate: 1,
-        clearBundle: '',
-        clearForce: false,
-        clearSub: '',
-        unsubBundle: '',
-        encryption: false,
-        maxProducersPerTopic: 0,
-        maxConsumersPerTopic: 0,
-        maxConsumersPerSub: 0,
-        threshold: 0,
-        thresholdSize: -1,
-        deletionLag: -1,
-        compatibility: 0,
-        startBundle: '0x00000000',
-        stopBundle: '0x40000000',
-        setStartBundle: '0x00000000',
-        setStopBundle: '0x40000000',
-        bandwidthIn: 0,
-        bandwidthOut: 0,
-        memory: '',
-        msgRateIn: 0,
-        msgRateOut: 0,
-        dynamic: false,
-        subName: ''
+        clusters: []
       }
     },
     handleCreate() {
@@ -734,13 +250,21 @@
       })
     },
     handleDelete(row) {
-      deleteNamespace(row.namespace).then((response) => {
+      this.dialogStatus = 'delete'
+      this.dialogFormVisible = true
+      this.temp.tenant = row.tenant
+      this.temp.namespace = row.namespace
+    },
+    deleteData() {
+      var tenantNamespace = this.temp.tenant + '/' + this.temp.namespace
+      deleteNamespace(tenantNamespace).then((response) => {
         this.$notify({
           title: 'success',
           message: 'delete success',
           type: 'success',
           duration: 2000
         })
+        this.dialogFormVisible = false
         this.localList = []
         this.getNamespaces()
       })
@@ -748,8 +272,9 @@
     getRemoteTenantsList() {
       fetchTenants().then(response => {
         if (!response.data) return
-        this.tenantsListOptions = response.data
-        console.log(this.tenantsListOptions)
+        for (var i = 0; i < response.data.total; i++) {
+          this.tenantsListOptions.push(response.data.data[i].tenant)
+        }
       })
     },
     getNamespacesList(tenant) {
@@ -757,24 +282,6 @@
       this.localList = []
       this.getNamespaces()
     },
-    moreListOptionsChange(item) {
-      if (this.currentNamespace.length <= 0) {
-        this.$notify({
-          title: 'error',
-          message: 'Please select any one namespace in table',
-          type: 'error',
-          duration: 3000
-        })
-        this.postForm.otherOptions = ''
-        return
-      }
-      this.dialogStatus = item.value
-      this.dialogFormVisible = true
-      this.postForm.otherOptions = ''
-      this.$nextTick(() => {
-        this.$refs['temp'].clearValidate()
-      })
-    },
     querySearch(queryString, cb) {
       var moreListOptions = this.moreListOptions
       var results = moreListOptions.filter(this.createFilterOptions(queryString))
@@ -785,42 +292,6 @@
         return (moreListOptions.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
       }
     },
-    loadAllOptions() {
-      const options = [
-        { 'value': 'set-clusters' },
-        { 'value': 'set-backlog-quota' },
-        { 'value': 'remove-backlog-quota' },
-        { 'value': 'set-persistence' },
-        { 'value': 'set-message-ttl' },
-        { 'value': 'set-anti-affinity-group' },
-        { 'value': 'delete-anti-affinity-group' },
-        { 'value': 'set-deduplication' },
-        { 'value': 'set-retention' },
-        { 'value': 'unload' },
-        { 'value': 'split-bundle' },
-        { 'value': 'set-dispatch-rate' },
-        { 'value': 'clear-backlog' },
-        { 'value': 'unsubscribe' },
-        { 'value': 'set-encryption-required' },
-        { 'value': 'set-subscription-auth-mode' },
-        { 'value': 'set-max-producers-per-topic' },
-        { 'value': 'set-max-consumers-per-topic' },
-        { 'value': 'set-max-consumers-per-subscription' },
-        { 'value': 'set-compaction-threshold' },
-        { 'value': 'set-offload-threshold' },
-        { 'value': 'set-offload-deletion-lag' },
-        { 'value': 'clear-offload-deletion-lag' },
-        { 'value': 'set-schema-autoupdate-strategy' }
-      ]
-      if (process.env.USE_TLS) {
-        options.push({ 'value': 'grant-permission' })
-        options.push({ 'value': 'revoke-permission' })
-      }
-      return options
-    },
-    getCurrentRow(item) {
-      this.currentNamespace = item.namespace
-    },
     handleOptions() {
       this.$refs['temp'].validate((valid) => {
         if (valid) {
@@ -828,553 +299,9 @@
             case 'create':
               this.createNamespace()
               break
-            case 'grant-permission':
-              this.confirmGrantPermission()
+            case 'delete':
+              this.deleteData()
               break
-            case 'revoke-permission':
-              this.confirmRevokePermissions()
-              break
-            case 'set-clusters':
-              this.confirmSetClusters()
-              break
-            case 'set-backlog-quota':
-              this.confirmSetBacklogQuota()
-              break
-            case 'remove-backlog-quota':
-              this.confirmRemoveBacklogQuota()
-              break
-            case 'set-persistence':
-              this.confirmSetPersistence()
-              break
-            case 'set-message-ttl':
-              this.confirmSetMessageTtl()
-              break
-            case 'set-anti-affinity-group':
-              this.confirmSetAntiAffinityGroup()
-              break
-            case 'delete-anti-affinity-group':
-              this.confirmDeleteAntiAffinityGroup()
-              break
-            case 'set-deduplication':
-              this.confirmSetDeduplication()
-              break
-            case 'set-retention':
-              this.confirmSetRetention()
-              break
-            case 'unload':
-              this.confirmUnload()
-              break
-            case 'split-bundle':
-              this.confirmSplitBundle()
-              break
-            case 'set-dispatch-rate':
-              this.confirmSetDispatchRate()
-              break
-            case 'clear-backlog':
-              this.confirmClearBacklog()
-              break
-            case 'unsubscribe':
-              this.confirmUnsubscribe()
-              break
-            case 'set-encryption-required':
-              this.confirmSetEncryptionRequired()
-              break
-            case 'set-subscription-auth-mode':
-              this.confirmSetSubscriptionAuthMode()
-              break
-            case 'set-max-producers-per-topic':
-              this.confirmSetMaxProducersPerTopic()
-              break
-            case 'set-max-consumers-per-topic':
-              this.confirmSetMaxConsumersPerTopic()
-              break
-            case 'set-max-consumers-per-subscription':
-              this.confirmSetMaxConsumersPerSubscription()
-              break
-            case 'set-compaction-threshold':
-              this.confirmSetCompactionThreshold()
-              break
-            case 'set-offload-threshold':
-              this.confirmSetOffloadThreshold()
-              break
-            case 'set-offload-deletion-lag':
-              this.confirmSetOffloadDeletionLag()
-              break
-            case 'clear-offload-deletion-lag':
-              this.confirmClearOffloadDeletionLag()
-              break
-            case 'set-schema-autoupdate-strategy':
-              this.confirmSetSchemaAutoupdateStrategy()
-              break
-            case 'quotas-get':
-              this.confirmQuotasGet()
-              break
-            case 'quotas-set':
-              this.confirmQuotasSet()
-              break
-            case 'quotas-reset':
-              this.confirmQuotasReset()
-              break
-          }
-        }
-      })
-    },
-    confirmGrantPermission() {
-      grantPermissions(this.currentNamespace, this.temp.role, this.temp.actions).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Add success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmRevokePermissions() {
-      revokePermissions(this.currentNamespace, this.temp.role).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Delete success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetClusters() {
-      setClusters(this.currentNamespace, this.temp.clusters).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Add clusters success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetBacklogQuota() {
-      setBacklogQuota(this.currentNamespace, this.temp).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Add Backlog Quota success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmRemoveBacklogQuota() {
-      removeBacklogQuota(this.currentNamespace).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Delete Backlog Quota success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetPersistence() {
-      const data = {
-        'bookkeeper_ack_quorum': this.temp.ackQuorum,
-        'bookkeeper_ensemble': this.temp.ensemble,
-        'bookkeeper_write_quorum': this.temp.writeQuorum,
-        'ml_mark_delete_max_rate': this.temp.deleteMaxRate
-      }
-      setPersistence(this.currentNamespace, data).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set persistence success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetMessageTtl() {
-      setMessageTtl(this.currentNamespace, parseInt(this.temp.messageTTL)).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set messageTTL success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetAntiAffinityGroup() {
-      setAntiAffinityGroup(this.currentNamespace, this.temp.group).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set AntiAffinityGroup success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmDeleteAntiAffinityGroup() {
-      deleteAntiAffinityGroup(this.currentNamespace).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Delete AntiAffinityGroup success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetDeduplication() {
-      setDeduplication(this.currentNamespace, this.temp.deduplication).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set deduplication success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetRetention() {
-      const data = { 'size': this.temp.retentionSize, 'time': this.temp.retentionTime }
-      setRetention(this.currentNamespace, data).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set Retention success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmUnload() {
-      const bundle = this.temp.startBundle + '_' + this.temp.stopBundle
-      unloadBundle(this.currentNamespace, bundle).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Unload success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSplitBundle() {
-      // const data = { 'unload': this.temp.splitUnload }
-      // problem split http 412
-      // to do solve
-      const bundle = this.temp.startBundle + '_' + this.temp.stopBundle
-      splitBundle(this.currentNamespace, bundle, this.temp.splitUnload).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'splitBundle success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetDispatchRate() {
-      const data = {
-        'dispatchThrottlingRateInByte': this.temp.byteDispatchRate,
-        'ratePeriodInSecond': this.temp.dispatchRatePeriod,
-        'dispatchThrottlingRateInMsg': this.temp.msgDispatchRate
-      }
-      setDispatchRate(this.currentNamespace, data).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'set DispatchRate success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmClearBacklog() {
-      clearBacklog(this.currentNamespace).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'clearBacklog success for namespace',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmUnsubscribe() {
-      if (this.temp.unsubBundle.length > 0) {
-        unsubscribeByBundle(this.currentNamespace, this.temp.unsubBundle, this.temp.unsubscribe).then(response => {
-          this.dialogFormVisible = false
-          this.$notify({
-            title: 'success',
-            message: 'unsubscribe success for namespace',
-            type: 'success',
-            duration: 3000
-          })
-        })
-      } else {
-        unsubscribe(this.currentNamespace, this.temp.subName).then(response => {
-          this.dialogFormVisible = false
-          this.$notify({
-            title: 'success',
-            message: 'unsubscribe success for namespace',
-            type: 'success',
-            duration: 3000
-          })
-        })
-      }
-    },
-    confirmSetEncryptionRequired() {
-      setEncryptionRequired(this.currentNamespace, this.temp.encryption).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetSubscriptionAuthMode() {
-      setSubscriptionAuthMode(this.currentNamespace, this.temp.subscriptionAuthMode).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetMaxProducersPerTopic() {
-      setMaxProducersPerTopic(this.currentNamespace, this.temp.maxProducersPerTopic).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set max producers per topic success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetMaxConsumersPerTopic() {
-      setMaxConsumersPerTopic(this.currentNamespace, this.temp.maxConsumersPerTopic).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set max consumers per topic success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetMaxConsumersPerSubscription() {
-      setMaxConsumersPerSubscription(this.currentNamespace, this.temp.maxConsumersPerSub).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set max subscription per topic success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetCompactionThreshold() {
-      setCompactionThreshold(this.currentNamespace, this.temp.threshold).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set threshold success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetOffloadThreshold() {
-      setOffloadThreshold(this.currentNamespace, this.temp.thresholdSize).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set threshold success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetOffloadDeletionLag() {
-      setOffloadDeletionLag(this.currentNamespace, this.temp.deletionLag).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set DeletionLag success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmClearOffloadDeletionLag() {
-      clearOffloadDeletionLag(this.currentNamespace).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Clear DeletionLag success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    confirmSetSchemaAutoupdateStrategy() {
-      // todo put method not allowed
-      setSchemaAutoupdateStrategy(this.currentNamespace, this.temp.compatibility).then(response => {
-        this.dialogFormVisible = false
-        this.$notify({
-          title: 'success',
-          message: 'Set SchemaAutoupdateStrategy success',
-          type: 'success',
-          duration: 3000
-        })
-      })
-    },
-    handleCommand(command) {
-      this.currentCommand = command
-      switch (this.currentCommand) {
-        case 'quotas-get':
-          this.handleQuotasGet()
-          break
-        case 'quotas-set':
-          this.handleQuotasSet()
-          break
-        case 'quotas-reset':
-          this.handleQuotasReset()
-          break
-      }
-    },
-    handleQuotasGet() {
-      if (this.currentNamespace.length > 0) {
-        this.dialogStatus = 'quotas-get'
-        this.dialogFormVisible = true
-        this.$nextTick(() => {
-          this.$refs['temp'].clearValidate()
-        })
-      } else {
-        this.confirmQuotasGet()
-      }
-    },
-    handleQuotasSet() {
-      this.dialogStatus = 'quotas-set'
-      this.dialogFormVisible = true
-      this.$nextTick(() => {
-        this.$refs['temp'].clearValidate()
-      })
-    },
-    handleQuotasReset() {
-      this.dialogStatus = 'quotas-reset'
-      this.dialogFormVisible = true
-      this.$nextTick(() => {
-        this.$refs['temp'].clearValidate()
-      })
-    },
-    confirmQuotasGet() {
-      if (this.currentNamespace.length > 0) {
-        const bundle = this.temp.startBundle + '_' + this.temp.stopBundle
-        getResourceQuotasByNamespace(this.currentNamespace, bundle).then(response => {
-          this.jsonValue = response.data
-          this.dialogFormVisible = false
-          return
-        })
-        return
-      }
-      getResourceQuotas().then(response => {
-        this.jsonValue = response.data
-      })
-    },
-    confirmQuotasSet() {
-      const data = {
-        'msgRateIn': this.temp.msgRateIn,
-        'msgRateOut': this.temp.msgRateOut,
-        'bandwidthIn': this.temp.bandwidthIn,
-        'bandwidthOut': this.temp.bandwidthOut,
-        'memory': this.temp.memory,
-        'dynamic': this.temp.dynamic
-      }
-      if (this.currentNamespace.length > 0) {
-        if (this.temp.setStartBundle.length <= 0 || this.temp.setStopBundle <= 0) {
-          this.$notify({
-            title: 'error',
-            message: 'Please select startBundle and stopBundle',
-            type: 'error',
-            duration: 3000
-          })
-          return
-        }
-        const bundle = this.temp.setStartBundle + '_' + this.temp.setStopBundle
-        setResourceQuotasByNamespace(this.currentNamespace, bundle, data).then(response => {
-          this.$notify({
-            title: 'success',
-            message: 'Set resource quotas success for namespace',
-            type: 'success',
-            duration: 3000
-          })
-          this.dialogFormVisible = false
-        })
-        return
-      }
-      setResourceQuotas(data).then(response => {
-        this.$notify({
-          title: 'success',
-          message: 'Set resource quotas success',
-          type: 'success',
-          duration: 3000
-        })
-        this.dialogFormVisible = false
-      })
-    },
-    confirmQuotasReset() {
-      if (this.currentNamespace.length <= 0) {
-        this.$notify({
-          title: 'error',
-          message: 'Please select any one namespace in table',
-          type: 'error',
-          duration: 3000
-        })
-        return
-      }
-      const bundle = this.temp.startBundle + '_' + this.temp.stopBundle
-      removeResourceQuotasByNamespace(this.currentNamespace, bundle).then(response => {
-        this.$notify({
-          title: 'success',
-          message: 'Remove resource quotas success',
-          type: 'success',
-          duration: 3000
-        })
-        this.dialogFormVisible = false
-        return
-      })
-    },
-    getBundleList() {
-      this.startBundleListOptions = []
-      this.stopBundleListOptions = []
-      if (this.currentNamespace.length <= 0) {
-        this.$notify({
-          title: 'error',
-          message: 'Please select any one namespace in table',
-          type: 'error',
-          duration: 3000
-        })
-        return
-      }
-      fetchNamespacePolicies(this.currentNamespace).then(response => {
-        this.startBundleListOptions = response.data.bundles.boundaries
-        this.stopBundleListOptions = response.data.bundles.boundaries
-      })
-    },
-    getGrafanaSearch() {
-      grafanaSearch('', 'messaging').then(response => {
-        for (var i = 0; i < response.data.length; i++) {
-          if (response.data[i]['uri'] === 'db/messaging-metrics') {
-            this.grafanaUrl = response.data[i]['url']
-            this.monitorEnable = true
-            this.getNamespaces()
           }
         }
       })
diff --git a/front-end/src/views/management/namespaces/namespace.vue b/front-end/src/views/management/namespaces/namespace.vue
new file mode 100644
index 0000000..8d5e9b2
--- /dev/null
+++ b/front-end/src/views/management/namespaces/namespace.vue
@@ -0,0 +1,1475 @@
+<template>
+  <div class="app-container">
+    <div class="createPost-container">
+      <el-form :inline="true" :model="postForm" class="form-container">
+        <el-form-item class="postInfo-container-item" label="Tenant">
+          <el-select v-model="postForm.tenant" placeholder="select tenant" @change="getNamespacesList(postForm.tenant)">
+            <el-option v-for="(item,index) in tenantsListOptions" :key="item+index" :label="item" :value="item"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item class="postInfo-container-item" label="Namespace">
+          <el-select v-model="postForm.namespace" placeholder="select namespace" @change="getNamespaceInfo(postForm.tenant, postForm.namespace)">
+            <el-option v-for="(item,index) in namespacesListOptions" :key="item+index" :label="item" :value="item"/>
+          </el-select>
+        </el-form-item>
+      </el-form>
+    </div>
+    <el-tabs v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="OVERVIEW" name="overview">
+        <el-table
+          :data="namespaceStats"
+          border
+          style="width: 100%">
+          <el-table-column prop="inMsg" label="In - msg/s"/>
+          <el-table-column prop="outMsg" label="Out - msg/s"/>
+          <el-table-column prop="inBytes" label="In - bytes/s"/>
+          <el-table-column prop="outBytes" label="Out - bytes/s"/>
+        </el-table>
+        <h4>Bundles</h4>
+        <hr class="split-line">
+        <div class="filter-container">
+          <!-- <el-input placeholder="Search Bundles" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilterBundle"/> -->
+          <!-- <el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilterBundle">{{ $t('table.search') }}</el-button> -->
+          <el-button class="filter-item" style="margin-left: 10px;" type="danger" icon="el-icon-delete" @click="handleUnloadAll">Unload All</el-button>
+          <el-button class="filter-item" style="margin-left: 10px;" type="danger" icon="el-icon-delete" @click="hanldeClearAllBacklog">Clear All Backlog</el-button>
+        </div>
+        <el-table
+          :key="tableKey"
+          :data="localList"
+          border
+          fit
+          highlight-current-row
+          style="width: 100%;">
+          <el-table-column label="Bundle" align="center" min-width="100px">
+            <template slot-scope="scope">
+              <span>{{ scope.row.bundle }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="Operations" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button size="medium" type="danger" @click="handleSplitBundle(scope.row)">Split</el-button>
+              <el-button size="medium" type="danger" @click="handleUnloadBundle(scope.row)">Unload</el-button>
+              <el-button size="medium" type="danger">Clear Backlog</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit"/> -->
+      </el-tab-pane>
+      <el-tab-pane label="TOPICS" name="topics">
+        <el-row :gutter="24">
+          <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 24}" :xl="{span: 24}" style="padding-right:8px;margin-bottom:30px;">
+            <el-table
+              v-loading="topicsListLoading"
+              :key="topicsTableKey"
+              :data="topicsList"
+              border
+              fit
+              highlight-current-row
+              style="width: 100%;">
+              <el-table-column label="Topic" min-width="50px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.topic }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Partitions" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.partitions }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Producers" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.producers }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Subscriptions" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.subscriptions }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="In - msg/s" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.inMsg }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Out - msg/s" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.outMsg }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="In - bytes/s" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.inBytes }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Out - bytes/s" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.outBytes }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="Storage Size" min-width="30px" align="center">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.storageSize }}</span>
+                </template>
+              </el-table-column>
+            </el-table>
+            <pagination v-show="topicsTotal>0" :total="topicsTotal" :page.sync="topicsListQuery.page" :limit.sync="topicsListQuery.limit" @pagination="getTopics" />
+          </el-col>
+        </el-row>
+      </el-tab-pane>
+      <el-tab-pane label="POLICIES" name="policies">
+        <h4>Namespace Name</h4>
+        <hr class="split-line">
+        <span>{{ tenantNamespace }}</span>
+        <h4>Clusters</h4>
+        <hr class="split-line">
+        <div class="component-item">
+          <div class="section-title">
+            <span>Replicated Clusters</span>
+            <el-tooltip :content="replicatedClustersContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+          </div>
+          <el-select
+            v-model="replicationClustersValue"
+            style="width:500px;margin-top:20px"
+            multiple
+            placeholder="Please Select Cluster"
+            @change="handleReplicationsClusters()">
+            <el-option v-for="item in replicationClustersOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </div>
+        <h4>Authorization
+          <el-tooltip :content="authorizationContent" class="item" effect="dark" placement="top">
+            <i class="el-icon-info"/>
+          </el-tooltip>
+        </h4>
+        <hr class="split-line">
+        <el-form>
+          <el-tag
+            v-for="tag in dynamicTags"
+            :label="tag"
+            :key="tag"
+            :disable-transitions="false"
+            style="margin-top:20px"
+            class="role-el-tag">
+            <div>
+              <span> {{ tag }} </span>
+            </div>
+            <el-select
+              v-model="roleMap[tag]"
+              multiple
+              placeholder="Please Select Options"
+              style="width:300px;"
+              @change="handleChangeOptions()">
+              <el-option
+                v-for="item in roleMapOptions[tag]"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+                style="width:300px"/>
+            </el-select>
+            <el-button @click.prevent="handleClose(tag)">删除</el-button>
+          </el-tag>
+          <el-form-item style="margin-top:30px">
+            <el-input
+              v-if="inputVisible"
+              ref="saveTagInput"
+              v-model="inputValue"
+              style="margin-right:10px;width:200px;vertical-align:top"
+              size="small"
+              class="input-new-tag"
+              @keyup.enter.native="handleInputConfirm"
+              @blur="handleInputConfirm"
+            />
+            <el-button @click="showInput()">Add Role</el-button>
+            <!-- <el-button @click="revokeAllRole()">Revoke All</el-button> -->
+          </el-form-item>
+        </el-form>
+        <h4>Subscription Authentication</h4>
+        <hr class="split-line">
+        <div class="section-title">
+          <span>Subscription Authentication Mode</span>
+          <el-tooltip :content="subscriptionAuthenticationModeContent" class="item" effect="dark" placement="top">
+            <i class="el-icon-info"/>
+          </el-tooltip>
+        </div>
+        <el-select
+          v-model="subscriptionAuthenticationMode"
+          placeholder="Please select Authentication"
+          style="margin-top:20px;width:300px"
+          @change="handleSubscriptionAuthMode()">
+          <el-option
+            v-for="item in subscriptionAuthenticationModeOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"/>
+        </el-select>
+        <h4>Storage</h4>
+        <hr class="split-line">
+        <div class="section-title">
+          <span>Replication Factor</span>
+          <el-tooltip :content="replicationFactorContent" class="item" effect="dark" placement="top">
+            <i class="el-icon-info"/>
+          </el-tooltip>
+        </div>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="ensembelSize">
+            <md-input
+              v-model="form.ensembleSize"
+              class="md-input-style"
+              name="ensembelSize"
+              placeholder="Please input Ensemble"
+              @keyup.enter.native="handlePersistence">
+              Ensemble Size
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="writeQuorumSize">
+            <md-input
+              v-model="form.writeQuorumSize"
+              class="md-input-style"
+              name="writeQuorumSize"
+              placeholder="Please input Write Quorum Size"
+              @keyup.enter.native="handlePersistence">
+              Write Quorum Size
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="readQuorumSize">
+            <md-input
+              v-model="form.readQuorumSize"
+              class="md-input-style"
+              name="readQuorumSize"
+              placeholder="Please input Read Quorum Size"
+              @keyup.enter.native="handlePersistence">
+              Read Quorum Size
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="markDeleteMaxRate">
+            <md-input
+              v-model="form.markDeleteMaxRate"
+              class="md-input-style"
+              name="markDeleteMaxRate"
+              placeholder="Please input Delete Max Rate"
+              @keyup.enter.native="handlePersistence">
+              Mark Delete Max Rate
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="backlogQuotasLimit">
+            <span>Backlog Quotas Limit</span>
+            <el-tooltip :content="backlogQuotasLimitContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.backlogQuotasLimit"
+              class="md-input-style"
+              name="backlogQuotasLimit"
+              placeholder="Please input Backlog Quotas Limit"
+              @keyup.enter.native="handleBacklogQuota">
+              Backlog Quotas Limit
+            </md-input>
+          </el-form-item>
+          <el-form-item style="width:300px">
+            <span>Backlog Retention Policy</span>
+            <el-tooltip :content="backlogRententionPolicyContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <br>
+            <el-select
+              v-model="form.backlogRententionPolicy"
+              placeholder="Please select backlog rentention policy"
+              style="margin-top:36px;width:400px"
+              @change="handleBacklogQuota()">
+              <el-option
+                v-for="item in backlogRententionPolicyOption"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"/>
+            </el-select>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="encryptionRequire">
+            <span>Encryption Require</span>
+            <el-tooltip :content="encryptionRequireContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <br>
+            <el-radio-group
+              v-model="form.encryptionRequireRadio"
+              size="medium"
+              style="margin-top:30px;width:300px"
+              @change="handleEncryption()">
+              <el-radio label="Enabled"/>
+              <el-radio label="Disabled"/>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item prop="deduplication">
+            <span>Deduplication</span>
+            <el-tooltip :content="deduplicationContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <br>
+            <el-radio-group
+              v-model="form.deduplicationRadio"
+              size="medium"
+              style="margin-top:30px;width:300px"
+              @change="handleDeduplication()">
+              <el-radio label="Enabled"/>
+              <el-radio label="Disabled"/>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+        <h4>Schema</h4>
+        <hr class="split-line">
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="autoUpdateStrategy">
+            <span>AutoUpdate Strategy</span>
+            <el-tooltip :content="autoUpdateStrategyContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <br>
+            <el-select
+              v-model="form.autoUpdateStrategy"
+              placeholder="Please select backlog autoUpdate strategy"
+              style="margin-top:30px;width:300px"
+              @change="handleSchemaAutoUpdateStrategy()">
+              <el-option
+                v-for="item in autoUpdateStrategyOption"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item prop="schemaValidationEnforced">
+            <span>Schema Validation Enforced</span>
+            <el-tooltip :content="schemaValidationEnforcedContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <br>
+            <el-radio-group
+              v-model="form.schemaValidationEnforcedRadio"
+              size="medium"
+              style="margin-top:39px;width:300px"
+              @change="handleSchemaValidationEnforced()">
+              <el-radio label="Enabled"/>
+              <el-radio label="Disabled"/>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+        <h4>Cleanup Policy</h4>
+        <hr class="split-line">
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="messageTTL">
+            <span>Message TTL(Unit Second)</span>
+            <el-tooltip :content="messageTTLContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.messageTTL"
+              class="md-input-style"
+              name="messageTTL"
+              placeholder="Please input Backlog Quotas Limit"
+              @keyup.enter.native="handleMessageTTL">
+              Default 0
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="retentionSize">
+            <span>Retention Size</span>
+            <el-tooltip :content="retentionSizeContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.retentionSize"
+              class="md-input-style"
+              name="retentionSize"
+              placeholder="Please input retention size"
+              @keyup.enter.native="handleRetention">
+              retention size default 0
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="retentionTime">
+            <span>Retention Time(Unit Minutes)</span>
+            <el-tooltip :content="retentionTimeContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.retentionTime"
+              class="md-input-style"
+              name="retentionTime"
+              placeholder="Please input Retention Time"
+              @keyup.enter.native="handleRetention">
+              Default 0
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="compactionThreshold">
+            <span>Compaction Threshold</span>
+            <el-tooltip :content="compactionThresholdContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.compactionThreshold"
+              class="md-input-style"
+              name="compactionThreshold"
+              placeholder="Please input retention size"
+              @keyup.enter.native="handleCompactionThreshold">
+              Default 0
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="offloadThreshold">
+            <span>Offload Threshold</span>
+            <el-tooltip :content="offloadThresholdContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.offloadThreshold"
+              class="md-input-style"
+              name="offloadThreshold"
+              placeholder="Please input Offload Threshold"
+              @keyup.enter.native="handleOffloadThreshold">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="offloadDeletionLag">
+            <span>Offload Deletion Lag</span>
+            <el-tooltip :content="offloadDeletionLagContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.offloadDeletionLag"
+              class="md-input-style"
+              name="offloadDeletionLag"
+              placeholder="Please input Retention Time"
+              @keyup.enter.native="handleOffloadDeletionLag">
+              Default -1
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <h4>Throttling</h4>
+        <hr class="split-line">
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="maxProducersPerTopic">
+            <span>Max Producers Per Topic</span>
+            <el-tooltip :content="maxProducersPerTopicContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.maxProducersPerTopic"
+              class="md-input-style"
+              name="maxProducersPerTopic"
+              placeholder="Please input max Producers"
+              @keyup.enter.native="handleMaxProducersPerTopic">
+              Default 0
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="maxConsumersPerTopic">
+            <span>Max Consumers Per Topic</span>
+            <el-tooltip :content="maxConsumersPerTopicContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.maxConsumersPerTopic"
+              class="md-input-style"
+              name="maxConsumersPerTopic"
+              placeholder="Please input max Consumers"
+              @keyup.enter.native="handleMaxConsumersPerTopic">
+              Default 0
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <el-form :inline="true" :model="form" :rules="rules" @submit.native.prevent>
+          <el-form-item prop="maxConsumerPerSub">
+            <span>Max Consumers Per Subscription</span>
+            <el-tooltip :content="maxConsumerPerSubContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.maxConsumerPerSub"
+              class="md-input-style"
+              name="maxConsumerPerSub"
+              placeholder="Please input max Consumers"
+              @keyup.enter.native="handleMaxConsuemrsPerSubscription">
+              Default 0
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <h4>Dispatch Rate</h4>
+        <hr class="split-line">
+        <span>Dispatch Rate Per Topic</span>
+        <el-tooltip :content="dispatchRatePerTopicContent" class="item" effect="dark" placement="top">
+          <i class="el-icon-info"/>
+        </el-tooltip>
+        <el-form :inline="true" :model="form" :rules="rules">
+          <el-form-item prop="dispatchRatePerTopicBytes">
+            <span>bytes/second</span>
+            <md-input
+              v-model="form.dispatchRatePerTopicBytes"
+              class="md-input-style"
+              name="dispatchRatePerTopicBytes"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerTopic">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="dispatchRatePerTopicMessage">
+            <span>message/second</span>
+            <md-input
+              v-model="form.dispatchRatePerTopicMessage"
+              class="md-input-style"
+              name="dispatchRatePerTopicMessage"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerTopic">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="dispatchRatePerTopicPeriod">
+            <span>period(Unit second)</span>
+            <md-input
+              v-model="form.dispatchRatePerTopicPeriod"
+              class="md-input-style"
+              name="dispatchRatePerTopicPeriod"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerTopic">
+              Default -1
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <span>Dispatch Rate Per Subscription</span>
+        <el-tooltip :content="dispatchRatePerSubContent" class="item" effect="dark" placement="top">
+          <i class="el-icon-info"/>
+        </el-tooltip>
+        <el-form :inline="true" :model="form" :rules="rules" @submit.native.prevent>
+          <el-form-item prop="dispatchRatePerSubBytes">
+            <span>bytes/second</span>
+            <md-input
+              v-model="form.dispatchRatePerSubBytes"
+              class="md-input-style"
+              name="dispatchRatePerSubBytes"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerSub">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="dispatchRatePerSubMessage">
+            <span>message/second</span>
+            <md-input
+              v-model="form.dispatchRatePerSubMessage"
+              class="md-input-style"
+              name="dispatchRatePerSubMessage"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerSub">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="dispatchRatePerSubPeriod">
+            <span>period(Unit Second)</span>
+            <md-input
+              v-model="form.dispatchRatePerSubPeriod"
+              class="md-input-style"
+              name="dispatchRatePerSubPeriod"
+              placeholder="Please input dispatch rate"
+              @keyup.enter.native="handleDispatchRatePerSub">
+              Default -1
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <span>Subscribe Rate Per Consumer</span>
+        <el-tooltip :content="subscribeRatePerConsumerContent" class="item" effect="dark" placement="top">
+          <i class="el-icon-info"/>
+        </el-tooltip>
+        <el-form :inline="true" :model="form" :rules="rules" @submit.native.prevent>
+          <el-form-item prop="subscribeRatePerConsumerSub">
+            <span>message/second</span>
+            <md-input
+              v-model="form.subscribeRatePerConsumerSub"
+              class="md-input-style"
+              name="subscribeRatePerConsumerSub"
+              placeholder="Please input subscribe rate"
+              @keyup.enter.native="handleSubscribeRate">
+              Default -1
+            </md-input>
+          </el-form-item>
+          <el-form-item prop="subscribeRatePerConsumerPeriod">
+            <span>period(Unit Second)</span>
+            <md-input
+              v-model="form.subscribeRatePerConsumerPeriod"
+              class="md-input-style"
+              name="subscribeRatePerConsumerPeriod"
+              placeholder="Please input subscribe rate"
+              @keyup.enter.native="handleSubscribeRate">
+              Default -1
+            </md-input>
+          </el-form-item>
+        </el-form>
+        <h4>Anti Affinity</h4>
+        <hr class="split-line">
+        <el-form :inline="true" :model="form" :rules="rules" @submit.native.prevent>
+          <el-form-item prop="antiAffinityGroup">
+            <span>Anti Affinity Group</span>
+            <el-tooltip :content="antiAffinityGroupContent" class="item" effect="dark" placement="top">
+              <i class="el-icon-info"/>
+            </el-tooltip>
+            <md-input
+              v-model="form.antiAffinityGroup"
+              class="md-input-style"
+              name="antiAffinityGroup"
+              placeholder="Please input Anti Affinity Group"
+              @keyup.enter.native="handleAntiAffinityGroup"/>
+          </el-form-item>
+        </el-form>
+        <h4>Danager Zone</h4>
+        <hr class="danger-line">
+        <el-button type="danger" class="button" @click="deleteNamespace">Delete Namespace</el-button>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+<script>
+import { fetchTenants } from '@/api/tenants'
+import {
+  fetchNamespaces,
+  fetchNamespacePolicies,
+  getPermissions,
+  getPersistence,
+  getRetention,
+  setClusters,
+  grantPermissions,
+  revokePermissions,
+  setSubscriptionAuthMode,
+  setPersistence,
+  setBacklogQuota,
+  setEncryptionRequired,
+  setDeduplication,
+  setSchemaAutoupdateStrategy,
+  setSchemaValidationEnforced,
+  setMessageTtl,
+  setRetention,
+  setCompactionThreshold,
+  setOffloadThreshold,
+  setOffloadDeletionLag,
+  setMaxProducersPerTopic,
+  setMaxConsumersPerTopic,
+  setMaxConsumersPerSubscription,
+  setDispatchRate,
+  setSubscriptionDispatchRate,
+  setSubscribeRate,
+  setAntiAffinityGroup,
+  splitBundle,
+  unloadBundle,
+  unload,
+  clearBacklog,
+  deleteNamespace
+} from '@/api/namespaces'
+import { fetchBrokerStats } from '@/api/brokerStats'
+import { fetchTopicsByPulsarManager } from '@/api/topics'
+import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
+import ElDragSelect from '@/components/DragSelect' // base on element-ui
+import MdInput from '@/components/MDinput'
+const defaultForm = {
+  tenant: '',
+  namespace: ''
+}
+export default {
+  name: 'NamespaceInfo',
+  components: {
+    ElDragSelect,
+    MdInput,
+    Pagination
+  },
+  data() {
+    // const validate = (rule, value, callback) => {
+    //   if (value.length !== 6) {
+    //     callback(new Error('请输入六个字符'))
+    //   } else {
+    //     callback()
+    //   }
+    // }
+    return {
+      postForm: Object.assign({}, defaultForm),
+      tenantNamespace: '',
+      tenantsListOptions: [],
+      namespacesListOptions: [],
+      activeName: 'overview',
+      namespaceStats: [{
+        inMsg: 0,
+        outMsg: 0,
+        inBytes: 0,
+        outBytes: 0
+      }],
+      replicatedClustersContent: 'This is Allowed Clusters',
+      replicationClustersValue: [],
+      replicationClustersOptions: [],
+      dynamicValidateForm: {
+        domains: [{
+          value: ''
+        }],
+        email: ''
+      },
+      dynamicTags: [],
+      inputVisible: false,
+      inputValue: '',
+      roleValue: [],
+      roleMap: {},
+      roleMapOptions: {},
+      roleOptions: [{
+        value: 'consume',
+        label: 'consume'
+      }, {
+        value: 'produce',
+        label: 'produce'
+      }, {
+        value: 'functions',
+        label: 'functions'
+      }],
+      authorizationContent: 'This is AuthorizationContent',
+      subscriptionAuthenticationMode: '',
+      subscriptionAuthenticationModeContent: 'This is subscriptionAuthenticationMode',
+      subscriptionAuthenticationModeOptions: [{
+        value: 'None',
+        label: 'None'
+      }, {
+        value: 'Prefix',
+        label: 'Prefix'
+      }],
+      replicationFactorContent: 'This is replicationFactorContent',
+      form: {
+        ensembelSize: '',
+        writeQuorumSize: '',
+        readQuorumSize: '',
+        markDeleteMaxRate: '',
+        backlogQuotasLimit: '',
+        backlogRententionPolicy: '',
+        encryptionRequire: '',
+        deduplication: '',
+        autoUpdateStrategy: '',
+        messageTTL: '',
+        retentionTime: '',
+        encryptionRequireRadio: 'Disabled',
+        deduplicationRadio: 'Disabled',
+        schemaValidationEnforcedRadio: 'Disabled',
+        dispatchRatePerTopicBytes: '',
+        dispatchRatePerTopicMessage: '',
+        dispatchRatePerTopicPeriod: '',
+        dispatchRatePerSubBytes: '',
+        antiAffinityGroup: '',
+        dispatchRatePerSubMessage: '',
+        dispatchRatePerSubPeriod: '',
+        subscribeRatePerConsumerSub: '',
+        subscribeRatePerConsumerPeriod: '',
+        maxConsumerPerSub: ''
+      },
+      rules: {
+        // ensembelSize: [{ required: true, message: 'EnsembelSize is greater more than 0', trigger: 'blur' }]
+      },
+      backlogQuotasLimitContent: 'This is backlogQuotasLimitContent',
+      backlogRententionPolicyContent: 'This is backlogRententionPolicyContent',
+      backlogRententionPolicyRadio: 'consumer_backlog_eviction',
+      backlogRententionPolicyOption: [{
+        value: 'consumer_backlog_eviction',
+        label: 'consumer_backlog_eviction'
+      }, {
+        value: 'producer_exception',
+        label: 'producer_exception'
+      }, {
+        value: 'producer_request_hold',
+        lable: 'producer_request_hold'
+      }],
+      encryptionRequireContent: 'This is encryptionRequireContent',
+      encryptionRequireOption: [{
+        value: 'Enabled',
+        label: 'Enabled'
+      }, {
+        value: 'Disabled',
+        label: 'Disabled'
+      }],
+      deduplicationContent: 'This is deduplicationContent',
+      deduplication: '',
+      deduplicationOption: [{
+        value: 'Enabled',
+        label: 'Enabled'
+      }, {
+        value: 'Disabled',
+        label: 'Disabled'
+      }],
+      autoUpdateStrategyContent: 'This is schemaValidationEnforced',
+      autoUpdateStrategyOption: [{
+        value: 'Full',
+        label: 'Full'
+      }, {
+        value: 'Forward',
+        label: 'Forward'
+      }, {
+        value: 'Backward',
+        label: 'Backward'
+      }, {
+        value: 'AlwaysCompatible',
+        label: 'Always Compatible'
+      }, {
+        value: 'AutoUpdateDisabled',
+        label: 'AutoUpdateDisabled'
+      }, {
+        value: 'BackwardTransitive',
+        label: 'BackwardTransitive'
+      }, {
+        value: 'ForwardTransitive',
+        label: 'ForwardTransitive'
+      }, {
+        value: 'FullTransitive',
+        label: 'FullTransitive'
+      }],
+      schemaValidationEnforcedContent: 'This is schemaValidationEnforcedContent',
+      schemaValidationEnforced: '',
+      messageTTLContent: 'This is messageTTLContent',
+      retentionSizeContent: 'This is retentionSizeContent',
+      retentionTimeContent: 'This is retentionTimeContent',
+      compactionThresholdContent: 'This is compactionThresholdContent',
+      offloadThresholdContent: 'This is offloadThresholdContent',
+      offloadDeletionLagContent: 'This is offloadDeletionLagContent',
+      maxProducersPerTopicContent: 'This is maxProducersPerTopicContent',
+      maxConsumersPerTopicContent: 'This is maxConsumersPerTopicContent',
+      maxConsumerPerSubContent: 'This is maxConsumerPerSubContent',
+      dispatchRatePerTopicContent: 'This is dispatchRatePerTopicContent',
+      dispatchRatePerSubContent: 'This is dispatchRatePerSubContent',
+      subscribeRatePerConsumerContent: 'This is subscribeRatePerConsumerContent',
+      antiAffinityGroupContent: 'This is antiAffinityGroupContent',
+      tableKey: 0,
+      topicsListLoading: true,
+      topicsTableKey: 0,
+      brokerStats: null,
+      topics: {},
+      localList: [],
+      topicsList: [],
+      topicsTotal: 0,
+      // total: 0,
+      topicsListQuery: {
+        page: 1,
+        limit: 10
+      },
+      firstInit: false
+    }
+  },
+  created() {
+    this.postForm.tenant = this.$route.params && this.$route.params.tenant
+    this.postForm.namespace = this.$route.params && this.$route.params.namespace
+    this.tenantNamespace = this.postForm.tenant + '/' + this.postForm.namespace
+    this.firstInit = true
+    this.getRemoteTenantsList()
+    this.getNamespacesList(this.postForm.tenant)
+    this.getPolicies(this.tenantNamespace)
+    this.initPermissions(this.tenantNamespace)
+    this.initPersistence(this.tenantNamespace)
+    this.initRetention(this.tenantNamespace)
+    this.getStats()
+  },
+  methods: {
+    getStats() {
+      this.getTopics()
+    },
+    getTopics() {
+      fetchTopicsByPulsarManager(this.postForm.tenant, this.postForm.namespace).then(response => {
+        if (!response.data) return
+        for (var i in response.data.topics) {
+          this.topics[response.data.topics[i]['topic']] = i
+          this.topicsList.push({
+            'topic': response.data.topics[i]['topic'],
+            'partitions': response.data.topics[i]['partitions'],
+            'producers': 0,
+            'subscriptions': 0,
+            'inMsg': 0,
+            'outMsg': 0,
+            'inBytes': 0,
+            'outBytes': 0,
+            'storageSize': 0
+          })
+        }
+        fetchBrokerStats().then(res => {
+          if (!res.data) return
+          this.brokerStats = res.data
+          if (this.brokerStats.hasOwnProperty(this.tenantNamespace)) {
+            for (var bundle in this.brokerStats[this.tenantNamespace]) {
+              for (var p in this.brokerStats[this.tenantNamespace][bundle]) {
+                for (var topic in this.brokerStats[this.tenantNamespace][bundle][p]) {
+                  this.namespaceStats[0].inMsg += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateIn
+                  this.namespaceStats[0].outMsg += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateOut
+                  this.namespaceStats[0].inBytes += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputIn
+                  this.namespaceStats[0].outBytes += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputOut
+                  var topicName = topic.split('://')[1].split('/')[2]
+                  var isPartition = false
+                  if (topicName.indexOf('-partition-') > 0) {
+                    topicName = topicName.split('-partition-')[0]
+                    isPartition = true
+                  }
+                  if (this.topics.hasOwnProperty(topicName)) {
+                    if (isPartition) {
+                      this.topicsList[this.topics[topicName]]['producers'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].producerCount
+                      for (var psub in this.brokerStats[this.tenantNamespace][bundle][p][topic].subscriptions) {
+                        this.topicsList[this.topics[topicName]]['subscriptions'] += Object.keys(this.brokerStats[this.tenantNamespace][bundle][p][topic].subscriptions[psub].consumers).length
+                      }
+                      this.topicsList[this.topics[topicName]]['inMsg'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateIn
+                      this.topicsList[this.topics[topicName]]['outMsg'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateOut
+                      this.topicsList[this.topics[topicName]]['inBytes'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputIn
+                      this.topicsList[this.topics[topicName]]['outBytes'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputOut
+                      this.topicsList[this.topics[topicName]]['storageSize'] += this.brokerStats[this.tenantNamespace][bundle][p][topic].storageSize
+                    } else {
+                      this.topicsList[this.topics[topicName]]['producers'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].producerCount
+                      for (var sub in this.brokerStats[this.tenantNamespace][bundle][p][topic].subscriptions) {
+                        this.topicsList[this.topics[topicName]]['subscriptions'] = Object.keys(this.brokerStats[this.tenantNamespace][bundle][p][topic].subscriptions[sub].consumers).length
+                      }
+                      this.topicsList[this.topics[topicName]]['inMsg'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateIn
+                      this.topicsList[this.topics[topicName]]['outMsg'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].msgRateOut
+                      this.topicsList[this.topics[topicName]]['inBytes'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputIn
+                      this.topicsList[this.topics[topicName]]['outBytes'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].msgThroughputOut
+                      this.topicsList[this.topics[topicName]]['storageSize'] = this.brokerStats[this.tenantNamespace][bundle][p][topic].storageSize
+                    }
+                  }
+                }
+              }
+            }
+          }
+        })
+        this.topicsListLoading = false
+      })
+    },
+    getPolicies(tenantNamespace) {
+      fetchNamespacePolicies(tenantNamespace).then(response => {
+        if (!response.data) return
+        this.initPoliciesOptions(response.data)
+      })
+    },
+    initPersistence(tenantNamespace) {
+      getPersistence(tenantNamespace).then(response => {
+        if (!response.data) return
+        this.form.ensembleSize = String(response.data.bookkeeperEnsemble)
+        this.form.writeQuorumSize = String(response.data.bookkeeperWriteQuorum)
+        this.form.readQuorumSize = String(response.data.bookkeeperAckQuorum)
+        this.form.markDeleteMaxRate = String(response.data.managedLedgerMaxMarkDeleteRate)
+      })
+    },
+    initPermissions(tenantNamespace) {
+      getPermissions(tenantNamespace).then(response => {
+        if (!response.data) return
+        for (var key in response.data) {
+          this.roleMap[key] = response.data.key
+          this.roleMapOptions[key] = this.roleOptions
+        }
+      })
+    },
+    initRetention(tenantNamespace) {
+      getRetention(tenantNamespace).then(response => {
+        if (!response.data) return
+        this.form.retentionSize = String(response.data.retentionSizeInMB)
+        this.form.retentionTime = String(response.data.retentionTimeInMinutes)
+      })
+    },
+    initPoliciesOptions(policies) {
+      for (var i = 0; i < policies.replication_clusters.length; i++) {
+        this.replicationClustersOptions.push({
+          value: policies.replication_clusters[i],
+          label: policies.replication_clusters[i]
+        })
+      }
+      this.replicationClustersValue = policies.replication_clusters
+      this.subscriptionAuthenticationMode = policies.subscription_auth_mode
+      this.form.backlogQuotasLimit = String(policies.backlog_quota_map.destination_storage.limit)
+      this.form.backlogRententionPolicy = String(policies.backlog_quota_map.destination_storage.policy)
+      if (policies.encryption_required) {
+        this.form.encryptionRequireRadio = 'Enabled'
+      }
+      if (policies.hasOwnProperty('deduplicationRadio')) {
+        this.form.deduplicationRadio = policies.deduplicationRadio
+      }
+      this.form.autoUpdateStrategy = policies.schema_auto_update_compatibility_strategy
+      if (policies.schema_validation_enforced) {
+        this.form.schemaValidationEnforcedRadio = 'Enabled'
+      }
+      this.form.messageTTL = String(policies.message_ttl_in_seconds)
+      this.form.compactionThreshold = String(policies.compaction_threshold)
+      this.form.offloadThreshold = String(policies.offload_threshold)
+      if (policies.hasOwnProperty('offload_deletion_lag_ms')) {
+        this.form.offloadDeletionLag = String(policies.offload_deletion_lag_ms)
+      }
+      this.form.maxProducersPerTopic = String(policies.max_producers_per_topic)
+      this.form.maxConsumersPerTopic = String(policies.max_consumers_per_topic)
+      this.form.maxConsumerPerSub = String(policies.max_consumers_per_subscription)
+      for (var t in policies.topicDispatchRate) {
+        this.form.dispatchRatePerTopicMessage = String(policies.topicDispatchRate[t].dispatchThrottlingRateInMsg)
+        this.form.dispatchRatePerTopicBytes = String(policies.topicDispatchRate[t].dispatchThrottlingRateInByte)
+        this.form.dispatchRatePerTopicPeriod = String(policies.topicDispatchRate[t].ratePeriodInSecond)
+      }
+      for (var s in policies.subscriptionDispatchRate) {
+        this.form.dispatchRatePerSubBytes = String(policies.subscriptionDispatchRate[s].dispatchThrottlingRateInByte)
+        this.form.dispatchRatePerSubMessage = String(policies.subscriptionDispatchRate[s].dispatchThrottlingRateInMsg)
+        this.form.dispatchRatePerSubPeriod = String(policies.subscriptionDispatchRate[s].ratePeriodInSecond)
+      }
+      for (var c in policies.clusterSubscribeRate) {
+        this.form.subscribeRatePerConsumerSub = String(policies.clusterSubscribeRate[c].subscribeThrottlingRatePerConsumer)
+        this.form.subscribeRatePerConsumerPeriod = String(policies.clusterSubscribeRate[c].ratePeriodInSecond)
+      }
+      if (policies.hasOwnProperty('antiAffinityGroup')) {
+        this.form.antiAffinityGroup = policies.antiAffinityGroup
+      }
+      // this.listQuery.limit = policies.bundles.numBundles
+      // this.listQuery.page = 1
+      // this.total = policies.bundles.numBundles
+      for (var n = 0; n < policies.bundles.numBundles; n++) {
+        this.localList.push({ 'bundle': policies.bundles.boundaries[n] + '_' + policies.bundles.boundaries[n + 1] })
+      }
+    },
+    handleClick(tab, event) {
+      console.log(tab, event)
+    },
+    getRemoteTenantsList() {
+      fetchTenants().then(response => {
+        if (!response.data) return
+        for (var i = 0; i < response.data.total; i++) {
+          this.tenantsListOptions.push(response.data.data[i].tenant)
+        }
+      })
+    },
+    getNamespacesList(tenant) {
+      fetchNamespaces(tenant, this.query).then(response => {
+        let namespace = []
+        this.namespacesListOptions = []
+        if (this.firstInit) {
+          this.firstInit = false
+        } else {
+          this.postForm.namespace = ''
+        }
+        for (var i = 0; i < response.data.data.length; i++) {
+          namespace = response.data.data[i].namespace
+          this.namespacesListOptions.push(namespace)
+        }
+      })
+    },
+    getNamespaceInfo(tenant, namespace) {
+      this.$router.push({ path: '/management/namespaces/' + tenant + '/' + namespace + '/namespace' })
+    },
+    handleFilterBundle() {
+    },
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          alert('submit!')
+        } else {
+          console.log('error submit!!')
+          return false
+        }
+      })
+    },
+    resetForm(formName) {
+      this.$refs[formName].resetFields()
+    },
+    // removeDomain(item) {
+    //   var index = this.dynamicValidateForm.domains.indexOf(item)
+    //   if (index !== -1) {
+    //     this.dynamicValidateForm.domains.splice(index, 1)
+    //   }
+    // },
+    // addDomain() {
+    //   this.dynamicValidateForm.domains.push({
+    //     value: '',
+    //     key: Date.now()
+    //   })
+    // },
+    handleClose(tag) {
+      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
+      revokePermissions(this.tenantNamespace, tag).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Add success',
+          type: 'success',
+          duration: 3000
+        })
+        delete this.roleMap[tag]
+        delete this.roleMapOptions[tag]
+      })
+    },
+    showInput() {
+      this.inputVisible = true
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus()
+      })
+    },
+    handleInputConfirm() {
+      const inputValue = this.inputValue
+      if (inputValue) {
+        if (this.roleMap.hasOwnProperty(inputValue)) {
+          this.$message({
+            message: 'This role is exist',
+            type: 'error'
+          })
+          this.inputVisible = false
+          this.inputValue = ''
+          return
+        }
+        grantPermissions(this.currentNamespace, inputValue, this.roleMap[inputValue]).then(response => {
+          this.$notify({
+            title: 'success',
+            message: 'Add success',
+            type: 'success',
+            duration: 3000
+          })
+          this.dynamicTags.push(inputValue)
+          this.roleMap[inputValue] = []
+          this.roleMapOptions[inputValue] = this.roleOptions
+        })
+      }
+      this.inputVisible = false
+      this.inputValue = ''
+    },
+    handleChangeOptions() {
+      console.log(this.roleMap)
+      this.$forceUpdate()
+    },
+    revokeAllRole() {
+    },
+    handlePersistence() {
+      const data = {
+        'bookkeeperAckQuorum': parseInt(this.form.readQuorumSize),
+        'bookkeeperEnsemble': parseInt(this.form.ensembleSize),
+        'bookkeeperWriteQuorum': parseInt(this.form.writeQuorumSize),
+        'managedLedgerMaxMarkDeleteRate': parseInt(this.form.markDeleteMaxRate)
+      }
+      setPersistence(this.tenantNamespace, data).then(response => {
+        this.dialogFormVisible = false
+        this.$notify({
+          title: 'success',
+          message: 'Set persistence success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleBacklogQuota() {
+      const data = {
+        'limit': this.form.backlogQuotasLimit,
+        'policy': this.form.backlogRententionPolicy
+      }
+      setBacklogQuota(this.tenantNamespace, data).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Add Backlog Quota success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleSplitBundle(row) {
+      splitBundle(this.tenantNamespace, row.bundle, false).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'splitBundle success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+        this.localList = []
+        this.getPolicies(this.tenantNamespace)
+      })
+    },
+    handleUnloadAll() {
+      unload(this.tenantNamespace).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Unload success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+        this.localList = []
+        this.getPolicies(this.tenantNamespace)
+      })
+    },
+    handleUnloadBundle(row) {
+      unloadBundle(this.tenantNamespace, row.bundle).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Unload success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+      this.localList = []
+      this.getPolicies(this.tenantNamespace)
+    },
+    hanldeClearAllBacklog() {
+      clearBacklog(this.tenantNamespace).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'clearBacklog success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleReplicationsClusters() {
+      setClusters(this.tenantNamespace, this.replicationClustersValue).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Add clusters success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleSubscriptionAuthMode() {
+      var subAuthMode = 0
+      if (this.subscriptionAuthenticationMode === 'Prefix') {
+        subAuthMode = 1
+      }
+      setSubscriptionAuthMode(this.tenantNamespace, subAuthMode).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleEncryption() {
+      var encryptionRequire = false
+      if (this.form.encryptionRequireRadio === 'Enabled') {
+        encryptionRequire = true
+      }
+      setEncryptionRequired(this.tenantNamespace, encryptionRequire).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleDeduplication() {
+      var deduplication = false
+      if (this.form.deduplicationRadio === 'Enabled') {
+        deduplication = true
+      }
+      setDeduplication(this.tenantNamespace, deduplication).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set deduplication success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleSchemaAutoUpdateStrategy() {
+      console.log(this.form.autoUpdateStrategy)
+      var strategy = 3
+      if (this.form.autoUpdateStrategy === 'AutoUpdateDisabled') {
+        strategy = 0
+      } else if (this.form.autoUpdateStrategy === 'Backward') {
+        strategy = 1
+      } else if (this.form.autoUpdateStrategy === 'Forward') {
+        strategy = 2
+      } else if (this.form.autoUpdateStrategy === 'Full') {
+        strategy = 3
+      } else if (this.form.autoUpdateStrategy === 'AlwaysCompatible') {
+        strategy = 4
+      } else if (this.form.autoUpdateStrategy === 'BackwardTransitive') {
+        strategy = 5
+      } else if (this.form.autoUpdateStrategy === 'ForwardTransitive') {
+        strategy = 6
+      } else if (this.form.autoUpdateStrategy === 'FullTransitive') {
+        strategy = 7
+      }
+      setSchemaAutoupdateStrategy(this.tenantNamespace, strategy).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set SchemaAutoupdateStrategy success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleSchemaValidationEnforced() {
+      var schemaValidation = false
+      if (this.form.schemaValidationEnforcedRadio === 'Enabled') {
+        schemaValidation = true
+      }
+      setSchemaValidationEnforced(this.tenantNamespace, schemaValidation).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set SchemaValidationEnforced success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleMessageTTL() {
+      setMessageTtl(this.tenantNamespace, parseInt(this.form.messageTTL)).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set messageTTL success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleRetention() {
+      const data = { 'retentionSizeInMB': parseInt(this.form.retentionSize), 'retentionTimeInMinutes': parseInt(this.form.retentionTime) }
+      setRetention(this.tenantNamespace, data).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set Retention success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleCompactionThreshold() {
+      setCompactionThreshold(this.tenantNamespace, this.form.compactionThreshold).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set threshold success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleOffloadThreshold() {
+      setOffloadThreshold(this.tenantNamespace, this.form.offloadThreshold).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set threshold success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleOffloadDeletionLag() {
+      setOffloadDeletionLag(this.tenantNamespace, this.form.offloadDeletionLag).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set DeletionLag success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleMaxProducersPerTopic() {
+      setMaxProducersPerTopic(this.tenantNamespace, this.form.maxProducersPerTopic).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set max producers per topic success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleMaxConsumersPerTopic() {
+      setMaxConsumersPerTopic(this.tenantNamespace, this.form.maxConsumersPerTopic).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set max consumers per topic success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleMaxConsuemrsPerSubscription() {
+      setMaxConsumersPerSubscription(this.tenantNamespace, this.form.maxConsumerPerSub).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set max subscription per topic success',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleDispatchRatePerTopic() {
+      const data = {
+        'dispatchThrottlingRateInByte': this.form.dispatchRatePerTopicBytes,
+        'ratePeriodInSecond': this.form.dispatchRatePerTopicPeriod,
+        'dispatchThrottlingRateInMsg': this.form.dispatchRatePerTopicMessage
+      }
+      setDispatchRate(this.tenantNamespace, data).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'set DispatchRate success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleDispatchRatePerSub() {
+      const data = {
+        'dispatchThrottlingRateInByte': this.form.dispatchRatePerSubBytes,
+        'ratePeriodInSecond': this.form.dispatchRatePerSubPeriod,
+        'dispatchThrottlingRateInMsg': this.form.dispatchRatePerSubMessage
+      }
+      setSubscriptionDispatchRate(this.tenantNamespace, data).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'set subscription dispatchRate success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleSubscribeRate() {
+      const data = {
+        'subscribeThrottlingRatePerConsumer': this.form.subscribeRatePerConsumerSub,
+        'ratePeriodInSecond': this.form.subscribeRatePerConsumerPeriod
+      }
+      setSubscribeRate(this.tenantNamespace, data).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'set subscription dispatchRate success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    handleAntiAffinityGroup() {
+      setAntiAffinityGroup(this.tenantNamespace, this.form.antiAffinityGroup).then(response => {
+        this.$notify({
+          title: 'success',
+          message: 'Set AntiAffinityGroup success for namespace',
+          type: 'success',
+          duration: 3000
+        })
+      })
+    },
+    deleteNamespace() {
+      deleteNamespace(this.tenantNamespace).then((response) => {
+        this.$notify({
+          title: 'success',
+          message: 'delete success',
+          type: 'success',
+          duration: 2000
+        })
+        this.$router.push({ path: '/management/namespaces/' + this.postForm.tenant })
+      })
+    }
+  }
+}
+</script>
+
+<style>
+.role-el-tag {
+  background-color: #fff !important;
+  border: none !important;
+  font-size: 16px !important;
+  color: black !important;
+}
+.split-line {
+  background: #e6e9f3;
+  border: none;
+  height: 1px;
+}
+.danger-line {
+  background: red;
+  border: none;
+  height: 1px;
+}
+.md-input-style {
+  width: 300px;
+  margin-top: 20px;
+}
+</style>
diff --git a/front-end/src/views/management/namespaces/policies.vue b/front-end/src/views/management/namespaces/policies.vue
deleted file mode 100644
index 8dd58c9..0000000
--- a/front-end/src/views/management/namespaces/policies.vue
+++ /dev/null
@@ -1,247 +0,0 @@
-<template>
-  <div class="app-container">
-
-    <el-row :gutter="8">
-      <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
-        <el-table
-          :key="tableKey"
-          :data="list"
-          border
-          fit
-          highlight-current-row
-          style="width: 100%;">
-          <el-table-column :label="$t('table.policies')" min-width="150px" align="center">
-            <template slot-scope="scope">
-              <span class="link-type" @click="getNamespacePolicie()">{{ scope.row.policies }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column :label="$t('table.description')" min-width="150px" align="center">
-            <template slot-scope="scope">
-              <span>{{ scope.row.description }}</span>
-            </template>
-          </el-table-column>
-        </el-table>
-        <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="pagePolicies" />
-      </el-col>
-      <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="margin-bottom:30px;">
-        <jsonEditor :value="jsonValue"/>
-        <template>
-          <el-button type="primary" style="float: right; margin-top: 10px" @click="handleDelete()">{{ $t('table.update') }}
-          </el-button>
-        </template>
-      </el-col>
-    </el-row>
-
-    <el-dialog :visible.sync="dialogFormVisible">
-      <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
-        <el-form-item :label="$t('table.namespace')" prop="namespace">
-          <el-input v-model="temp.namespace"/>
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
-        <el-button type="primary" @click="createData()">{{ $t('table.confirm') }}</el-button>
-      </div>
-    </el-dialog>
-
-  </div>
-</template>
-
-<script>
-import { updateTenant } from '@/api/tenants'
-import waves from '@/directive/waves' // Waves directive
-import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
-import JsonEditor from '@/components/JsonEditor'
-
-export default {
-  name: 'Namespaces',
-  components: {
-    Pagination,
-    JsonEditor
-  },
-  directives: { waves },
-  data() {
-    return {
-      tableKey: 0,
-      jsonValue: {},
-      tenant: '',
-      namespace: '',
-      list: null,
-      policiesList: policiesList,
-      total: 0,
-      listQuery: {
-        page: 1,
-        limit: 10
-      },
-      temp: {
-        namespace: ''
-      },
-      dialogFormVisible: false,
-      dialogStatus: '',
-      textMap: {
-        update: 'Edit',
-        create: 'Create'
-      },
-      rules: {
-        namespace: [{ required: true, message: 'namespace is required', trigger: 'blur' }]
-      }
-    }
-  },
-  created() {
-    this.tenant = this.$route.params && this.$route.params.tenant
-    this.namespace = this.$route.params && this.$route.params.namespace
-    this.pagePolicies()
-    // this.getNamespaces()
-    // this.getNamespacePolicies()
-  },
-  methods: {
-    pagePolicies() {
-      this.total = this.policiesList.length
-      this.list = this.policiesList.slice((this.listQuery.page - 1) * 10, this.listQuery.page * 10)
-    },
-    handleUpdate(row) {
-      this.temp = Object.assign({}, row) // copy obj
-      this.dialogStatus = 'update'
-      this.dialogFormVisible = true
-      this.$nextTick(() => {
-        this.$refs['dataForm'].clearValidate()
-      })
-    },
-    getNamespacePolicie() {
-
-    },
-    updateData() {
-      this.$refs['dataForm'].validate((valid) => {
-        if (valid) {
-          const tempData = Object.assign({}, this.temp)
-          updateTenant(this.temp.tenant, tempData).then(() => {
-            for (const v of this.list) {
-              if (v.tenant === this.temp.tenant) {
-                const index = this.list.indexOf(v)
-                this.list.splice(index, 1, this.temp)
-                break
-              }
-            }
-            this.dialogFormVisible = false
-            this.$notify({
-              title: 'success',
-              message: 'update success',
-              type: 'success',
-              duration: 2000
-            })
-          })
-        }
-      })
-    },
-    handleDelete(row) {
-      this.$notify({
-        title: 'success',
-        message: 'delete success',
-        type: 'success',
-        duration: 2000
-      })
-      const index = this.list.indexOf(row)
-      this.list.splice(index, 1)
-    }
-  }
-}
-const policiesList = [
-  {
-    'policies': 'maxConsumersPerSubscription',
-    'description': 'maxConsumersPerSubscription'
-  },
-  {
-    'policies': 'compactionThreshold',
-    'description': 'compactionThreshold'
-  },
-  {
-    'policies': 'antiAffinity',
-    'description': 'antiAffinity'
-  },
-  {
-    'policies': 'backlogQuota',
-    'description': 'backlogQuota'
-  },
-  {
-    'policies': 'clearBacklog',
-    'description': 'clearBacklog'
-  },
-  {
-    'policies': 'deduplication',
-    'description': 'deduplication'
-  },
-  {
-    'policies': 'dispatchRate',
-    'description': 'dispatchRate'
-  },
-  {
-    'policies': 'encryptionRequired',
-    'description': 'encryptionRequired'
-  },
-  {
-    'policies': 'maxConsumersPerTopic',
-    'description': 'maxConsumersPerTopic'
-  },
-  {
-    'policies': 'maxProducersPerTopic',
-    'description': 'maxProducersPerTopic'
-  },
-  {
-    'policies': 'messageTTL',
-    'description': 'messageTTL'
-  },
-  {
-    'policies': 'offloadDeletionLagMs',
-    'description': 'offloadDeletionLagMs'
-  },
-  {
-    'policies': 'offloadThreshold',
-    'description': 'offloadThreshold'
-  },
-  {
-    'policies': 'permissions',
-    'description': 'permissions'
-  },
-  {
-    'policies': 'persistence',
-    'description': 'persistence'
-  },
-  {
-    'policies': 'replication',
-    'description': 'replication'
-  },
-  {
-    'policies': 'retention',
-    'description': 'retention'
-  },
-  {
-    'policies': 'schemaAutoUpdateCompatibilityStrategy',
-    'description': 'schemaAutoUpdateCompatibilityStrategy'
-  },
-  {
-    'policies': 'subscribeRate',
-    'description': 'subscribeRate'
-  },
-  {
-    'policies': 'subscriptionAuthMode',
-    'description': 'subscriptionAuthMode'
-  },
-  {
-    'policies': 'subscriptionDispatchRate',
-    'description': 'subscriptionDispatchRate'
-  },
-  {
-    'policies': 'unload',
-    'description': 'unload'
-  },
-  {
-    'policies': 'unsubscribe',
-    'description': 'unsubscribe'
-  },
-  {
-    'policies': 'bundle',
-    'description': 'bundle'
-  }
-]
-</script>
-
diff --git a/gradle.properties b/gradle.properties
index cc5f12a..90f3c91 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -8,8 +8,9 @@
 pageHelperVersion=1.2.4
 mockitoVersion=1.10.19
 guavaVersion=21.0
-pulsarVersion=2.5.0-1b64a6e1f
+pulsarVersion=2.5.0-2cc34afc0
 swagger2Version=2.9.2
 swaggeruiVersion=2.9.2
 apiMockitoVersion=1.7.1
-mockitoJunit4Version=1.7.1
\ No newline at end of file
+mockitoJunit4Version=1.7.1
+gsonVersion=2.8.2
diff --git a/src/main/java/com/manager/pulsar/controller/NamespacesController.java b/src/main/java/com/manager/pulsar/controller/NamespacesController.java
index 9ab75c9..f1abca5 100644
--- a/src/main/java/com/manager/pulsar/controller/NamespacesController.java
+++ b/src/main/java/com/manager/pulsar/controller/NamespacesController.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.Maps;
 import com.manager.pulsar.entity.NamespaceEntity;
 import com.manager.pulsar.entity.NamespacesRepository;
+import com.manager.pulsar.service.NamespacesService;
 import io.swagger.annotations.*;
 import org.hibernate.validator.constraints.Range;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -45,6 +46,9 @@
     @Autowired
     private NamespacesRepository namespacesRepository;
 
+    @Autowired
+    private NamespacesService namespacesService;
+
     @ApiOperation(value = "Get the list of existing namespaces, support paging, the default is 10 per page")
     @ApiResponses({
             @ApiResponse(code = 200, message = "ok"),
diff --git a/src/main/java/com/manager/pulsar/controller/TopicsController.java b/src/main/java/com/manager/pulsar/controller/TopicsController.java
new file mode 100644
index 0000000..d56b9ac
--- /dev/null
+++ b/src/main/java/com/manager/pulsar/controller/TopicsController.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.controller;
+
+import com.manager.pulsar.service.TopicsService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.hibernate.validator.constraints.Range;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.Size;
+import java.util.Map;
+
+/**
+ * Topics rest api class.
+ */
+@RequestMapping(value = "/pulsar-manager/admin/v2")
+@Api(description = "Support more flexible queries to namespaces.")
+@Validated
+@RestController
+public class TopicsController {
+
+    @Autowired
+    private TopicsService topicsService;
+
+    @ApiOperation(value = "Query topic info by tenant and namespace and topic")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "ok"),
+            @ApiResponse(code = 500, message = "Internal server error")
+    })
+    @RequestMapping(value = "/topics/{tenant}/{namespace}", method = RequestMethod.GET)
+    public Map<String, Object> getTopicsByTenantNamespace(
+            @ApiParam(value = "page_num", defaultValue = "1", example = "1")
+            @RequestParam(name = "page_num", defaultValue = "1")
+            @Min(value = 1, message = "page_num is incorrect, should be greater than 0.")
+                    Integer pageNum,
+            @ApiParam(value = "page_size", defaultValue = "10", example = "10")
+            @RequestParam(name="page_size", defaultValue = "10")
+            @Range(min = 1, max = 1000, message = "page_size is incorrect, should be greater than 0 and less than 1000.")
+                    Integer pageSize,
+            @ApiParam(value = "The name of tenant")
+            @Size(min = 1, max = 255)
+            @PathVariable String tenant,
+            @ApiParam(value = "The name of namespace")
+            @Size(min = 1, max = 255)
+            @PathVariable String namespace) {
+        Map<String, Object> result = topicsService.getTopicsList(pageNum, pageSize, tenant, namespace);
+        return result;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/manager/pulsar/service/NamespacesService.java b/src/main/java/com/manager/pulsar/service/NamespacesService.java
new file mode 100644
index 0000000..786de06
--- /dev/null
+++ b/src/main/java/com/manager/pulsar/service/NamespacesService.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service;
+
+import java.util.Map;
+
+public interface NamespacesService {
+
+    Map<String, Object> getNamespaceList(Integer pageNum, Integer pageSize, String tenant);
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/manager/pulsar/service/TopicsService.java b/src/main/java/com/manager/pulsar/service/TopicsService.java
new file mode 100644
index 0000000..7949ca6
--- /dev/null
+++ b/src/main/java/com/manager/pulsar/service/TopicsService.java
@@ -0,0 +1,21 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service;
+
+import java.util.Map;
+
+public interface TopicsService {
+
+    Map<String, Object> getTopicsList(Integer pageNum, Integer pageSize, String namespace, String tenant);
+}
\ No newline at end of file
diff --git a/src/main/java/com/manager/pulsar/service/impl/NamespacesServiceImpl.java b/src/main/java/com/manager/pulsar/service/impl/NamespacesServiceImpl.java
new file mode 100644
index 0000000..be74939
--- /dev/null
+++ b/src/main/java/com/manager/pulsar/service/impl/NamespacesServiceImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service.impl;
+
+import com.google.common.collect.Maps;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.manager.pulsar.service.NamespacesService;
+import com.manager.pulsar.service.TopicsService;
+import com.manager.pulsar.utils.HttpUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class NamespacesServiceImpl implements NamespacesService {
+
+    @Value("${backend.directRequestBroker}")
+    private boolean directRequestBroker;
+
+    @Value("${backend.directRequestHost}")
+    private String directRequestHost;
+
+    @Autowired
+    private TopicsService topicsService;
+
+    public Map<String, Object> getNamespaceList(Integer pageNum, Integer pageSize, String tenant) {
+        Map<String, Object> namespacesMap = Maps.newHashMap();
+        List<Map<String, Object>> namespacesArray = new ArrayList<>();
+        if (directRequestBroker) {
+            Gson gson = new Gson();
+            Map<String, String> header = Maps.newHashMap();
+            header.put("Content-Type", "application/json");
+            String result = HttpUtil.doGet(directRequestHost + "/admin/v2/namespaces/" + tenant, header);
+            if (result != null) {
+                List<String> namespacesList = gson.fromJson(result, new TypeToken<List<String>>(){}.getType());
+                for (String tenantNamespace : namespacesList) {
+                    String namespace = tenantNamespace.split("/")[1];
+                    Map<String, Object> topicsEntity = Maps.newHashMap();
+                    Map<String, Object> topics = topicsService.getTopicsList(
+                            0, 0, tenant, namespace);
+                    topicsEntity.put("topics", topics.get("total"));
+                    topicsEntity.put("namespace", namespace);
+                    namespacesArray.add(topicsEntity);
+                }
+                namespacesMap.put("isPage", false);
+                namespacesMap.put("total", namespacesList.size());
+                namespacesMap.put("data", namespacesArray);
+                namespacesMap.put("pageNum", 1);
+                namespacesMap.put("pageSize", namespacesArray.size());
+            }
+        }
+        return namespacesMap;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/manager/pulsar/service/impl/TenantsServiceImpl.java b/src/main/java/com/manager/pulsar/service/impl/TenantsServiceImpl.java
index c9ebd2a..914f2b7 100644
--- a/src/main/java/com/manager/pulsar/service/impl/TenantsServiceImpl.java
+++ b/src/main/java/com/manager/pulsar/service/impl/TenantsServiceImpl.java
@@ -13,17 +13,14 @@
  */
 package com.manager.pulsar.service.impl;
 
-import com.github.pagehelper.Page;
 import com.google.common.collect.Maps;
 import com.google.common.reflect.TypeToken;
-import com.manager.pulsar.entity.NamespaceEntity;
+import com.google.gson.Gson;
 import com.manager.pulsar.entity.NamespacesRepository;
-import com.manager.pulsar.entity.TenantEntity;
 import com.manager.pulsar.entity.TenantsRepository;
 import com.manager.pulsar.service.TenantsService;
 import com.manager.pulsar.utils.HttpUtil;
 import org.apache.pulsar.common.policies.data.TenantInfo;
-import org.apache.pulsar.shade.com.google.gson.Gson;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/src/main/java/com/manager/pulsar/service/impl/TopicsServiceImpl.java b/src/main/java/com/manager/pulsar/service/impl/TopicsServiceImpl.java
new file mode 100644
index 0000000..a18f5b9
--- /dev/null
+++ b/src/main/java/com/manager/pulsar/service/impl/TopicsServiceImpl.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service.impl;
+
+import com.google.common.collect.Maps;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.manager.pulsar.service.TopicsService;
+import com.manager.pulsar.utils.HttpUtil;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class TopicsServiceImpl implements TopicsService {
+
+    @Value("${backend.directRequestBroker}")
+    private boolean directRequestBroker;
+
+    @Value("${backend.directRequestHost}")
+    private String directRequestHost;
+
+    public static final String PARTITIONED_TOPIC_SUFFIX = "-partition-";
+
+    private boolean isPartitonedTopic(List<String> topics, String topic) {
+        if (topic.contains(PARTITIONED_TOPIC_SUFFIX)) {
+            String[] t = topic.split(PARTITIONED_TOPIC_SUFFIX);
+            if (topics != null && topics.contains(t[0])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Map<String, Object> getTopicsList(Integer pageNum, Integer pageSize, String tenant, String namespace) {
+        Map<String, Object> topicsMap = Maps.newHashMap();
+        List<Map<String, String>> persistentTopic = this.getTopicListByHttp(tenant, namespace, "persistent");
+        topicsMap.put("topics", persistentTopic);
+        topicsMap.put("isPage", false);
+        topicsMap.put("total", persistentTopic.size());
+        topicsMap.put("pageNum", 1);
+        topicsMap.put("pageSize", persistentTopic.size());
+        return topicsMap;
+    }
+
+    private List<Map<String, String>> getTopicListByHttp(String tenant, String namespace, String persistent) {
+        List<Map<String, String>> topicsArray = new ArrayList<>();
+        Map<String, String> header = Maps.newHashMap();
+        header.put("Content-Type", "application/json");
+        String prefix = "/admin/v2/" + persistent + "/" + tenant + "/" + namespace;
+        Gson gson = new Gson();
+        String partitonedUrl = directRequestHost + prefix + "/partitioned";
+        String partitonedTopic = HttpUtil.doGet(partitonedUrl, header);
+        List<String> partitionedTopicsList = Arrays.asList();
+        Map<String, List<String>> partitionedMap = Maps.newHashMap();
+        if (partitonedTopic != null) {
+            partitionedTopicsList = gson.fromJson(
+                    partitonedTopic, new TypeToken<List<String>>(){}.getType());
+            for (String p : partitionedTopicsList) {
+                partitionedMap.put(this.getTopicName(p), new ArrayList<>());
+            }
+        }
+
+        String topicUrl = directRequestHost + prefix;
+        String topics = HttpUtil.doGet(topicUrl, header);
+        if (topics != null) {
+            List<String> topicsList = gson.fromJson(
+                    topics, new TypeToken<List<String>>(){}.getType());
+            for (String topic: topicsList) {
+                String topicName = this.getTopicName(topic);
+                Map<String, String> topicEntity = Maps.newHashMap();
+                if (isPartitonedTopic(partitionedTopicsList, topic)) {
+                    String[] name = topicName.split(PARTITIONED_TOPIC_SUFFIX);
+                    partitionedMap.get(name[0]).add(topicName);
+                } else {
+                    topicEntity.put("topic", topicName);
+                    topicEntity.put("partitions", "0");
+                    topicsArray.add(topicEntity);
+                }
+            }
+        }
+        if (partitionedTopicsList != null) {
+            for (String s : partitionedTopicsList) {
+                String topicName = this.getTopicName(s);
+                Map<String, String> topicEntity = Maps.newHashMap();
+                List<String> partitionedTopicList = partitionedMap.get(s);
+                if (partitionedTopicList != null && partitionedTopicList.size() > 0) {
+                    topicEntity.put("topic", topicName);
+                    topicEntity.put("partitions", String.valueOf(partitionedTopicList.size()));
+                } else {
+                    topicEntity.put("topic", topicName);
+                    String metadataTopicUrl = directRequestHost + prefix + "/" + topicName + "/partitions";
+                    String metadataTopic = HttpUtil.doGet(metadataTopicUrl, header);
+                    Map<String, Integer> metadata = gson.fromJson(
+                            metadataTopic, new TypeToken<Map<String, Integer>>(){}.getType());
+                    topicEntity.put("partitions", String.valueOf(metadata.get("partitions")));
+                }
+                topicsArray.add(topicEntity);
+            }
+        }
+        return topicsArray;
+    }
+
+    private String getTopicName(String topic) {
+        String tntPath = topic.split("://")[1];
+        String topicName = tntPath.split("/")[2];
+        return topicName;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/manager/pulsar/service/NamespacesServiceImplTest.java b/src/test/java/com/manager/pulsar/service/NamespacesServiceImplTest.java
new file mode 100644
index 0000000..55d6634
--- /dev/null
+++ b/src/test/java/com/manager/pulsar/service/NamespacesServiceImplTest.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service;
+
+import com.google.common.collect.Maps;
+import com.manager.pulsar.utils.HttpUtil;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Map;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(SpringRunner.class)
+@PowerMockIgnore( {"javax.management.*", "javax.net.ssl.*"})
+@PrepareForTest(HttpUtil.class)
+@SpringBootTest
+public class NamespacesServiceImplTest {
+
+    @Autowired
+    private NamespacesService namespacesService;
+
+    @Test
+    public void namespaceServiceImplTest() {
+        PowerMockito.mockStatic(HttpUtil.class);
+        Map<String, String> header = Maps.newHashMap();
+        header.put("Content-Type", "application/json");
+        PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/namespaces/public", header))
+                .thenReturn("[\"public/default\"]");
+
+        PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/persistent/public/default", header))
+                .thenReturn("[\"persistent://public/default/test789\"]");
+        PowerMockito.when(HttpUtil.doGet(
+                "http://localhost:8080/admin/v2/persistent/public/default/partitioned", header))
+                .thenReturn("[]");
+        Map<String, Object> result = namespacesService.getNamespaceList(1, 1, "public");
+        Assert.assertEquals(result.get("total"), 1);
+        Assert.assertFalse((Boolean) result.get("isPage"));
+        Assert.assertEquals(result.get("data").toString(), "[{topics=1, namespace=default}]");
+    }
+}
diff --git a/src/test/java/com/manager/pulsar/service/TopicsServiceImplTest.java b/src/test/java/com/manager/pulsar/service/TopicsServiceImplTest.java
new file mode 100644
index 0000000..e6a0631
--- /dev/null
+++ b/src/test/java/com/manager/pulsar/service/TopicsServiceImplTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed 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.
+ */
+package com.manager.pulsar.service;
+
+import com.google.common.collect.Maps;
+import com.manager.pulsar.utils.HttpUtil;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Map;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(SpringRunner.class)
+@PowerMockIgnore( {"javax.management.*", "javax.net.ssl.*"})
+@PrepareForTest(HttpUtil.class)
+@SpringBootTest
+public class TopicsServiceImplTest {
+
+    @Autowired
+    private TopicsService topicsService;
+
+    private final String topics = "[" +
+            "\"persistent://public/default/test789\"," +
+            "\"persistent://public/default/test900-partition-0\"," +
+            "\"persistent://public/default/test900-partition-1\"," +
+            "\"persistent://public/default/test900-partition-2\"]";
+
+    private final String partitionedTopics = "[\"persistent://public/default/test900\"]";
+
+    @Test
+    public void topicsServiceImplTest() {
+        PowerMockito.mockStatic(HttpUtil.class);
+        Map<String, String> header = Maps.newHashMap();
+        header.put("Content-Type", "application/json");
+        PowerMockito.when(HttpUtil.doGet("http://localhost:8080/admin/v2/persistent/public/default", header))
+                .thenReturn(topics);
+        PowerMockito.when(HttpUtil.doGet(
+                "http://localhost:8080/admin/v2/persistent/public/default/partitioned", header))
+                .thenReturn(partitionedTopics);
+        PowerMockito.when(HttpUtil.doGet(
+                "http://localhost:8080/admin/v2/persistent/public/default/test900/partitions", header))
+                .thenReturn("{\"partitions\":3}");
+        Map<String, Object> topicsMap = topicsService.getTopicsList(
+                1, 1, "public", "default");
+        Assert.assertEquals(topicsMap.get("total"), 2);
+        Assert.assertFalse((Boolean) topicsMap.get("isPage"));
+        Assert.assertEquals(topicsMap.get("topics").toString(),
+                "[{partitions=0, topic=test789}, {partitions=3, topic=test900}]");
+    }
+}