This is an automated email from the ASF dual-hosted git repository.
xianjingfeng 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 fe2efe096 [#1401][part-1] The dashboard supports multiple Coordinator
links. (#1449)
fe2efe096 is described below
commit fe2efe096e1c35395269c3f181aef15927aafa69
Author: yl09099 <[email protected]>
AuthorDate: Wed Jun 12 15:54:45 2024 +0800
[#1401][part-1] The dashboard supports multiple Coordinator links. (#1449)
### What changes were proposed in this pull request?
After multiple coordinators are deployed, a dashboard is added to link
multiple coordinators.
### Why are the changes needed?
Fix: #1401
### Does this PR introduce any user-facing change?
No.
### How was this patch tested?
No.
---
conf/dashboard.conf | 19 +++++
.../uniffle/dashboard/web/JettyServerFront.java | 19 +++--
.../dashboard/web/proxy/WebProxyServlet.java | 12 +--
.../dashboard/web/resource/BaseResource.java} | 37 +++++----
.../web/resource/CoordinatorResource.java | 47 ++++++++++++
.../uniffle/dashboard/web/resource/Response.java | 70 +++++++++++++++++
.../dashboard/web/resource/WebResource.java} | 14 +++-
.../dashboard/web/utils/DashboardUtils.java | 45 +++++++++++
dashboard/src/main/webapp/package.json | 3 +-
dashboard/src/main/webapp/src/api/api.js | 54 +++++++------
.../src/main/webapp/src/components/LayoutPage.vue | 88 ++++++++++++++++------
dashboard/src/main/webapp/src/main.js | 4 +-
.../src/{components => pages}/ApplicationPage.vue | 20 ++++-
.../CoordinatorServerPage.vue | 24 +++++-
.../{components => pages}/ShuffleServerPage.vue | 22 +++++-
.../serverstatus}/ActiveNodeListPage.vue | 17 ++++-
.../serverstatus}/DecommissionednodeListPage.vue | 16 +++-
.../serverstatus}/DecommissioningNodeListPage.vue | 18 ++++-
.../serverstatus}/ExcludeNodeList.vue | 16 +++-
.../serverstatus}/LostNodeList.vue | 19 ++++-
.../serverstatus}/UnhealthyNodeListPage.vue | 17 ++++-
dashboard/src/main/webapp/src/router/index.js | 24 +++---
.../request.js => store/useCurrentServerStore.js} | 27 +++----
dashboard/src/main/webapp/src/utils/http.js | 43 +++++++----
dashboard/src/main/webapp/src/utils/request.js | 43 +++++++++--
dashboard/src/main/webapp/vue.config.js | 12 +++
.../dashboard/web/utils/DashboardUtilsTest.java} | 32 ++++----
27 files changed, 599 insertions(+), 163 deletions(-)
diff --git a/conf/dashboard.conf b/conf/dashboard.conf
new file mode 100644
index 000000000..0b4658261
--- /dev/null
+++ b/conf/dashboard.conf
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+rss.dashboard.http.port 19997
+coordinator.web.address
http://coordinator.hostname00:19998/,http://coordinator.hostname01:19998/,http://coordinator.hostname02:19998/
diff --git
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/JettyServerFront.java
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/JettyServerFront.java
index 723ac16ae..bef348cce 100644
---
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/JettyServerFront.java
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/JettyServerFront.java
@@ -18,11 +18,13 @@
package org.apache.uniffle.dashboard.web;
import java.net.BindException;
+import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import org.eclipse.jetty.proxy.ProxyServlet;
+import
org.apache.hbase.thirdparty.org.glassfish.jersey.server.ServerProperties;
+import
org.apache.hbase.thirdparty.org.glassfish.jersey.servlet.ServletContainer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -44,6 +46,7 @@ import org.apache.uniffle.common.util.ExitUtils;
import org.apache.uniffle.common.util.ThreadUtils;
import org.apache.uniffle.dashboard.web.config.DashboardConf;
import org.apache.uniffle.dashboard.web.proxy.WebProxyServlet;
+import org.apache.uniffle.dashboard.web.utils.DashboardUtils;
public class JettyServerFront {
@@ -89,7 +92,10 @@ public class JettyServerFront {
HandlerList handlers = new HandlerList();
ResourceHandler resourceHandler = addResourceHandler();
String coordinatorWebAddress =
conf.getString(DashboardConf.COORDINATOR_WEB_ADDRESS);
- ServletContextHandler servletContextHandler =
addProxyHandler(coordinatorWebAddress);
+ Map<String, String> stringStringMap =
+ DashboardUtils.convertAddressesStrToMap(coordinatorWebAddress);
+
+ ServletContextHandler servletContextHandler =
addProxyHandler(stringStringMap);
handlers.setHandlers(new Handler[] {resourceHandler,
servletContextHandler});
server.setHandler(handlers);
}
@@ -103,11 +109,14 @@ public class JettyServerFront {
return resourceHandler;
}
- private static ServletContextHandler addProxyHandler(String
coordinatorWebAddress) {
- ProxyServlet proxyServlet = new WebProxyServlet(coordinatorWebAddress);
- ServletHolder holder = new ServletHolder(proxyServlet);
+ private ServletContextHandler addProxyHandler(Map<String, String>
coordinatorServerAddresses) {
ServletContextHandler contextHandler = new ServletContextHandler();
+ ServletHolder holder = new ServletHolder(new
WebProxyServlet(coordinatorServerAddresses));
contextHandler.addServlet(holder, "/api/*");
+ ServletHolder servletHolder =
contextHandler.addServlet(ServletContainer.class, "/*");
+ servletHolder.setInitParameter(
+ ServerProperties.PROVIDER_PACKAGES,
"org.apache.uniffle.dashboard.web.resource");
+ contextHandler.setAttribute("coordinatorServerAddresses",
coordinatorServerAddresses);
return contextHandler;
}
diff --git
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/proxy/WebProxyServlet.java
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/proxy/WebProxyServlet.java
index 2877cc6ef..0bb980c91 100644
---
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/proxy/WebProxyServlet.java
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/proxy/WebProxyServlet.java
@@ -17,6 +17,7 @@
package org.apache.uniffle.dashboard.web.proxy;
+import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -28,12 +29,12 @@ import org.slf4j.LoggerFactory;
public class WebProxyServlet extends ProxyServlet {
- private String targetAddress;
-
private static final Logger LOG =
LoggerFactory.getLogger(WebProxyServlet.class);
- public WebProxyServlet(String targetAddress) {
- this.targetAddress = targetAddress;
+ private Map<String, String> coordinatorServerAddressesMap;
+
+ public WebProxyServlet(Map<String, String> coordinatorServerAddressesMap) {
+ this.coordinatorServerAddressesMap = coordinatorServerAddressesMap;
}
@Override
@@ -41,8 +42,9 @@ public class WebProxyServlet extends ProxyServlet {
if (!validateDestination(clientRequest.getServerName(),
clientRequest.getServerPort())) {
return null;
}
+ String targetAddress =
+
coordinatorServerAddressesMap.get(clientRequest.getHeader("targetAddress"));
StringBuilder target = new StringBuilder();
-
if (targetAddress.endsWith("/")) {
targetAddress = targetAddress.substring(0, targetAddress.length() - 1);
}
diff --git a/dashboard/src/main/webapp/src/utils/http.js
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/BaseResource.java
similarity index 61%
copy from dashboard/src/main/webapp/src/utils/http.js
copy to
dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/BaseResource.java
index 472f9ef1c..5ed197302 100644
--- a/dashboard/src/main/webapp/src/utils/http.js
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/BaseResource.java
@@ -15,25 +15,22 @@
* limitations under the License.
*/
-import request from "@/utils/request";
-const http = {
- get(url, params, headers) {
- const config = {
- method: 'GET',
- url: url,
- params: params,
- headers: headers
- }
- return request(config);
- },
- post(url, data, headers) {
- const config = {
- method: 'POST',
- url: url,
- data: data,
- headers: headers
- }
- return request(config);
+package org.apache.uniffle.dashboard.web.resource;
+
+import java.util.concurrent.Callable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class BaseResource {
+ private static final Logger LOG =
LoggerFactory.getLogger(BaseResource.class);
+
+ protected <T> Response<T> execute(Callable<T> callable) {
+ try {
+ return Response.success(callable.call());
+ } catch (Throwable e) {
+ LOG.error("Call failure:", e);
+ return Response.fail(e.getMessage());
}
+ }
}
-export default http
diff --git
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/CoordinatorResource.java
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/CoordinatorResource.java
new file mode 100644
index 000000000..2aed5ca0d
--- /dev/null
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/CoordinatorResource.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package org.apache.uniffle.dashboard.web.resource;
+
+import java.util.Map;
+import javax.servlet.ServletContext;
+
+import org.apache.hbase.thirdparty.javax.ws.rs.GET;
+import org.apache.hbase.thirdparty.javax.ws.rs.Path;
+import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.Context;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
+
+@Produces({MediaType.APPLICATION_JSON})
+public class CoordinatorResource extends BaseResource {
+
+ @Context protected ServletContext servletContext;
+
+ @GET
+ @Path("/coordinatorServers")
+ public Response<Map<String, String>> getCoordinatorServers() {
+ return execute(
+ () -> {
+ Map<String, String> coordinatorServerAddresses =
getCoordinatorServerAddresses();
+ return coordinatorServerAddresses;
+ });
+ }
+
+ private Map<String, String> getCoordinatorServerAddresses() {
+ return (Map<String, String>)
servletContext.getAttribute("coordinatorServerAddresses");
+ }
+}
diff --git
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/Response.java
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/Response.java
new file mode 100644
index 000000000..ef71a320b
--- /dev/null
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/Response.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package org.apache.uniffle.dashboard.web.resource;
+
+public class Response<T> {
+ private static final int SUCCESS_CODE = 0;
+ private static final int ERROR_CODE = -1;
+ private int code;
+ private T data;
+ private String msg;
+
+ public Response() {}
+
+ public Response(int code, T data, String msg) {
+ this.code = code;
+ this.data = data;
+ this.msg = msg;
+ }
+
+ public static <T> Response<T> success(T data) {
+ return new Response<>(SUCCESS_CODE, data, "success");
+ }
+
+ public static <T> Response<T> fail(String msg) {
+ return new Response<>(ERROR_CODE, null, msg);
+ }
+
+ public static <T> Response<T> fail(String msg, int code) {
+ return new Response<>(code, null, msg);
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public String getErrMsg() {
+ return msg;
+ }
+
+ public void setErrMsg(String errMsg) {
+ this.msg = errMsg;
+ }
+}
diff --git a/dashboard/src/main/webapp/vue.config.js
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/WebResource.java
similarity index 64%
copy from dashboard/src/main/webapp/vue.config.js
copy to
dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/WebResource.java
index a007fc8ba..aaab37001 100644
--- a/dashboard/src/main/webapp/vue.config.js
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/resource/WebResource.java
@@ -15,5 +15,17 @@
* limitations under the License.
*/
-module.exports ={
+package org.apache.uniffle.dashboard.web.resource;
+
+import org.apache.hbase.thirdparty.javax.ws.rs.Path;
+import org.apache.hbase.thirdparty.javax.ws.rs.Produces;
+import org.apache.hbase.thirdparty.javax.ws.rs.core.MediaType;
+
+@Path("web")
+@Produces({MediaType.APPLICATION_JSON})
+public class WebResource {
+ @Path("coordinator")
+ public Class<CoordinatorResource> getGainCoordinatorsResource() {
+ return CoordinatorResource.class;
+ }
}
diff --git
a/dashboard/src/main/java/org/apache/uniffle/dashboard/web/utils/DashboardUtils.java
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/utils/DashboardUtils.java
new file mode 100644
index 000000000..69ddc88da
--- /dev/null
+++
b/dashboard/src/main/java/org/apache/uniffle/dashboard/web/utils/DashboardUtils.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.apache.uniffle.dashboard.web.utils;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DashboardUtils {
+ private static final Logger LOG =
LoggerFactory.getLogger(DashboardUtils.class);
+
+ public static Map<String, String> convertAddressesStrToMap(String
coordinatorAddressesStr) {
+ HashMap<String, String> coordinatorAddressMap = Maps.newHashMap();
+ String[] coordinators = coordinatorAddressesStr.split(",");
+ for (String coordinator : coordinators) {
+ try {
+ URL coordinatorURL = new URL(coordinator);
+ coordinatorAddressMap.put(coordinatorURL.getHost(), coordinator);
+ } catch (MalformedURLException e) {
+ LOG.error("The coordinator address is abnormal.", e);
+ }
+ }
+ return coordinatorAddressMap;
+ }
+}
diff --git a/dashboard/src/main/webapp/package.json
b/dashboard/src/main/webapp/package.json
index 820c7379a..0ab9bfba4 100644
--- a/dashboard/src/main/webapp/package.json
+++ b/dashboard/src/main/webapp/package.json
@@ -32,6 +32,7 @@
"core-js": "^3.8.3",
"element-plus": "^2.3.6",
"moment": "^2.29.4",
+ "pinia": "^2.1.7",
"rimraf": "^5.0.1",
"vue": "^3.2.13",
"vue-resource": "^1.5.3",
@@ -42,7 +43,7 @@
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
- "@vue/cli-service": "~5.0.0",
+ "@vue/cli-service": "^5.0.8",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"node-sass": "^9.0.0",
diff --git a/dashboard/src/main/webapp/src/api/api.js
b/dashboard/src/main/webapp/src/api/api.js
index d70e24b2b..8d4c7cd6f 100644
--- a/dashboard/src/main/webapp/src/api/api.js
+++ b/dashboard/src/main/webapp/src/api/api.js
@@ -16,63 +16,67 @@
*/
import http from "@/utils/http";
-
// Create a Coordinator information interface
-export function getCoordinatorServerInfo(params){
- return http.get('/coordinator/info', params,{})
+export function getCoordinatorServerInfo(params,headers) {
+ return http.get('/coordinator/info', params, headers, 0)
}
// Create a coordinator configuration file interface
-export function getCoordinatorConf(params){
- return http.get('/coordinator/conf', params,{})
+export function getCoordinatorConf(params,headers) {
+ return http.get('/coordinator/conf', params, headers, 0)
}
// Create an interface for the total number of nodes
-export function getShufflegetStatusTotal(params){
- return http.get('/server/nodes/summary', params,{})
+export function getShufflegetStatusTotal(params,headers) {
+ return http.get('/server/nodes/summary', params, headers, 0)
}
// Create an interface for activeNodes
-export function getShuffleActiveNodes(params){
- return http.get('/server/nodes?status=active', params,{})
+export function getShuffleActiveNodes(params,headers) {
+ return http.get('/server/nodes?status=active', params, headers, 0)
}
// Create an interface for lostNodes
-export function getShuffleLostList(params){
- return http.get('/server/nodes?status=lost', params,{})
+export function getShuffleLostList(params,headers) {
+ return http.get('/server/nodes?status=lost', params, headers, 0)
}
// Create an interface for unhealthyNodes
-export function getShuffleUnhealthyList(params){
- return http.get('/server/nodes?status=unhealthy', params,{})
+export function getShuffleUnhealthyList(params,headers) {
+ return http.get('/server/nodes?status=unhealthy', params, headers, 0)
}
// Create an interface for decommissioningNodes
-export function getShuffleDecommissioningList(params){
- return http.get('/server/nodes?status=decommissioning', params,{})
+export function getShuffleDecommissioningList(params,headers) {
+ return http.get('/server/nodes?status=decommissioning', params, headers, 0)
}
// Create an interface for decommissionedNodes
-export function getShuffleDecommissionedList(params){
- return http.get('/server/nodes?status=decommissioned', params,{})
+export function getShuffleDecommissionedList(params,headers) {
+ return http.get('/server/nodes?status=decommissioned', params, headers, 0)
}
// Create an interface for excludeNodes
-export function getShuffleExcludeNodes(params){
- return http.get('/server/nodes?status=excluded', params,{})
+export function getShuffleExcludeNodes(params,headers) {
+ return http.get('/server/nodes?status=excluded', params, headers, 0)
}
// Total number of interfaces for new App
-export function getAppTotal(params){
- return http.get('/app/total', params,{})
+export function getAppTotal(params,headers) {
+ return http.get('/app/total', params, headers, 0)
}
// Create an interface for the app basic information list
-export function getApplicationInfoList(params){
- return http.get('/app/appInfos', params,{})
+export function getApplicationInfoList(params,headers) {
+ return http.get('/app/appInfos', params, headers, 0)
}
// Create an interface for the number of apps for a user
-export function getTotalForUser(params){
- return http.get('/app/userTotal', params,{})
+export function getTotalForUser(params,headers) {
+ return http.get('/app/userTotal', params, headers, 0)
+}
+
+// Obtain the configured coordinator server list
+export function getAllCoordinatorAddrees(params,headers) {
+ return http.get('/coordinator/coordinatorServers', params, headers, 1)
}
diff --git a/dashboard/src/main/webapp/src/components/LayoutPage.vue
b/dashboard/src/main/webapp/src/components/LayoutPage.vue
index eb370829e..aa24a3847 100644
--- a/dashboard/src/main/webapp/src/components/LayoutPage.vue
+++ b/dashboard/src/main/webapp/src/components/LayoutPage.vue
@@ -23,33 +23,46 @@
<el-col :span="24">
<el-menu
:default-active="activeIndex1"
+ router
class="el-menu-demo"
mode="horizontal"
background-color="#20B2AA"
box-shadow="0 -2px 8px 0 rgba(0,0,0,0.12)"
text-color="#fff"
- active-text-color="#ffd04b"
- @select="handleSelect">
+ active-text-color="#ffd04b">
<el-menu-item index="0">
<div class="unffilelogo">
<img src="../assets/uniffle-logo.png" alt="unffile">
</div>
</el-menu-item>
- <router-link to="/coordinatorserverpage">
- <el-menu-item index="1">
- Coordinator
- </el-menu-item>
- </router-link>
- <router-link to="/shuffleserverpage">
- <el-menu-item index="2">
- Shuffle Server
- </el-menu-item>
- </router-link>
- <router-link to="/applicationpage">
- <el-menu-item index="3">
- Application
+ <el-menu-item index="/coordinatorserverpage">
+ <el-icon><House /></el-icon>
+ <span>Coordinator</span>
+ </el-menu-item>
+ <el-menu-item index="/shuffleserverpage">
+ <el-icon><Monitor /></el-icon>
+ <span>Shuffle Server</span>
+ </el-menu-item>
+ <el-menu-item index="/applicationpage">
+ <el-icon><Coin /></el-icon>
+ <span>Application</span>
+ </el-menu-item>
+ <el-sub-menu index="">
+ <template #title>Switching server</template>
+ <el-menu-item
+ v-for="item in hostNameAndPorts"
+ :key="item.label"
+ index="/nullpage"
+ @click="changeServer(item.label)">
+ <span>{{ item.label }}</span>
</el-menu-item>
- </router-link>
+ </el-sub-menu>
+ <el-menu-item index="">
+ <el-icon><SwitchFilled /></el-icon>
+ <label class="currentserver">
+ current:{{ currentServerStore.currentServer }}
+ </label>
+ </el-menu-item>
</el-menu>
</el-col>
</el-row>
@@ -62,25 +75,50 @@
</template>
<script>
-import {ref, onMounted} from 'vue'
+import {ref, reactive, onMounted} from 'vue'
+import {getAllCoordinatorAddrees} from '@/api/api'
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
const activeIndex1 = ref('1')
+ const currentServerStore = useCurrentServerStore()
+ const hostNameAndPorts = reactive([
+ {
+ value: '',
+ label: ''
+ }
+ ])
- function handleSelect() {
- localStorage.setItem("menuId", JSON.stringify(activeIndex1))
+ function changeServer(key) {
+ currentServerStore.currentServer = key
}
- onMounted(() => {
+ async function getSelectCurrentServer() {
+ const res = await getAllCoordinatorAddrees()
+ const selectCurrentServer = res.data.data
+ currentServerStore.currentServer = Object.keys(selectCurrentServer)[0]
+ hostNameAndPorts.length = 0
+ Object.entries(selectCurrentServer).forEach(([key, value]) => {
+ hostNameAndPorts.push({"value": value, "label": key})
+ })
+ }
+ onMounted(() => {
+ getSelectCurrentServer()
})
- return {activeIndex1, handleSelect}
+
+ return {
+ activeIndex1,
+ currentServerStore,
+ hostNameAndPorts,
+ changeServer,
+ }
}
}
</script>
-<style>
+<style scoped>
a {
text-decoration: none;
color: white;
@@ -95,4 +133,10 @@ a {
.unffilelogo > img {
height: 55px;
}
+
+.currentserver {
+ font-family: "Andale Mono";
+ font-size: smaller;
+ color: yellow;
+}
</style>
diff --git a/dashboard/src/main/webapp/src/main.js
b/dashboard/src/main/webapp/src/main.js
index e6c92fb81..1c5e2f3f1 100644
--- a/dashboard/src/main/webapp/src/main.js
+++ b/dashboard/src/main/webapp/src/main.js
@@ -16,13 +16,15 @@
*/
import {createApp} from 'vue';
+import {createPinia} from 'pinia'
import App from './App.vue'
import ElementPlus from 'element-plus'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import 'element-plus/dist/index.css'
import router from "@/router";
const app = createApp(App)
+const pinia = createPinia()
Object.keys(ElementPlusIconsVue).forEach(key => {
app.component(key, ElementPlusIconsVue[key])
})
-app.use(router).use(ElementPlus).mount('#app')
+app.use(router).use(pinia).use(ElementPlus).mount('#app')
diff --git a/dashboard/src/main/webapp/src/components/ApplicationPage.vue
b/dashboard/src/main/webapp/src/pages/ApplicationPage.vue
similarity index 80%
rename from dashboard/src/main/webapp/src/components/ApplicationPage.vue
rename to dashboard/src/main/webapp/src/pages/ApplicationPage.vue
index 1729311b9..0a29fa897 100644
--- a/dashboard/src/main/webapp/src/components/ApplicationPage.vue
+++ b/dashboard/src/main/webapp/src/pages/ApplicationPage.vue
@@ -56,6 +56,7 @@ import {
getTotalForUser
} from "@/api/api";
import {onMounted, reactive} from "vue";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -64,6 +65,7 @@ export default {
userAppCount: [{}],
appInfoData: [{appId: "", userName: "", updateTime: ""}]
})
+ const currentServerStore = useCurrentServerStore()
async function getApplicationInfoListPage() {
const res = await getApplicationInfoList();
@@ -80,10 +82,22 @@ export default {
pageData.apptotal = 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) {
+ getApplicationInfoListPage();
+ getTotalForUserPage();
+ getAppTotalPage();
+ }
+ })
+
onMounted(() => {
- getApplicationInfoListPage();
- getTotalForUserPage();
- getAppTotalPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getApplicationInfoListPage();
+ getTotalForUserPage();
+ getAppTotalPage();
+ }
})
return {pageData}
}
diff --git a/dashboard/src/main/webapp/src/components/CoordinatorServerPage.vue
b/dashboard/src/main/webapp/src/pages/CoordinatorServerPage.vue
similarity index 85%
rename from dashboard/src/main/webapp/src/components/CoordinatorServerPage.vue
rename to dashboard/src/main/webapp/src/pages/CoordinatorServerPage.vue
index ca30d47bb..a0a292790 100644
--- a/dashboard/src/main/webapp/src/components/CoordinatorServerPage.vue
+++ b/dashboard/src/main/webapp/src/pages/CoordinatorServerPage.vue
@@ -85,6 +85,7 @@
<script>
import {ref, reactive, computed, onMounted} from 'vue'
import {getCoordinatorConf, getCoordinatorServerInfo} from "@/api/api";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -94,17 +95,31 @@ export default {
serverInfo: {}
}
);
+ const currentServerStore= useCurrentServerStore()
+
async function getCoordinatorServerConfPage() {
- const res = await getCoordinatorConf();
+ const res = await getCoordinatorConf()
pageData.tableData = res.data.data
}
async function getCoorServerInfo() {
- const res = await getCoordinatorServerInfo();
+ const res = await getCoordinatorServerInfo()
pageData.serverInfo = 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) {
+ getCoordinatorServerConfPage();
+ getCoorServerInfo();
+ }
+ })
+
onMounted(() => {
- getCoordinatorServerConfPage();
- getCoorServerInfo();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getCoordinatorServerConfPage();
+ getCoorServerInfo();
+ }
})
const size = ref('')
@@ -128,6 +143,7 @@ export default {
marginTop: marginMap[size.value] || marginMap.default,
}
})
+
return {
pageData,
iconStyle,
diff --git a/dashboard/src/main/webapp/src/components/ShuffleServerPage.vue
b/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
similarity index 86%
rename from dashboard/src/main/webapp/src/components/ShuffleServerPage.vue
rename to dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
index 1a8af5298..0c6ce6955 100644
--- a/dashboard/src/main/webapp/src/components/ShuffleServerPage.vue
+++ b/dashboard/src/main/webapp/src/pages/ShuffleServerPage.vue
@@ -102,7 +102,8 @@
<script>
import {onMounted, reactive} from 'vue'
-import {getShufflegetStatusTotal} from "@/api/api";
+import {getShufflegetStatusTotal} from "@/api/api"
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -116,14 +117,25 @@ export default {
UNHEALTHY: 0
}
})
+ const currentServerStore= useCurrentServerStore()
async function getShufflegetStatusTotalPage() {
const res = await getShufflegetStatusTotal();
dataList.allshuffleServerSize = 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) {
+ getShufflegetStatusTotalPage();
+ }
+ })
+
onMounted(() => {
- getShufflegetStatusTotalPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShufflegetStatusTotalPage();
+ }
})
return {dataList}
}
@@ -141,6 +153,7 @@ export default {
font-weight: bolder;
font-size: 30px;
color: green;
+ text-decoration: none;
}
.decommissioningnode {
@@ -149,6 +162,7 @@ export default {
font-weight: bolder;
font-size: 30px;
color: #00c4ff;
+ text-decoration: none;
}
.decommissionednode {
@@ -157,6 +171,7 @@ export default {
font-weight: bolder;
font-size: 30px;
color: blue;
+ text-decoration: none;
}
.lostnode {
@@ -165,6 +180,7 @@ export default {
font-weight: bolder;
font-size: 30px;
color: red;
+ text-decoration: none;
}
.unhealthynode {
@@ -173,6 +189,7 @@ export default {
font-weight: bolder;
font-size: 30px;
color: #ff8800;
+ text-decoration: none;
}
.excludesnode {
@@ -180,5 +197,6 @@ export default {
font-style: normal;
font-weight: bolder;
font-size: 30px;
+ text-decoration: none;
}
</style>
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/ActiveNodeListPage.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/ActiveNodeListPage.vue
similarity index 78%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/ActiveNodeListPage.vue
rename to
dashboard/src/main/webapp/src/pages/serverstatus/ActiveNodeListPage.vue
index 703f15a53..e1dce0767 100644
---
a/dashboard/src/main/webapp/src/components/shufflecomponent/ActiveNodeListPage.vue
+++ b/dashboard/src/main/webapp/src/pages/serverstatus/ActiveNodeListPage.vue
@@ -27,7 +27,7 @@
<el-table-column prop="availableMemory" label="AvailableMem"
min-width="80" :formatter="memFormatter"/>
<el-table-column prop="eventNumInFlush" label="FlushNum" min-width="80"/>
<el-table-column prop="status" label="Status" min-width="80"/>
- <el-table-column prop="timestamp" label="ResigerTime" min-width="80"
:formatter="dateFormatter"/>
+ <el-table-column prop="timestamp" label="RegistrationTime"
min-width="80" :formatter="dateFormatter"/>
<el-table-column prop="tags" label="Tags" min-width="80"/>
</el-table>
</div>
@@ -36,6 +36,7 @@
import {onMounted, reactive} from 'vue'
import { getShuffleActiveNodes} from "@/api/api";
import {memFormatter, dateFormatter} from "@/utils/common";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -56,15 +57,27 @@ export default {
}
]
})
+ const currentServerStore= useCurrentServerStore()
async function getShuffleActiveNodesPage() {
const res = await getShuffleActiveNodes();
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) {
+ getShuffleActiveNodesPage()
+ }
+ })
+
onMounted(() => {
- getShuffleActiveNodesPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleActiveNodesPage();
+ }
})
+
return {pageData, memFormatter, dateFormatter}
}
}
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/DecommissionednodeListPage.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/DecommissionednodeListPage.vue
similarity index 78%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/DecommissionednodeListPage.vue
rename to
dashboard/src/main/webapp/src/pages/serverstatus/DecommissionednodeListPage.vue
index 1a0fa63d3..c95da69bd 100644
---
a/dashboard/src/main/webapp/src/components/shufflecomponent/DecommissionednodeListPage.vue
+++
b/dashboard/src/main/webapp/src/pages/serverstatus/DecommissionednodeListPage.vue
@@ -27,7 +27,7 @@
<el-table-column prop="availableMemory" label="AvailableMem"
min-width="80" :formatter="memFormatter"/>
<el-table-column prop="eventNumInFlush" label="FlushNum" min-width="80"/>
<el-table-column prop="status" label="Status" min-width="80"/>
- <el-table-column prop="timestamp" label="ResigerTime" min-width="80"
:formatter="dateFormatter"/>
+ <el-table-column prop="timestamp" label="RegistrationTime"
min-width="80" :formatter="dateFormatter"/>
<el-table-column prop="tags" label="Tags" min-width="80"/>
</el-table>
</div>
@@ -36,6 +36,7 @@
import {onMounted, reactive} from 'vue'
import { getShuffleDecommissionedList } from "@/api/api";
import {memFormatter, dateFormatter} from "@/utils/common";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore';
export default {
setup() {
@@ -56,14 +57,25 @@ export default {
}
]
})
+ const currentServerStore= useCurrentServerStore()
async function getShuffleDecommissionedListPage() {
const res = await getShuffleDecommissionedList();
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) {
+ getShuffleDecommissionedListPage();
+ }
+ })
+
onMounted(() => {
- getShuffleDecommissionedListPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleDecommissionedListPage();
+ }
})
return {pageData, memFormatter, dateFormatter}
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/DecommissioningNodeListPage.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/DecommissioningNodeListPage.vue
similarity index 78%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/DecommissioningNodeListPage.vue
rename to
dashboard/src/main/webapp/src/pages/serverstatus/DecommissioningNodeListPage.vue
index 930f64304..d6d7a75e6 100644
---
a/dashboard/src/main/webapp/src/components/shufflecomponent/DecommissioningNodeListPage.vue
+++
b/dashboard/src/main/webapp/src/pages/serverstatus/DecommissioningNodeListPage.vue
@@ -27,7 +27,7 @@
<el-table-column prop="availableMemory" label="AvailableMem"
min-width="80" :formatter="memFormatter"/>
<el-table-column prop="eventNumInFlush" label="FlushNum" min-width="80"/>
<el-table-column prop="status" label="Status" min-width="80"/>
- <el-table-column prop="timestamp" label="ResigerTime" min-width="80"
:formatter="dateFormatter"/>
+ <el-table-column prop="timestamp" label="RegistrationTime"
min-width="80" :formatter="dateFormatter"/>
<el-table-column prop="tags" label="Tags" min-width="80"/>
</el-table>
</div>
@@ -36,6 +36,7 @@
import {onMounted, reactive} from 'vue'
import { getShuffleDecommissioningList } from "@/api/api";
import {memFormatter, dateFormatter} from "@/utils/common";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -56,16 +57,29 @@ export default {
}
]
})
+ const currentServerStore= useCurrentServerStore()
async function getShuffleDecommissioningListPage() {
const res = await getShuffleDecommissioningList();
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) {
+ getShuffleDecommissioningListPage();
+ }
+ })
+
+
onMounted(() => {
- getShuffleDecommissioningListPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleDecommissioningListPage();
+ }
})
+
return {pageData, memFormatter, dateFormatter}
}
}
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/ExcludeNodeList.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue
similarity index 71%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/ExcludeNodeList.vue
rename to dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue
index 4c0286ee3..3566657f9 100644
---
a/dashboard/src/main/webapp/src/components/shufflecomponent/ExcludeNodeList.vue
+++ b/dashboard/src/main/webapp/src/pages/serverstatus/ExcludeNodeList.vue
@@ -25,6 +25,7 @@
<script>
import {onMounted, reactive} from 'vue'
import { getShuffleExcludeNodes } from "@/api/api";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -35,14 +36,27 @@ export default {
}
]
})
+ const currentServerStore= useCurrentServerStore()
+
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(() => {
- getShuffleExcludeNodesPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleExcludeNodesPage();
+ }
})
+
return {pageData}
}
}
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/LostNodeList.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/LostNodeList.vue
similarity index 78%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/LostNodeList.vue
rename to dashboard/src/main/webapp/src/pages/serverstatus/LostNodeList.vue
index 902951cdc..adfef3f52 100644
--- a/dashboard/src/main/webapp/src/components/shufflecomponent/LostNodeList.vue
+++ b/dashboard/src/main/webapp/src/pages/serverstatus/LostNodeList.vue
@@ -27,7 +27,7 @@
<el-table-column prop="availableMemory" label="AvailableMem"
min-width="80" :formatter="memFormatter"/>
<el-table-column prop="eventNumInFlush" label="FlushNum" min-width="80"/>
<el-table-column prop="status" label="Status" min-width="80"/>
- <el-table-column prop="timestamp" label="ResigerTime" min-width="80"
:formatter="dateFormatter"/>
+ <el-table-column prop="timestamp" label="RegistrationTime"
min-width="80" :formatter="dateFormatter"/>
<el-table-column prop="tags" label="Tags" min-width="80"/>
</el-table>
</div>
@@ -36,6 +36,7 @@
import {onMounted, reactive} from 'vue'
import { getShuffleLostList } from "@/api/api";
import {memFormatter, dateFormatter} from "@/utils/common";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -57,15 +58,29 @@ export default {
]
})
+ const currentServerStore= useCurrentServerStore()
+
async function getShuffleLostListPage() {
const res = await getShuffleLostList();
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) {
+ getShuffleLostListPage();
+ }
+ })
+
onMounted(() => {
- getShuffleLostListPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleLostListPage();
+ }
})
+
+
return {pageData, memFormatter, dateFormatter}
}
}
diff --git
a/dashboard/src/main/webapp/src/components/shufflecomponent/UnhealthyNodeListPage.vue
b/dashboard/src/main/webapp/src/pages/serverstatus/UnhealthyNodeListPage.vue
similarity index 78%
rename from
dashboard/src/main/webapp/src/components/shufflecomponent/UnhealthyNodeListPage.vue
rename to
dashboard/src/main/webapp/src/pages/serverstatus/UnhealthyNodeListPage.vue
index f66346dcd..627ce47cf 100644
---
a/dashboard/src/main/webapp/src/components/shufflecomponent/UnhealthyNodeListPage.vue
+++ b/dashboard/src/main/webapp/src/pages/serverstatus/UnhealthyNodeListPage.vue
@@ -27,7 +27,7 @@
<el-table-column prop="availableMemory" label="AvailableMem"
min-width="80" :formatter="memFormatter"/>
<el-table-column prop="eventNumInFlush" label="FlushNum" min-width="80"/>
<el-table-column prop="status" label="Status" min-width="80"/>
- <el-table-column prop="timestamp" label="ResigerTime" min-width="80"
:formatter="dateFormatter"/>
+ <el-table-column prop="timestamp" label="RegistrationTime"
min-width="80" :formatter="dateFormatter"/>
<el-table-column prop="tags" label="Tags" min-width="80"/>
</el-table>
</div>
@@ -36,6 +36,7 @@
import {onMounted, reactive} from 'vue'
import { getShuffleUnhealthyList } from "@/api/api";
import {memFormatter, dateFormatter} from "@/utils/common";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
export default {
setup() {
@@ -56,16 +57,28 @@ export default {
}
]
})
+ const currentServerStore= useCurrentServerStore()
async function getShuffleUnhealthyListPage() {
const res = await getShuffleUnhealthyList();
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) {
+ getShuffleUnhealthyListPage();
+ }
+ })
+
onMounted(() => {
- getShuffleUnhealthyListPage();
+ // If the coordinator address to request is not found in the global
variable, the request is not initiated.
+ if (currentServerStore.currentServer) {
+ getShuffleUnhealthyListPage();
+ }
})
+
return {pageData, memFormatter, dateFormatter}
}
}
diff --git a/dashboard/src/main/webapp/src/router/index.js
b/dashboard/src/main/webapp/src/router/index.js
index 6bd21c360..5bccc8496 100644
--- a/dashboard/src/main/webapp/src/router/index.js
+++ b/dashboard/src/main/webapp/src/router/index.js
@@ -16,15 +16,15 @@
*/
import {createRouter, createWebHashHistory} from "vue-router"
-import ApplicationPage from '@/components/ApplicationPage'
-import CoordinatorServerPage from '@/components/CoordinatorServerPage'
-import ShuffleServerPage from '@/components/ShuffleServerPage'
-import ActiveNodeListPage from
'@/components/shufflecomponent/ActiveNodeListPage'
-import DecommissioningNodeListPage from
'@/components/shufflecomponent/DecommissioningNodeListPage'
-import DecommissionednodeListPage from
'@/components/shufflecomponent/DecommissionednodeListPage'
-import LostNodeList from '@/components/shufflecomponent/LostNodeList'
-import UnhealthyNodeListPage from
'@/components/shufflecomponent/UnhealthyNodeListPage'
-import ExcludeNodeList from '@/components/shufflecomponent/ExcludeNodeList'
+import ApplicationPage from '@/pages/ApplicationPage.vue'
+import CoordinatorServerPage from '@/pages/CoordinatorServerPage.vue'
+import ShuffleServerPage from '@/pages/ShuffleServerPage.vue'
+import ActiveNodeListPage from '@/pages/serverstatus/ActiveNodeListPage'
+import DecommissioningNodeListPage from
'@/pages/serverstatus/DecommissioningNodeListPage'
+import DecommissionednodeListPage from
'@/pages/serverstatus/DecommissionednodeListPage'
+import LostNodeList from '@/pages/serverstatus/LostNodeList'
+import UnhealthyNodeListPage from '@/pages/serverstatus/UnhealthyNodeListPage'
+import ExcludeNodeList from '@/pages/serverstatus/ExcludeNodeList'
const routes = [
{
@@ -59,6 +59,12 @@ const routes = [
name: 'applicationpage',
component: ApplicationPage,
},
+ {
+ path: '/nullpage',
+ name: 'nullpage',
+ beforeEnter:(to,from,next)=>{next(false)},
+ component: ApplicationPage
+ },
]
const router = createRouter({
diff --git a/dashboard/src/main/webapp/src/utils/request.js
b/dashboard/src/main/webapp/src/store/useCurrentServerStore.js
similarity index 59%
copy from dashboard/src/main/webapp/src/utils/request.js
copy to dashboard/src/main/webapp/src/store/useCurrentServerStore.js
index 2e6b3c400..be6ab0807 100644
--- a/dashboard/src/main/webapp/src/utils/request.js
+++ b/dashboard/src/main/webapp/src/store/useCurrentServerStore.js
@@ -15,23 +15,14 @@
* limitations under the License.
*/
-import axios from 'axios'
+import {defineStore} from 'pinia'
+import {ref} from 'vue'
-const axiosInstance = axios.create({
- baseURL: '/api',
- timeout: 10000,
- headers: {}
-})
-
-axiosInstance.interceptors.request.use(config => {
- config.headers['Content-type'] = 'application/json';
- config.headers['Accept'] = 'application/json';
- return config;
-})
-
-axiosInstance.interceptors.response.use(response => {
- return response;
-}, error => {
- return error;
+/**
+ * Create a global shared repository that allows you to share state across
components/pages.
+ * @type {StoreDefinition<"overall",
_ExtractStateFromSetupStore<{currentServer: Ref<UnwrapRef<string>>}>,
_ExtractGettersFromSetupStore<{currentServer: Ref<UnwrapRef<string>>}>,
_ExtractActionsFromSetupStore<{currentServer: Ref<UnwrapRef<string>>}>>}
+ */
+export const useCurrentServerStore = defineStore('overall', () => {
+ const currentServer = ref('')
+ return { currentServer }
})
-export default axiosInstance;
diff --git a/dashboard/src/main/webapp/src/utils/http.js
b/dashboard/src/main/webapp/src/utils/http.js
index 472f9ef1c..87ca359bb 100644
--- a/dashboard/src/main/webapp/src/utils/http.js
+++ b/dashboard/src/main/webapp/src/utils/http.js
@@ -16,24 +16,39 @@
*/
import request from "@/utils/request";
+import {useCurrentServerStore} from '@/store/useCurrentServerStore'
+
+
const http = {
- get(url, params, headers) {
- const config = {
- method: 'GET',
- url: url,
- params: params,
- headers: headers
+ get(url, params, headers, fontBackFlag) {
+ if (fontBackFlag == 0) {
+ // The system obtains the address of the Coordinator to be
accessed from global variables.
+ const currentServerStore= useCurrentServerStore()
+ if (typeof headers !== 'undefined') {
+ headers['targetAddress'] = currentServerStore.currentServer;
+ } else {
+ headers = {}
+ headers['targetAddress'] = currentServerStore.currentServer;
+ }
+ return request.getBackEndAxiosInstance().get(url,{params,headers});
+ } else {
+ return
request.getFrontEndAxiosInstance().get(url,{params,headers});
}
- return request(config);
},
- post(url, data, headers) {
- const config = {
- method: 'POST',
- url: url,
- data: data,
- headers: headers
+ post(url, data, headers, fontBackFlag) {
+ if (fontBackFlag == 0) {
+ // The system obtains the address of the Coordinator to be
accessed from global variables.
+ const currentServerStore= useCurrentServerStore()
+ if (typeof headers !== 'undefined') {
+ headers['targetAddress'] = currentServerStore.currentServer;
+ } else {
+ headers = {}
+ headers['targetAddress'] = currentServerStore.currentServer;
+ }
+ return request.getBackEndAxiosInstance().post(url,data,headers);
+ } else {
+ return request.getFrontEndAxiosInstance().post(url,data,headers);
}
- return request(config);
}
}
export default http
diff --git a/dashboard/src/main/webapp/src/utils/request.js
b/dashboard/src/main/webapp/src/utils/request.js
index 2e6b3c400..5d7c72068 100644
--- a/dashboard/src/main/webapp/src/utils/request.js
+++ b/dashboard/src/main/webapp/src/utils/request.js
@@ -17,21 +17,54 @@
import axios from 'axios'
-const axiosInstance = axios.create({
+/**
+ * The root directory, starting with web, is handled by the dashboard server's
servlet
+ * @type {axios.AxiosInstance}
+ */
+const frontEndAxiosInstance = axios.create({
+ baseURL: '/web',
+ timeout: 10000
+})
+/**
+ * The root directory starts with API. The dashboard server reverse proxy
requests Coordinator apis
+ * @type {axios.AxiosInstance}
+ */
+const backEndAxiosInstance=axios.create({
baseURL: '/api',
- timeout: 10000,
- headers: {}
+ timeout: 10000
})
-axiosInstance.interceptors.request.use(config => {
+const axiosInstance = {
+ getFrontEndAxiosInstance(){
+ return frontEndAxiosInstance
+ },
+ getBackEndAxiosInstance(){
+ return backEndAxiosInstance
+ }
+}
+
+frontEndAxiosInstance.interceptors.request.use(config => {
config.headers['Content-type'] = 'application/json';
config.headers['Accept'] = 'application/json';
return config;
})
-axiosInstance.interceptors.response.use(response => {
+backEndAxiosInstance.interceptors.request.use(config => {
+ config.headers['Content-type'] = 'application/json';
+ config.headers['Accept'] = 'application/json';
+ return config;
+})
+
+frontEndAxiosInstance.interceptors.response.use(response => {
return response;
}, error => {
return error;
})
+
+backEndAxiosInstance.interceptors.response.use(response => {
+ return response;
+}, error => {
+ return error;
+})
+
export default axiosInstance;
diff --git a/dashboard/src/main/webapp/vue.config.js
b/dashboard/src/main/webapp/vue.config.js
index a007fc8ba..6bc469673 100644
--- a/dashboard/src/main/webapp/vue.config.js
+++ b/dashboard/src/main/webapp/vue.config.js
@@ -16,4 +16,16 @@
*/
module.exports ={
+ // Proxies can be set up by configuring the vue.config.js file to proxy
requests to the backend server.
+ devServer: {
+ host:'localhost',
+ port:8080,
+ proxy: {
+ '/': {
+ ws:false,
+ target: 'http://localhost:19997',
+ changeOrigin: true,
+ },
+ }
+ }
}
diff --git a/dashboard/src/main/webapp/src/utils/request.js
b/dashboard/src/test/java/org/apache/uniffle/dashboard/web/utils/DashboardUtilsTest.java
similarity index 57%
copy from dashboard/src/main/webapp/src/utils/request.js
copy to
dashboard/src/test/java/org/apache/uniffle/dashboard/web/utils/DashboardUtilsTest.java
index 2e6b3c400..12f869473 100644
--- a/dashboard/src/main/webapp/src/utils/request.js
+++
b/dashboard/src/test/java/org/apache/uniffle/dashboard/web/utils/DashboardUtilsTest.java
@@ -15,23 +15,21 @@
* limitations under the License.
*/
-import axios from 'axios'
+package org.apache.uniffle.dashboard.web.utils;
-const axiosInstance = axios.create({
- baseURL: '/api',
- timeout: 10000,
- headers: {}
-})
+import java.util.Map;
-axiosInstance.interceptors.request.use(config => {
- config.headers['Content-type'] = 'application/json';
- config.headers['Accept'] = 'application/json';
- return config;
-})
+import org.junit.jupiter.api.Test;
-axiosInstance.interceptors.response.use(response => {
- return response;
-}, error => {
- return error;
-})
-export default axiosInstance;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DashboardUtilsTest {
+ @Test
+ public void testConvertToMap() {
+ String coordinatorStr =
+
"http://coordinator.hostname00:19998/,http://coordinator.hostname01:19998/,http://coordinator.hostname02:19998/,http://coordinator.hostname03:19998/";
+ Map<String, String> coordinatorAddressMap =
+ DashboardUtils.convertAddressesStrToMap(coordinatorStr);
+ assertEquals(coordinatorAddressMap.size(), 4);
+ }
+}