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

roryqi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-uniffle.git


The following commit(s) were added to refs/heads/master by this push:
     new 258db12f5 [#2288] feat(dashboard): Show nodeInfo in excludeNode page 
(#2289)
258db12f5 is described below

commit 258db12f57aaa41c285b8336306a688efbd1d936
Author: kqhzz <[email protected]>
AuthorDate: Wed Dec 18 10:06:55 2024 +0800

    [#2288] feat(dashboard): Show nodeInfo in excludeNode page (#2289)
    
    ### What changes were proposed in this pull request?
    Show nodeInfo in excludeNode page
    <img width="1593" alt="image" 
src="https://github.com/user-attachments/assets/e74b23dc-4c32-4faf-94c7-278a0b05fef1";
 />
    
    <img width="1670" alt="企业微信截图_b08453cf-21af-43ed-bcdd-4238390c9823" 
src="https://github.com/user-attachments/assets/3b9ada0b-56ed-4515-9c24-0414ea324a27";
 />
    
    ### Why are the changes needed?
    Fix: #2288
    
    ### Does this PR introduce _any_ user-facing change?
    No.
    
    ### How was this patch tested?
    
    Manually.
---
 .../coordinator/web/resource/ServerResource.java   |  11 +-
 .../main/webapp/src/pages/ShuffleServerPage.vue    |  12 +-
 .../src/pages/serverstatus/ExcludeNodeList.vue     | 264 ---------------------
 .../webapp/src/pages/serverstatus/NodeListPage.vue | 174 +++++++++++++-
 dashboard/src/main/webapp/src/router/index.js      |   3 +-
 5 files changed, 185 insertions(+), 279 deletions(-)

diff --git 
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
 
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
index ade673112..e86b6597d 100644
--- 
a/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
+++ 
b/coordinator/src/main/java/org/apache/uniffle/coordinator/web/resource/ServerResource.java
@@ -79,8 +79,8 @@ public class ServerResource extends BaseResource {
       serverList = clusterManager.getLostServerList();
     } else if (ServerStatus.EXCLUDED.name().equalsIgnoreCase(status)) {
       serverList =
-          clusterManager.getExcludedNodes().stream()
-              .map(ServerNode::new)
+          clusterManager.list().stream()
+              .filter(node -> 
clusterManager.getExcludedNodes().contains(node.getId()))
               .collect(Collectors.toList());
     } else {
       List<ServerNode> serverAllList = clusterManager.list();
@@ -92,9 +92,10 @@ public class ServerResource extends BaseResource {
     serverList =
         serverList.stream()
             .filter(
-                server -> {
-                  return status == null || 
server.getStatus().name().equalsIgnoreCase(status);
-                })
+                server ->
+                    status == null
+                        || server.getStatus().name().equalsIgnoreCase(status)
+                        || 
ServerStatus.EXCLUDED.name().equalsIgnoreCase(status))
             .collect(Collectors.toList());
     serverList.sort(Comparator.comparing(ServerNode::getId));
     return Response.success(serverList);
diff --git a/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue 
b/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
index 43d23ee3e..3ecf7b1a0 100644
--- a/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
+++ b/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
@@ -21,7 +21,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/activeNodeList"
+          :to="{ path: '/shuffleserverpage/activeNodeList', query: { 
isExcludedPage: false } }"
           @click.native="routerHandler"
         >
           <el-card class="box-card" shadow="hover">
@@ -37,7 +37,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/decommissioningNodeList"
+          :to="{ path: '/shuffleserverpage/decommissioningNodeList', query: { 
isExcludedPage: false } }"
           @click.native="routerHandler"
         >
           <el-card class="box-card" shadow="hover">
@@ -55,7 +55,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/decommissionedNodeList"
+          :to="{ path: '/shuffleserverpage/decommissionedNodeList', query: { 
isExcludedPage: false } }"
           @click.native="routerHandler"
         >
           <el-card class="box-card" shadow="hover">
@@ -73,7 +73,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/lostNodeList"
+          :to="{ path: '/shuffleserverpage/lostNodeList', query: { 
isExcludedPage: false } }"
           @click.native="routerHandler"
           :updateTotalPage="updateTotalPage"
         >
@@ -90,7 +90,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/unhealthyNodeList"
+          :to="{ path: '/shuffleserverpage/unhealthyNodeList', query: { 
isExcludedPage: false } }"
           @click.native="routerHandler"
         >
           <el-card class="box-card" shadow="hover">
@@ -106,7 +106,7 @@
       <el-col :span="4">
         <router-link
           class="router-link-active"
-          to="/shuffleserverpage/excludeNodeList"
+          :to="{ path: '/shuffleserverpage/excludeNodeList', query: { 
isExcludedPage: true } }"
           @click.native="routerHandler"
         >
           <el-card class="box-card" shadow="hover">
diff --git 
a/dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue 
b/dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue
deleted file mode 100644
index e12768fdd..000000000
--- a/dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue
+++ /dev/null
@@ -1,264 +0,0 @@
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<template>
-  <div>
-    <div class="button-wrapper">
-      <el-button type="success" @click="dialogFormVisible = true"> Add Node 
</el-button>
-      <el-button type="danger" @click="handleDeleteNode">Delete({{ 
selectItemNum }})</el-button>
-    </div>
-    <el-divider />
-    <div>
-      <el-table
-        :data="filteredTableData"
-        :row-key="rowKey"
-        :default-sort="sortColumn"
-        @sort-change="sortChangeEvent"
-        @selection-change="handlerSelectionChange"
-        class="table-wapper"
-        ref="table"
-        stripe
-      >
-        <el-table-column type="selection" width="55" />
-        <el-table-column prop="id" label="ExcludeNodeId" min-width="180" 
:sortable="true" />
-        <el-table-column align="right">
-          <template #header>
-            <el-input v-model="searchKeyword" size="small" placeholder="Type 
to search" />
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
-    <div>
-      <el-dialog
-        v-model="dialogFormVisible"
-        title="Please enter the server id list to be excluded:"
-        class="dialog-wrapper"
-      >
-        <el-form>
-          <el-form-item :label-width="formLabelWidth">
-            <el-input
-              v-model="textarea"
-              class="textarea-wrapper"
-              :rows="10"
-              type="textarea"
-              placeholder="Please input"
-            />
-          </el-form-item>
-        </el-form>
-        <template #footer>
-          <div class="dialog-footer">
-            <el-button @click="dialogFormVisible = false">Cancel</el-button>
-            <el-button type="primary" @click="handleConfirmAddHandler"> 
Confirm </el-button>
-          </div>
-        </template>
-      </el-dialog>
-    </div>
-  </div>
-</template>
-<script>
-import { onMounted, reactive, ref, inject, computed } from 'vue'
-import {
-  addShuffleExcludeNodes,
-  getShuffleExcludeNodes,
-  removeShuffleExcludeNodes
-} from '@/api/api'
-import { useCurrentServerStore } from '@/store/useCurrentServerStore'
-import { ElMessage, ElMessageBox } from 'element-plus'
-
-export default {
-  setup() {
-    const pageData = reactive({ tableData: [] })
-    const currentServerStore = useCurrentServerStore()
-
-    const dialogFormVisible = ref(false)
-    const formLabelWidth = '10%'
-    const textarea = ref('')
-
-    /**
-     * Get the callback method of the parent page and update the number of 
servers on the page.
-     */
-    const updateTotalPage = inject('updateTotalPage')
-
-    async function getShuffleExcludeNodesPage() {
-      const res = await getShuffleExcludeNodes()
-      pageData.tableData = res.data.data
-    }
-
-    // The system obtains data from global variables and requests the 
interface to obtain new data after data changes.
-    currentServerStore.$subscribe((mutable, state) => {
-      if (state.currentServer) {
-        getShuffleExcludeNodesPage()
-      }
-    })
-
-    onMounted(() => {
-      // If the coordinator address to request is not found in the global 
variable, the request is not initiated.
-      if (currentServerStore.currentServer) {
-        getShuffleExcludeNodesPage()
-      }
-    })
-
-    /**
-     * The following describes how to handle sort events.
-     */
-    const sortColumn = reactive({})
-    const sortChangeEvent = (sortInfo) => {
-      for (const sortColumnKey in sortColumn) {
-        delete sortColumn[sortColumnKey]
-      }
-      sortColumn[sortInfo.prop] = sortInfo.order
-    }
-
-    /**
-     * The following describes how to handle add events.
-     */
-    function handleConfirmAddHandler() {
-      dialogFormVisible.value = false
-      addShuffleExcludeNodesPage()
-      // Refreshing the number of blacklists.
-      updateTotalPage()
-      // Refreshing the Blacklist list.
-      getShuffleExcludeNodesPage()
-    }
-
-    async function addShuffleExcludeNodesPage() {
-      try {
-        const excludeNodes = textarea.value.split('\n').map((item) => 
item.trim())
-        const excludeNodesObj = { excludeNodes }
-        const res = await addShuffleExcludeNodes(excludeNodesObj)
-        if (res.status >= 200 && res.status < 300) {
-          if (res.data.data === 'success') {
-            ElMessage.success('Add successfully.')
-          } else {
-            ElMessage.error('Add failed.')
-          }
-        } else {
-          ElMessage.error('Failed to add due to server bad.')
-        }
-      } catch (err) {
-        ElMessage.error('Failed to add due to network exception.')
-      }
-    }
-
-    /**
-     * The following describes how to handle blacklist deletion events.
-     */
-    const selectItemNum = ref(0)
-    const rowKey = 'id'
-    const selectedRows = ref([])
-    function handlerSelectionChange(selection) {
-      selectedRows.value = selection
-      selectItemNum.value = selectedRows.value.length
-    }
-    function handleDeleteNode() {
-      ElMessageBox.confirm('Are you sure about removing these nodes?', 
'Warning', {
-        confirmButtonText: 'OK',
-        cancelButtonText: 'Cancel',
-        type: 'warning'
-      })
-        .then(() => {
-          if (selectedRows.value.length === 0) {
-            ElMessage({
-              type: 'info',
-              message: 'No node is selected, Nothing!'
-            })
-          } else {
-            const selectedIds = selectedRows.value.map((row) => row[rowKey])
-            // pageData.tableData = pageData.tableData.filter(row => 
!selectedIds.includes(row[rowKey]));
-            deleteShuffleExcludedNodes(selectedIds)
-            // Refreshing the number of blacklists.
-            updateTotalPage()
-            // Refreshing the Blacklist list.
-            getShuffleExcludeNodesPage()
-            ElMessage({
-              type: 'success',
-              message: 'Delete completed'
-            })
-          }
-        })
-        .catch(() => {
-          ElMessage({
-            type: 'info',
-            message: 'Delete canceled'
-          })
-        })
-    }
-
-    async function deleteShuffleExcludedNodes(excludeNodes) {
-      try {
-        const excludeNodesObj = { excludeNodes }
-        const res = await removeShuffleExcludeNodes(excludeNodesObj)
-        if (res.status >= 200 && res.status < 300) {
-          if (res.data.data === 'success') {
-            ElMessage.success('Add successfully.')
-          } else {
-            ElMessage.error('Add failed.')
-          }
-        } else {
-          ElMessage.error('Failed to add due to server bad.')
-        }
-      } catch (err) {
-        ElMessage.error('Failed to add due to network exception.')
-      }
-    }
-
-    /**
-     * The following describes how to handle blacklist select events.
-     */
-    const searchKeyword = ref('')
-    const filteredTableData = computed(() => {
-      const keyword = searchKeyword.value.trim()
-      if (!keyword) {
-        return pageData.tableData
-      } else {
-        return pageData.tableData.filter((row) => {
-          return row.id.includes(keyword)
-        })
-      }
-    })
-    return {
-      pageData,
-      sortColumn,
-      selectItemNum,
-      sortChangeEvent,
-      handleConfirmAddHandler,
-      handleDeleteNode,
-      handlerSelectionChange,
-      dialogFormVisible,
-      formLabelWidth,
-      textarea,
-      rowKey,
-      searchKeyword,
-      filteredTableData
-    }
-  }
-}
-</script>
-
-<style>
-.textarea-wrapper {
-  width: 90%;
-}
-.dialog-wrapper {
-  width: 50%;
-}
-.table-wapper {
-  height: 550px;
-  width: 100%;
-  text-align: right;
-}
-</style>
diff --git a/dashboard/src/main/webapp/src/pages/serverstatus/NodeListPage.vue 
b/dashboard/src/main/webapp/src/pages/serverstatus/NodeListPage.vue
index ac92a1b8a..9af0682fa 100644
--- a/dashboard/src/main/webapp/src/pages/serverstatus/NodeListPage.vue
+++ b/dashboard/src/main/webapp/src/pages/serverstatus/NodeListPage.vue
@@ -17,13 +17,18 @@
 
 <template>
   <div>
+    <el-button type="success" @click="dialogFormVisible = true" 
v-show="isExcludePage()"> Add Node </el-button>
+    <el-button type="danger" @click="handleDeleteNode" 
v-show="isExcludePage()">Delete({{ selectItemNum }})</el-button>
     <el-table
       :data="listPageData.tableData"
       height="800"
       style="width: 100%"
+      :row-key="rowKey"
       :default-sort="sortColumn"
       @sort-change="sortChangeEvent"
+      @selection-change="handlerSelectionChange"
     >
+      <el-table-column type="selection" width="55" v-show="isExcludePage()"/>
       <el-table-column prop="id" label="Id" min-width="140" sortable fixed />
       <el-table-column label="NodeInfo(ip:jetty/grpc/netty)" min-width="140" >
         <template v-slot="{ row }">
@@ -109,6 +114,30 @@
         </template>
       </el-table-column>
     </el-table>
+    <el-dialog
+        v-model="dialogFormVisible"
+        title="Please enter the server id list to be excluded:"
+        class="dialog-wrapper"
+        v-show="isExcludePage()"
+    >
+      <el-form>
+        <el-form-item :label-width="formLabelWidth">
+          <el-input
+              v-model="textarea"
+              class="textarea-wrapper"
+              :rows="10"
+              type="textarea"
+              placeholder="Please input"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogFormVisible = false">Cancel</el-button>
+          <el-button type="primary" @click="handleConfirmAddHandler"> Confirm 
</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 <script>
@@ -127,7 +156,10 @@ import {
   getShuffleServerConf,
   getShuffleServerMetrics,
   getShuffleServerPrometheusMetrics,
-  getShuffleServerStacks
+  getShuffleServerStacks,
+  addShuffleExcludeNodes,
+  getShuffleExcludeNodes,
+  removeShuffleExcludeNodes
 } from '@/api/api'
 
 export default {
@@ -137,6 +169,114 @@ export default {
     const sortColumn = reactive({})
     const listPageData = reactive({ tableData: [] })
     const isShowRemove = ref(false)
+    const dialogFormVisible = ref(false)
+    const formLabelWidth = '10%'
+    const textarea = ref('')
+    const selectItemNum = ref(0)
+    const rowKey = 'id'
+    const selectedRows = ref([])
+    function isExcludePage() {
+      return router.currentRoute.value.query.isExcludedPage === 'true';
+    }
+
+    async function getShuffleExcludeNodesPage() {
+      const res = await getShuffleExcludeNodes()
+      listPageData.tableData = res.data.data
+    }
+
+    // The system obtains data from global variables and requests the 
interface to obtain new data after data changes.
+    currentServerStore.$subscribe((mutable, state) => {
+      if (state.currentServer) {
+        getShuffleExcludeNodesPage()
+      }
+    })
+
+    onMounted(() => {
+      // If the coordinator address to request is not found in the global 
variable, the request is not initiated.
+      if (currentServerStore.currentServer) {
+        getShuffleExcludeNodesPage()
+      }
+    })
+
+    /**
+     * The following describes how to handle add events.
+     */
+    function handleConfirmAddHandler() {
+      dialogFormVisible.value = false
+      addShuffleExcludeNodesPage()
+      // Refreshing the number of blacklists.
+      updateTotalPage()
+      // Refreshing the Blacklist list.
+      getShuffleExcludeNodesPage()
+    }
+    async function addShuffleExcludeNodesPage() {
+      try {
+        const excludeNodes = textarea.value.split('\n').map((item) => 
item.trim())
+        const excludeNodesObj = { excludeNodes }
+        const res = await addShuffleExcludeNodes(excludeNodesObj)
+        if (res.status >= 200 && res.status < 300) {
+          if (res.data.data === 'success') {
+            ElMessage.success('Add successfully.')
+          } else {
+            ElMessage.error('Add failed.')
+          }
+        } else {
+          ElMessage.error('Failed to add due to server bad.')
+        }
+      } catch (err) {
+        ElMessage.error('Failed to add due to network exception.')
+      }
+    }
+    function handleDeleteNode() {
+      ElMessageBox.confirm('Are you sure about removing these nodes?', 
'Warning', {
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
+        type: 'warning'
+      })
+          .then(() => {
+            if (selectedRows.value.length === 0) {
+              ElMessage({
+                type: 'info',
+                message: 'No node is selected, Nothing!'
+              })
+            } else {
+              const selectedIds = selectedRows.value.map((row) => row[rowKey])
+              deleteShuffleExcludedNodes(selectedIds)
+              // Refreshing the number of blacklists.
+              updateTotalPage()
+              // Refreshing the Blacklist list.
+              getShuffleExcludeNodesPage()
+              ElMessage({
+                type: 'success',
+                message: 'Delete completed'
+              })
+            }
+          })
+          .catch(() => {
+            ElMessage({
+              type: 'info',
+              message: 'Delete canceled'
+            })
+          })
+    }
+
+    async function deleteShuffleExcludedNodes(excludeNodes) {
+      try {
+        const excludeNodesObj = { excludeNodes }
+        const res = await removeShuffleExcludeNodes(excludeNodesObj)
+        if (res.status >= 200 && res.status < 300) {
+          if (res.data.data === 'success') {
+            ElMessage.success('Delete successfully.')
+          } else {
+            ElMessage.error('Delete failed.')
+          }
+        } else {
+          ElMessage.error('Failed to delete due to server bad.')
+        }
+      } catch (err) {
+        ElMessage.error('Failed to delete due to network exception.')
+      }
+    }
     async function deleteLostServer(row) {
       try {
         const params = { serverId: row.id }
@@ -177,6 +317,11 @@ export default {
       listPageData.tableData = res.data.data
     }
 
+    async function getShuffleExcludeListPage() {
+      const res = await getShuffleExcludeNodes()
+      listPageData.tableData = res.data.data
+    }
+
     function combinedRequestAddress(serverRow) {
       return 'http://' + serverRow.ip + ':' + serverRow.jettyPort
     }
@@ -279,6 +424,8 @@ export default {
       } else if (router.currentRoute.value.name === 'lostNodeList') {
         isShowRemove.value = true
         getShuffleLostListPage()
+      } else if (router.currentRoute.value.name === 'excludeNodeList') {
+        getShuffleExcludeListPage()
       }
     }
 
@@ -324,6 +471,10 @@ export default {
           // Cancelled
         })
     }
+    function handlerSelectionChange(selection) {
+      selectedRows.value = selection
+      selectItemNum.value = selectedRows.value.length
+    }
     return {
       listPageData,
       sortColumn,
@@ -335,8 +486,27 @@ export default {
       handlerServerMetrics,
       handlerServerStacks,
       memFormatter,
-      dateFormatter
+      dateFormatter,
+      dialogFormVisible,
+      formLabelWidth,
+      textarea,
+      selectItemNum,
+      handleDeleteNode,
+      getShuffleExcludeNodesPage,
+      handleConfirmAddHandler,
+      isExcludePage,
+      rowKey,
+      handlerSelectionChange
     }
   }
 }
 </script>
+
+<style>
+.textarea-wrapper {
+  width: 90%;
+}
+.dialog-wrapper {
+  width: 50%;
+}
+</style>
\ No newline at end of file
diff --git a/dashboard/src/main/webapp/src/router/index.js 
b/dashboard/src/main/webapp/src/router/index.js
index f0b6bb8e7..114ccdb3f 100644
--- a/dashboard/src/main/webapp/src/router/index.js
+++ b/dashboard/src/main/webapp/src/router/index.js
@@ -20,7 +20,6 @@ import ApplicationPage from '@/pages/ApplicationPage.vue'
 import DashboardPage from '@/pages/DashboardPage.vue'
 import CoordinatorServerPage from '@/pages/CoordinatorServerPage.vue'
 import ShuffleServerPage from '@/pages/ShuffleServerPage.vue'
-import ExcludeNodeList from '@/pages/serverstatus/ExcludeNodeList'
 import NodeListPage from '@/pages/serverstatus/NodeListPage.vue'
 
 const routes = [
@@ -68,7 +67,7 @@ const routes = [
       {
         path: '/shuffleserverpage/excludeNodeList',
         name: 'excludeNodeList',
-        component: ExcludeNodeList
+        component: NodeListPage
       }
     ]
   },

Reply via email to