SLIDER-1210 Expose diagnostics information as a summary table in AM UI landing page as well
diff --git a/slider-core/src/main/java/org/apache/slider/api/types/ContainerInformation.java b/slider-core/src/main/java/org/apache/slider/api/types/ContainerInformation.java
index 25ef310..3b5b590 100644
--- a/slider-core/src/main/java/org/apache/slider/api/types/ContainerInformation.java
+++ b/slider-core/src/main/java/org/apache/slider/api/types/ContainerInformation.java
@@ -18,6 +18,9 @@
 
 package org.apache.slider.api.types;
 
+import java.io.Serializable;
+import java.util.Comparator;
+
 import org.apache.hadoop.registry.client.binding.JsonSerDeser;
 import org.codehaus.jackson.annotate.JsonIgnoreProperties;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
@@ -143,4 +146,15 @@
             ContainerInformation.class);
     return serDeser.toString(this);
   }
+
+  /**
+   * Compare two containers by their ids.
+   */
+  public static class CompareById implements Comparator<ContainerInformation>,
+      Serializable {
+    @Override
+    public int compare(ContainerInformation c1, ContainerInformation c2) {
+      return c1.getContainerId().compareTo(c2.getContainerId());
+    }
+  }
 }
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
index c3b9b6f..3d9dbaf 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/view/IndexBlock.java
@@ -24,8 +24,9 @@
 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.UL;
 import org.apache.slider.api.ClusterDescription;
 import org.apache.slider.api.StatusKeys;
+import org.apache.slider.api.types.ApplicationDiagnostics;
 import org.apache.slider.api.types.ApplicationLivenessInformation;
-import org.apache.slider.api.types.RoleStatistics;
+import org.apache.slider.api.types.ContainerInformation;
 import org.apache.slider.common.tools.SliderUtils;
 import org.apache.slider.core.registry.docstore.ExportEntry;
 import org.apache.slider.core.registry.docstore.PublishedExports;
@@ -183,10 +184,6 @@
     containers._();
     containers = null;
 
-    // some spacing
-    html.div()._();
-    html.div()._();
-
     DIV<Hamlet> diagnostics = html.div("diagnostics");
 
     List<String> statusEntries = new ArrayList<>(0);
@@ -228,6 +225,44 @@
     enumeratePublishedExports(appState.getPublishedExportsSet(), ul);
     ul._();
     exports._();
+
+    DIV<Hamlet> appDiagnosticsDiv = html.div("app_diagnostics")
+        .h3("Application Container Diagnostics");
+
+    Hamlet.TABLE<DIV<Hamlet>> appDiagnosticsTable = appDiagnosticsDiv.table();
+    Hamlet.TR<Hamlet.THEAD<Hamlet.TABLE<DIV<Hamlet>>>> appDiagnosticsHeader = 
+        appDiagnosticsTable.thead().tr();
+    trb(appDiagnosticsHeader, "Container ID");
+    trb(appDiagnosticsHeader, "Component");
+    trb(appDiagnosticsHeader, "State");
+    trb(appDiagnosticsHeader, "Exit Code");
+    trb(appDiagnosticsHeader, "Logs");
+    trb(appDiagnosticsHeader, "Diagnostics");
+    appDiagnosticsHeader._()._(); // tr & thread
+
+    ApplicationDiagnostics appDiagnostics = appState
+        .getApplicationDiagnostics();
+    List<ContainerInformation> appContainers = new ArrayList<>(
+        appDiagnostics.getContainers());
+    Collections.sort(appContainers, new ContainerInformation.CompareById());
+    for (ContainerInformation appContainer : appContainers) {
+      String diagText = String.format("%s",
+          appContainer.getDiagnostics() == null ? ""
+              : appContainer.getDiagnostics());
+      appDiagnosticsTable.tr()
+          .td(appContainer.getContainerId())
+          .td(appContainer.getComponent())
+          .td(String.format("%d", appContainer.getState()))
+          .td(String.format("%d", appContainer.getExitCode()))
+          .td().a(appContainer.getLogLink(), "Logs")._()
+          .td(diagText)
+          ._();
+    }
+
+    // close table and div
+    appDiagnosticsTable._();
+    appDiagnosticsDiv._();
+    appDiagnosticsDiv = null;
   }
 
   @VisibleForTesting
diff --git a/slider-core/src/main/resources/webapps/static/yarn.css b/slider-core/src/main/resources/webapps/static/yarn.css
index 1e9ca94..7f9f862 100644
--- a/slider-core/src/main/resources/webapps/static/yarn.css
+++ b/slider-core/src/main/resources/webapps/static/yarn.css
@@ -61,5 +61,7 @@
 div.container_instances { margin-bottom: 15px; }
 div.diagnostics { margin-bottom: 15px; }
 div.provider_info { margin-bottom: 15px; }
+div.exports { margin-bottom: 15px; }
+div.app_diagnostics { margin-bottom: 15px; }
 
 div.cluster_json pre { white-space: pre-wrap; }