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

domgarguilo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new 09894478d1 Add Resource Group Overview tables to the Monitor Home page 
(#6240)
09894478d1 is described below

commit 09894478d17e38f2810d0de0cd40a11d7f5943c5
Author: Dom G. <[email protected]>
AuthorDate: Tue Mar 31 13:01:24 2026 -0400

    Add Resource Group Overview tables to the Monitor Home page (#6240)
    
    * Add Resource Group Overview tables to the Monitor Home page
    
    * build deployment view on finalize
    
    * Add two tables to overview page
    
    * Add pagination and info back to breakdown table
    
    * Update 
server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
    
    Co-authored-by: Dave Marion <[email protected]>
    
    * properly update notResponded set
    
    * center entry count on table
    
    ---------
    
    Co-authored-by: Dave Marion <[email protected]>
---
 .../apache/accumulo/monitor/next/Endpoints.java    |  11 +-
 .../accumulo/monitor/next/InformationFetcher.java  |   2 +-
 .../accumulo/monitor/next/SystemInformation.java   |  65 +++++----
 .../next/deployment/DeploymentOverview.java        |  82 ++++++++++++
 .../org/apache/accumulo/monitor/resources/js/ec.js |  10 --
 .../accumulo/monitor/resources/js/functions.js     |  15 +++
 .../accumulo/monitor/resources/js/overview.js      | 147 ++++++++++++++++++---
 .../accumulo/monitor/resources/js/tservers.js      |  23 +++-
 .../apache/accumulo/monitor/templates/overview.ftl |  71 ++++++----
 .../apache/accumulo/monitor/templates/tservers.ftl |  10 ++
 10 files changed, 336 insertions(+), 100 deletions(-)

diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
index d2fdaa26ef..9a809e9d3c 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
@@ -43,16 +43,15 @@ import jakarta.ws.rs.core.MediaType;
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.admin.TabletInformation;
 import org.apache.accumulo.core.client.admin.servers.ServerId;
-import org.apache.accumulo.core.data.ResourceGroupId;
 import org.apache.accumulo.core.data.TableId;
 import org.apache.accumulo.core.metrics.flatbuffers.FMetric;
 import org.apache.accumulo.core.process.thrift.MetricResponse;
 import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
 import org.apache.accumulo.monitor.Monitor;
 import org.apache.accumulo.monitor.next.InformationFetcher.InstanceSummary;
-import org.apache.accumulo.monitor.next.SystemInformation.ProcessSummary;
 import org.apache.accumulo.monitor.next.SystemInformation.TableSummary;
 import 
org.apache.accumulo.monitor.next.SystemInformation.TimeOrderedRunningCompactionSet;
+import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
 import org.apache.accumulo.monitor.next.ec.CompactorsSummary;
 import org.apache.accumulo.monitor.next.ec.CoordinatorSummary;
 import org.apache.accumulo.monitor.next.sservers.ScanServerView;
@@ -408,10 +407,10 @@ public class Endpoints {
   @GET
   @Path("deployment")
   @Produces(MediaType.APPLICATION_JSON)
-  @Description("Returns a map of resource group to server type to process 
summary."
-      + " The process summary contains the number of configured, responding, 
and not responding servers")
-  public Map<ResourceGroupId,Map<String,ProcessSummary>> 
getDeploymentOverview() {
-    return 
monitor.getInformationFetcher().getSummaryForEndpoint().getDeploymentOverview();
+  @Description("Returns a UI-ready deployment overview grouped by resource 
group. Each process row"
+      + " contains the total and responding server counts.")
+  public DeploymentOverview getDeploymentOverview() {
+    return 
monitor.getInformationFetcher().getSummaryForEndpoint().getDeploymentView();
   }
 
   @GET
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
index 9b27141f0d..1f5f915114 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
@@ -133,7 +133,7 @@ public class InformationFetcher implements 
RemovalListener<ServerId,MetricRespon
         }
       } catch (Exception e) {
         LOG.warn("Error trying to get metrics from server: {}", server, e);
-        summary.processError(server);
+        summary.processMetricsError(server);
       }
     }
 
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
index 3de740a1b8..3949e5766b 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
@@ -58,6 +58,7 @@ import org.apache.accumulo.core.metrics.flatbuffers.FTag;
 import org.apache.accumulo.core.process.thrift.MetricResponse;
 import org.apache.accumulo.core.spi.balancer.TableLoadBalancer;
 import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
+import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
 import org.apache.accumulo.monitor.next.sservers.ScanServerView;
 import org.apache.accumulo.server.ServerContext;
 import org.apache.accumulo.server.conf.TableConfiguration;
@@ -272,34 +273,25 @@ public class SystemInformation {
   }
 
   public static class ProcessSummary {
-    private final AtomicLong configured = new AtomicLong(0);
-    private final AtomicLong responded = new AtomicLong();
-    private final Set<String> notResponded = ConcurrentHashMap.newKeySet();
+    private final Set<ServerId> responded = ConcurrentHashMap.newKeySet();
+    private final Set<ServerId> notResponded = ConcurrentHashMap.newKeySet();
 
-    public void addResponded() {
-      configured.incrementAndGet();
-      responded.incrementAndGet();
+    public void addResponded(ServerId server) {
+      notResponded.remove(server);
+      responded.add(server);
     }
 
     public void addNotResponded(ServerId server) {
-      configured.incrementAndGet();
-      notResponded.add(server.getHost() + ":" + server.getPort());
+      responded.remove(server);
+      notResponded.add(server);
     }
 
-    public long getConfigured() {
-      return this.configured.get();
+    public long getTotal() {
+      return this.responded.size() + this.notResponded.size();
     }
 
     public long getResponded() {
-      return this.responded.get();
-    }
-
-    public long getNotResponded() {
-      return this.notResponded.size();
-    }
-
-    public Set<String> getNotRespondedHosts() {
-      return this.notResponded;
+      return this.responded.size();
     }
 
   }
@@ -368,6 +360,7 @@ public class SystemInformation {
 
   private final Set<String> resourceGroups = ConcurrentHashMap.newKeySet();
   private final Set<ServerId> problemHosts = ConcurrentHashMap.newKeySet();
+  private final Set<ServerId> metricProblemHosts = 
ConcurrentHashMap.newKeySet();
   private final AtomicReference<ServerId> manager = new AtomicReference<>();
   private final AtomicReference<ServerId> gc = new AtomicReference<>();
 
@@ -410,7 +403,7 @@ public class SystemInformation {
   private final Map<TableId,List<TabletInformation>> tablets = new 
ConcurrentHashMap<>();
 
   // Deployment Overview
-  private final Map<ResourceGroupId,Map<String,ProcessSummary>> deployment =
+  private final Map<ResourceGroupId,Map<ServerId.Type,ProcessSummary>> 
deployment =
       new ConcurrentHashMap<>();
 
   private final Set<String> suggestions = new ConcurrentSkipListSet<>();
@@ -418,7 +411,9 @@ public class SystemInformation {
   private final Set<String> configuredCompactionResourceGroups = 
ConcurrentHashMap.newKeySet();
 
   private long timestamp = 0;
-  private ScanServerView scanServerView;
+  private ScanServerView scanServerView = new ScanServerView(0L, List.of(),
+      new ScanServerView.Status(false, false, false, 0, 0, 0L, "OK", null));
+  private DeploymentOverview deploymentOverview = new DeploymentOverview(0L, 
List.of());
   private final int rgLongRunningCompactionSize;
 
   public SystemInformation(Cache<ServerId,MetricResponse> allMetrics, 
ServerContext ctx) {
@@ -431,6 +426,7 @@ public class SystemInformation {
   public void clear() {
     resourceGroups.clear();
     problemHosts.clear();
+    metricProblemHosts.clear();
     compactors.clear();
     sservers.clear();
     tservers.clear();
@@ -451,7 +447,6 @@ public class SystemInformation {
     runningCompactionsPerGroup.clear();
     runningCompactionsPerTable.clear();
     configuredCompactionResourceGroups.clear();
-    scanServerView = null;
   }
 
   private void updateAggregates(final MetricResponse response,
@@ -509,10 +504,11 @@ public class SystemInformation {
 
   public void processResponse(final ServerId server, final MetricResponse 
response) {
     problemHosts.remove(server);
+    metricProblemHosts.remove(server);
     allMetrics.put(server, response);
     resourceGroups.add(response.getResourceGroup());
     deployment.computeIfAbsent(server.getResourceGroup(), g -> new 
ConcurrentHashMap<>())
-        .computeIfAbsent(server.getType().name(), t -> new 
ProcessSummary()).addResponded();
+        .computeIfAbsent(server.getType(), t -> new 
ProcessSummary()).addResponded(server);
     switch (response.serverType) {
       case COMPACTOR:
         compactors
@@ -583,17 +579,21 @@ public class SystemInformation {
     problemHosts.add(server);
   }
 
+  public void processMetricsError(ServerId server) {
+    problemHosts.add(server);
+    metricProblemHosts.add(server);
+  }
+
   public void addConfiguredCompactionGroups(Set<String> groups) {
     configuredCompactionResourceGroups.addAll(groups);
   }
 
   public void finish() {
     // Update the deployment not-responded numbers based
-    // on the problem hosts.
-    problemHosts.forEach(serverId -> {
+    // on metric fetch failures for this refresh.
+    metricProblemHosts.forEach(serverId -> {
       deployment.computeIfAbsent(serverId.getResourceGroup(), g -> new 
ConcurrentHashMap<>())
-          .computeIfAbsent(serverId.getType().name(), t -> new 
ProcessSummary())
-          .addNotResponded(serverId);
+          .computeIfAbsent(serverId.getType(), t -> new 
ProcessSummary()).addNotResponded(serverId);
     });
     for (SystemTables table : SystemTables.values()) {
       TableConfiguration tconf = 
this.ctx.getTableConfiguration(table.tableId());
@@ -607,6 +607,9 @@ public class SystemInformation {
     for (String rg : getResourceGroups()) {
       Set<ServerId> rgCompactors = getCompactorResourceGroupServers(rg);
       List<FMetric> metrics = queueMetrics.get(rg);
+      if (metrics == null || metrics.isEmpty()) {
+        continue;
+      }
       Optional<FMetric> queued = metrics.stream()
           .filter(fm -> 
fm.name().equals(Metric.COMPACTOR_JOB_PRIORITY_QUEUE_JOBS_QUEUED.getName()))
           .findFirst();
@@ -620,6 +623,9 @@ public class SystemInformation {
             // Check for idle compactors.
             Map<Id,CumulativeDistributionSummary> rgMetrics =
                 getCompactorResourceGroupMetricSummary(rg);
+            if (rgMetrics == null || rgMetrics.isEmpty()) {
+              continue;
+            }
             Optional<Entry<Id,CumulativeDistributionSummary>> idleMetric = 
rgMetrics.entrySet()
                 .stream().filter(e -> 
e.getKey().getName().equals(Metric.SERVER_IDLE.getName()))
                 .findFirst();
@@ -648,6 +654,7 @@ public class SystemInformation {
         .filter(serverId -> serverId.getType() == 
ServerId.Type.SCAN_SERVER).count();
     var responses = allMetrics.getAllPresent(scanServers).values();
     timestamp = System.currentTimeMillis();
+    deploymentOverview = DeploymentOverview.fromSummary(deployment, timestamp);
     scanServerView = ScanServerView.fromMetrics(responses, scanServers.size(),
         problemScanServerCount, timestamp);
   }
@@ -731,8 +738,8 @@ public class SystemInformation {
     return this.tablets.get(tableId);
   }
 
-  public Map<ResourceGroupId,Map<String,ProcessSummary>> 
getDeploymentOverview() {
-    return this.deployment;
+  public DeploymentOverview getDeploymentView() {
+    return this.deploymentOverview;
   }
 
   public Set<String> getSuggestions() {
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
new file mode 100644
index 0000000000..536399fda1
--- /dev/null
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
@@ -0,0 +1,82 @@
+/*
+ * 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
+ *
+ *   https://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.accumulo.monitor.next.deployment;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.accumulo.core.client.admin.servers.ServerId;
+import org.apache.accumulo.core.data.ResourceGroupId;
+import org.apache.accumulo.monitor.next.SystemInformation.ProcessSummary;
+
+/**
+ * Data Transfer Object for the Monitor Deployment page.
+ */
+public record DeploymentOverview(long lastUpdate, List<DeploymentRow> 
breakdown) {
+
+  /**
+   * Data Transfer Object containing counts of total and responding servers 
for a given resource
+   * group and server type.
+   */
+  public record DeploymentRow(String resourceGroup, String serverType, long 
total,
+      long responding) {
+  }
+
+  public static DeploymentOverview fromSummary(
+      Map<ResourceGroupId,Map<ServerId.Type,ProcessSummary>> deployment, long 
lastUpdate) {
+    if (deployment == null || deployment.isEmpty()) {
+      return new DeploymentOverview(lastUpdate, List.of());
+    }
+
+    var breakdown =
+        
deployment.entrySet().stream().sorted(Map.Entry.comparingByKey()).flatMap(entry 
-> {
+          var resourceGroup = entry.getKey().canonical();
+          var processes = entry.getValue();
+          if (processes == null || processes.isEmpty()) {
+            return java.util.stream.Stream.empty();
+          }
+
+          return processes.entrySet().stream()
+              
.sorted(Map.Entry.comparingByKey(Comparator.comparingInt(Enum::ordinal)))
+              .map(processEntry -> {
+                ServerId.Type type = processEntry.getKey();
+                ProcessSummary processSummary = processEntry.getValue();
+                return new DeploymentRow(resourceGroup, processLabel(type),
+                    processSummary.getTotal(), processSummary.getResponded());
+              });
+        }).toList();
+
+    return new DeploymentOverview(lastUpdate, breakdown);
+  }
+
+  /**
+   * @return String representation of the server type
+   */
+  private static String processLabel(ServerId.Type process) {
+    return switch (process) {
+      case COMPACTOR -> "Compactor";
+      case GARBAGE_COLLECTOR -> "Garbage Collector";
+      case MANAGER -> "Manager";
+      case MONITOR -> "Monitor";
+      case SCAN_SERVER -> "Scan Server";
+      case TABLET_SERVER -> "Tablet Server";
+    };
+  }
+}
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
index 9541cbc30e..9fcda2ec5b 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
@@ -334,13 +334,3 @@ async function refreshManagerStatus() {
     return managerStatus;
   });
 }
-
-// Helper function to validate regex
-function isValidRegex(input) {
-  try {
-    new RegExp(input);
-    return true;
-  } catch (e) {
-    return false;
-  }
-}
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
index 331f0844db..947b8b943d 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
@@ -753,3 +753,18 @@ function getTable(name) {
 function getCompactionsSummary() {
   return getJSONForTable(REST_V2_PREFIX + '/compactions/summary', 
'compactionsSummary');
 }
+
+/**
+ * Returns true if the input is a valid regular expression, false otherwise.
+ *
+ * @param {string} input Potential regex string
+ * @returns {boolean} Whether the input is a valid regex
+ */
+function isValidRegex(input) {
+  try {
+    new RegExp(input);
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
index a0255e32c9..fe5e691406 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
@@ -18,10 +18,101 @@
  */
 "use strict";
 
+var deploymentSummaryTable;
+var deploymentBreakdownTable;
+
 /**
  * Creates overview initial table
  */
 $(function () {
+  // display datatables errors in the console instead of in alerts
+  $.fn.dataTable.ext.errMode = 'throw';
+
+  deploymentSummaryTable = $('#deploymentSummaryTable').DataTable({
+    "autoWidth": false,
+    "paging": false,
+    "searching": false,
+    "info": false,
+    "ordering": false,
+    "dom": 't',
+    "data": [],
+    "columnDefs": [{
+        "targets": 0,
+        "width": "60%"
+      },
+      {
+        "targets": 1,
+        "width": "40%"
+      }
+    ],
+    "columns": [{
+        "data": "serverType"
+      },
+      {
+        "data": null,
+        "render": function (data, type, row) {
+          return row.responding + ' / ' + row.total;
+        }
+      }
+    ]
+  });
+
+  deploymentBreakdownTable = $('#deploymentBreakdownTable').DataTable({
+    "autoWidth": false,
+    "paging": true,
+    "pageLength": 10,
+    "searching": true,
+    "info": true,
+    "order": [
+      [0, 'asc'],
+      [1, 'asc']
+    ],
+    "dom": 't<"row"<"col-sm-3"l><"col-sm-5 text-center"i><"col-sm-4 
text-right"p>>',
+    "data": [],
+    "columnDefs": [{
+        "targets": 0,
+        "width": "30%"
+      },
+      {
+        "targets": 1,
+        "width": "40%"
+      },
+      {
+        "targets": 2,
+        "width": "30%"
+      }
+    ],
+    "columns": [{
+        "data": "resourceGroup",
+        "name": "resourceGroup"
+      },
+      {
+        "data": "serverType"
+      },
+      {
+        "data": null,
+        "render": function (data, type, row) {
+          return row.responding + ' / ' + row.total;
+        }
+      }
+    ]
+  });
+
+  $('#deployment-rg-filter').on('keyup', function () {
+    var input = this.value;
+    if (isValidRegex(input) || input === '') {
+      $('#deployment-rg-feedback').hide();
+      $(this).removeClass('is-invalid');
+      deploymentBreakdownTable
+        .column('resourceGroup:name')
+        .search(input, true, false)
+        .draw();
+    } else {
+      $('#deployment-rg-feedback').show();
+      $(this).addClass('is-invalid');
+    }
+  });
+
   refreshOverview();
 });
 
@@ -29,17 +120,7 @@ $(function () {
  * Makes the REST calls, generates the table with the new information
  */
 function refreshOverview() {
-  getStatus().then(function () {
-    var managerStatus = JSON.parse(sessionStorage.status).managerStatus;
-    // If the manager is down, show only the first row, otherwise refresh old 
values
-    $('#manager tr td').hide();
-    if (managerStatus === 'ERROR') {
-      $('#manager tr td:first').show();
-    } else {
-      $('#manager tr td:not(:first)').show();
-      refreshManagerTable();
-    }
-  });
+  refreshDeploymentTables();
 }
 
 /**
@@ -50,16 +131,42 @@ function refresh() {
 }
 
 /**
- * Refreshes the manager table
+ * Refreshes the deployment overview tables
  */
-function refreshManagerTable() {
-  getManager().then(function () {
-    var data = JSON.parse(sessionStorage.manager);
-    var table = $('#manager td.right');
+function refreshDeploymentTables() {
+  getDeployment().then(function () {
+    var data = JSON.parse(sessionStorage.deployment);
+    var breakdown = Array.isArray(data.breakdown) ? data.breakdown : [];
+    var summary = buildDeploymentSummary(breakdown);
+
+    if (breakdown.length === 0) {
+      $('#deploymentWarning').html('<div class="alert alert-warning" 
role="alert">' +
+        'No deployment data is currently available.</div>');
+    } else {
+      $('#deploymentWarning').empty();
+    }
 
-    table.eq(0).html(data.host);
-    table.eq(1).html(data.resourceGroup);
-    table.eq(2).html(dateFormat(data.timestamp));
-    table.eq(3).html('<a href="' + contextPath + 
'rest-v2/manager/metrics">Metrics</a>');
+    deploymentSummaryTable.clear().rows.add(summary).draw();
+    deploymentBreakdownTable.clear().rows.add(breakdown).draw();
   });
 }
+
+function buildDeploymentSummary(breakdown) {
+  var totalsByType = new Map();
+
+  breakdown.forEach(function (row) {
+    var existing = totalsByType.get(row.serverType);
+    if (existing === undefined) {
+      totalsByType.set(row.serverType, {
+        serverType: row.serverType,
+        total: row.total,
+        responding: row.responding
+      });
+    } else {
+      existing.total += row.total;
+      existing.responding += row.responding;
+    }
+  });
+
+  return Array.from(totalsByType.values());
+}
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
index 981ec85762..e03cff19b4 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
@@ -70,16 +70,28 @@ function refreshTServersTable() {
 }
 
 /**
- * If manager is down, tserver status will be ERROR. Add a banner to indicate
+ * Show a page banner that matches the tablet server status shown in the 
navbar.
  */
-function refreshTServersBanner(managerStatus) {
-  if (managerStatus === 'ERROR') {
+function refreshTServersBanner(statusData) {
+  if (statusData.managerStatus === 'ERROR') {
     $('#tserversManagerBanner').show();
+    $('#tserversWarnBanner').hide();
+    $('#tserversErrorBanner').hide();
     $('#tservers_wrapper').hide();
     $('#recovery-caption').hide();
   } else {
     $('#tserversManagerBanner').hide();
     $('#tservers_wrapper').show();
+    if (statusData.tServerStatus === 'ERROR') {
+      $('#tserversWarnBanner').hide();
+      $('#tserversErrorBanner').show();
+    } else if (statusData.tServerStatus === 'WARN') {
+      $('#tserversWarnBanner').show();
+      $('#tserversErrorBanner').hide();
+    } else {
+      $('#tserversWarnBanner').hide();
+      $('#tserversErrorBanner').hide();
+    }
   }
 }
 
@@ -88,8 +100,9 @@ function refreshTServersBanner(managerStatus) {
  */
 function refreshTServers() {
   getStatus().then(function () {
-    var managerStatus = JSON.parse(sessionStorage.status).managerStatus;
-    refreshTServersBanner(managerStatus);
+    var statusData = JSON.parse(sessionStorage.status);
+    var managerStatus = statusData.managerStatus;
+    refreshTServersBanner(statusData);
 
     if (managerStatus === 'ERROR') {
       return;
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
index 55a6f2cad5..72875d4952 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
@@ -24,33 +24,46 @@
         </div>
       </div>
       <div class="row d-flex justify-content-center">
-        <div class="col-sm-6 col-sm-offset-3" id="manager">
-          <table class="table table-bordered table-striped table-condensed">
-            <thead>
-              <tr>
-                <th colspan="2"><a href="manager">Accumulo Manager</a></th>
-              </tr>
-              <tr>
-                <td colspan="2" class="center" style="display:none;"><span 
class="label label-danger nowrap">Manager is Down</span></td>
-              </tr>
-              <tr>
-                <td class="left">Server</td>
-                <td class="right"></td>
-              </tr>
-              <tr>
-                <td class="left">Resource&nbsp;Group</td>
-                <td class="right"></td>
-              </tr>
-              <tr>
-                <td class="left">Last&nbsp;Contact</td>
-                <td class="right"></td>
-              </tr>
-              <tr>
-                <td class="left">Metrics</td>
-                <td class="right"></td>
-              </tr>
-            </thead>
-            <tbody></tbody>
-          </table>
+        <div class="col-xs-12" id="deploymentOverview">
+          <div id="deploymentWarning"></div>
+          <div class="mb-4" style="max-width: 560px; margin: 0 auto;">
+            <table id="deploymentSummaryTable"
+              class="table table-bordered table-striped table-condensed" 
style="width: 100%;">
+              <thead>
+                <tr>
+                  <th colspan="2" class="center">Server Type Summary</th>
+                </tr>
+                <tr>
+                  <th>Server Type</th>
+                  <th>Responding / Total</th>
+                </tr>
+              </thead>
+              <tbody></tbody>
+            </table>
+          </div>
+
+          <div style="max-width: 760px; margin: 0 auto;">
+            <div class="mb-3">
+              <label for="deployment-rg-filter" class="form-label">Resource 
Group Filter</label>
+              <input type="text" id="deployment-rg-filter" class="form-control"
+                placeholder="Enter resource group regex">
+              <small id="deployment-rg-feedback" class="form-text text-danger"
+                style="display:none;">Invalid regex pattern</small>
+            </div>
+            <table id="deploymentBreakdownTable"
+              class="table table-bordered table-striped table-condensed" 
style="width: 100%;">
+              <thead>
+                <tr>
+                  <th colspan="3" class="center">Deployment Breakdown</th>
+                </tr>
+                <tr>
+                  <th>Resource Group</th>
+                  <th>Server Type</th>
+                  <th>Responding / Total</th>
+                </tr>
+              </thead>
+              <tbody></tbody>
+            </table>
+          </div>
         </div>
-      </div>
\ No newline at end of file
+      </div>
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
index ac3368e946..311938b32d 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
@@ -26,6 +26,16 @@
     <div id="tserversManagerBanner" style="display: none;">
       <div class="alert alert-danger" role="alert">Manager Not Running</div>
     </div>
+    <div id="tserversWarnBanner" style="display: none;">
+      <div class="alert alert-warning" role="alert">
+        One or more Tablet Servers are unavailable or reported as bad.
+      </div>
+    </div>
+    <div id="tserversErrorBanner" style="display: none;">
+      <div class="alert alert-danger" role="alert">
+        No Tablet Servers are currently responding.
+      </div>
+    </div>
     <div class="row">
       <div class="col-xs-12">
         <span id="recovery-caption" style="background-color: gold; display: 
none;">Highlighted rows correspond to tservers in recovery mode.</span>

Reply via email to