mirror of
https://github.com/FairwindsOps/polaris.git
synced 2026-05-09 02:36:43 +00:00
Add explanations for each error
first pass add info links to dashboard
This commit is contained in:
12
pkg/dashboard/assets/css/check-details.css
Normal file
12
pkg/dashboard/assets/css/check-details.css
Normal file
@@ -0,0 +1,12 @@
|
||||
th, td {
|
||||
padding: 4px 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Helvetica", "Arial", sans-serif
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: "Muli", "Helvetica", "Arial", sans-serif
|
||||
}
|
||||
227
pkg/dashboard/assets/css/dashboard.css
Normal file
227
pkg/dashboard/assets/css/dashboard.css
Normal file
@@ -0,0 +1,227 @@
|
||||
.charts {
|
||||
height: 405px;
|
||||
}
|
||||
|
||||
.card.cluster {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.card.namespace {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 28px;
|
||||
padding: 15px 20px 20px;
|
||||
}
|
||||
|
||||
.namespace h3 strong {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cluster-overview {
|
||||
height: 204px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .weather {
|
||||
font-size: 90px;
|
||||
color: #444;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .sailing-message {
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
margin-left: 7px;
|
||||
font-weight: 300;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .scores {
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cluster .expandable-table ul.message-list {
|
||||
margin: 10px 26px;
|
||||
}
|
||||
|
||||
#clusterScoreChart {
|
||||
width: 550px;
|
||||
position: relative;
|
||||
top: -227px;
|
||||
left: 120px;
|
||||
}
|
||||
|
||||
.cluster-overview .result-messages {
|
||||
margin: 0 20px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
left: -100px;
|
||||
top: -45px;
|
||||
}
|
||||
|
||||
.cluster-overview .result-messages ul {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
left: 400px;
|
||||
font-size: 20px;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.card.cluster .expandable-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.card.cluster .detail-label {
|
||||
display: inline-block;
|
||||
min-width: 140px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.expandable-table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.expandable-table tr {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.expandable-table td {
|
||||
padding: 15px 20px;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .name {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .caret-expander {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 10px;
|
||||
background-image: url('../images/caret-right.svg');
|
||||
background-size: 13px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .caret-expander {
|
||||
background-image: url('../images/caret-bottom.svg');
|
||||
background-position: center 2px;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .expandable-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .expandable-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.namespace .resource-info .result-messages {
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
.namespace .result-messages h4 {
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
margin: 15px 25px 6px;
|
||||
}
|
||||
|
||||
ul.message-list {
|
||||
list-style-type: none;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
margin: 5px 35px;
|
||||
padding: 0;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
ul.message-list li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.message-list li i.message-icon {
|
||||
display: inline-block;
|
||||
margin-right: 7px;
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
bottom: -3px;
|
||||
}
|
||||
|
||||
.result-messages .success i.message-icon {
|
||||
color: #8BD2DC;
|
||||
}
|
||||
|
||||
.result-messages .warning i.message-icon {
|
||||
color: #f26c21;
|
||||
}
|
||||
|
||||
.result-messages .error i.message-icon {
|
||||
color: #a11f4c;
|
||||
}
|
||||
|
||||
a.more-info {
|
||||
color: #6a6a6a;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.namespace .status-bar {
|
||||
vertical-align: top;
|
||||
padding-top: 18px;
|
||||
}
|
||||
.namespace .status-bar .status {
|
||||
float: right;
|
||||
animation: fadeIn 2s;
|
||||
}
|
||||
|
||||
.cluster .status {
|
||||
width: 280px;
|
||||
}
|
||||
.namespace .status {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.status div {
|
||||
height: 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status .passing {
|
||||
background-color: #8BD2DC;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.status .warning {
|
||||
background-color: #f26c21;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.status .failing {
|
||||
background-color: #a11f4c;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
@@ -2,50 +2,47 @@ body {
|
||||
margin: 0;
|
||||
font-family: 'Muli', 'Helvetica', 'Arial', sans-serif;
|
||||
background: #f5f5f5;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
.navbar {
|
||||
padding: 20px 20px 0;
|
||||
}
|
||||
|
||||
.header .header-content {
|
||||
.navbar .navbar-content {
|
||||
margin: 0 auto;
|
||||
width: 900px;
|
||||
}
|
||||
|
||||
.header .header-right {
|
||||
.navbar .navbar-right {
|
||||
padding: 15px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.header .logo {
|
||||
.navbar .logo {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.header span.oss-text {
|
||||
.navbar span.oss-text {
|
||||
color: #23103A;
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.header a {
|
||||
.navbar a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.header .ro-logo {
|
||||
.navbar .ro-logo {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
.main-content {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.charts {
|
||||
height: 405px;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 25px 20px;
|
||||
padding: 20px;
|
||||
@@ -55,225 +52,6 @@ body {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.card.cluster {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
|
||||
.card.namespace {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin: 0;
|
||||
font-weight: 300;
|
||||
font-size: 28px;
|
||||
padding: 15px 20px 20px;
|
||||
}
|
||||
|
||||
.namespace h3 strong {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cluster-overview {
|
||||
height: 204px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score {
|
||||
width: 200px;
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .weather {
|
||||
font-size: 90px;
|
||||
color: #444;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .sailing-message {
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
margin-left: 7px;
|
||||
font-weight: 300;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.cluster-overview .cluster-score .scores {
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.cluster .expandable-table ul.message-list {
|
||||
margin: 10px 26px;
|
||||
}
|
||||
|
||||
#clusterScoreChart {
|
||||
width: 550px;
|
||||
position: relative;
|
||||
top: -242px;
|
||||
left: 120px;
|
||||
}
|
||||
|
||||
.cluster-overview .result-messages {
|
||||
margin: 0 20px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
left: -100px;
|
||||
top: -45px;
|
||||
}
|
||||
|
||||
.cluster-overview .result-messages ul {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
left: 400px;
|
||||
font-size: 20px;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.card.cluster .expandable-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.card.cluster .detail-label {
|
||||
display: inline-block;
|
||||
min-width: 140px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.expandable-table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.expandable-table tr {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.expandable-table td {
|
||||
padding: 15px 20px;
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .name {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .caret-expander {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
margin-right: 10px;
|
||||
background-image: url('../images/caret-right.svg');
|
||||
background-size: 13px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 2px center;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .caret-expander {
|
||||
background-image: url('../images/caret-bottom.svg');
|
||||
background-position: center 2px;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info .expandable-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.expandable-table .resource-info.expanded .expandable-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.namespace .resource-info .result-messages {
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
.namespace .result-messages h4 {
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
margin: 15px 25px 6px;
|
||||
}
|
||||
|
||||
ul.message-list {
|
||||
list-style-type: none;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
margin: 5px 35px;
|
||||
padding: 0;
|
||||
color: #6a6a6a;
|
||||
}
|
||||
|
||||
ul.message-list li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
ul.message-list li i {
|
||||
display: inline-block;
|
||||
margin-right: 7px;
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
font-size: 17px;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
bottom: -3px;
|
||||
}
|
||||
|
||||
.result-messages .success i {
|
||||
color: #8BD2DC;
|
||||
}
|
||||
|
||||
.result-messages .warning i {
|
||||
color: #f26c21;
|
||||
}
|
||||
|
||||
.result-messages .error i {
|
||||
color: #a11f4c;
|
||||
}
|
||||
|
||||
.namespace .status-bar {
|
||||
vertical-align: top;
|
||||
padding-top: 18px;
|
||||
}
|
||||
.namespace .status-bar .status {
|
||||
float: right;
|
||||
animation: fadeIn 2s;
|
||||
}
|
||||
|
||||
.cluster .status {
|
||||
width: 280px;
|
||||
}
|
||||
.namespace .status {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.status div {
|
||||
height: 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status .passing {
|
||||
background-color: #8BD2DC;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.status .warning {
|
||||
background-color: #f26c21;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.status .failing {
|
||||
background-color: #a11f4c;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {opacity: 0;}
|
||||
100% {opacity: 1;}
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding-top: 10px;
|
||||
@@ -288,3 +66,4 @@ ul.message-list li i {
|
||||
.footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,24 +25,30 @@ import (
|
||||
"github.com/reactiveops/fairwinds/pkg/kube"
|
||||
"github.com/reactiveops/fairwinds/pkg/validator"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gitlab.com/golang-commonmark/markdown"
|
||||
)
|
||||
|
||||
const (
|
||||
// MainTemplateName is the main template
|
||||
MainTemplateName = "main.gohtml"
|
||||
// HeaderTemplateName contains the navbar
|
||||
HeaderTemplateName = "header.gohtml"
|
||||
// HeadTemplateName contains styles and meta info
|
||||
HeadTemplateName = "head.gohtml"
|
||||
// NavbarTemplateName contains the navbar
|
||||
NavbarTemplateName = "navbar.gohtml"
|
||||
// PreambleTemplateName contains an empty preamble that can be overridden
|
||||
PreambleTemplateName = "preamble.gohtml"
|
||||
// DashboardTemplateName contains the content of the dashboard
|
||||
DashboardTemplateName = "dashboard.gohtml"
|
||||
// FooterTemplateName contains the footer
|
||||
FooterTemplateName = "footer.gohtml"
|
||||
// CheckDetailsTemplateName is a page for rendering details about a given check
|
||||
CheckDetailsTemplateName = "check-details.gohtml"
|
||||
)
|
||||
|
||||
var (
|
||||
templateBox = (*packr.Box)(nil)
|
||||
assetBox = (*packr.Box)(nil)
|
||||
markdownBox = (*packr.Box)(nil)
|
||||
)
|
||||
|
||||
// GetAssetBox returns a binary-friendly set of assets packaged from disk
|
||||
@@ -61,6 +67,14 @@ func GetTemplateBox() *packr.Box {
|
||||
return templateBox
|
||||
}
|
||||
|
||||
// GetMarkdownBox returns a binary-friendly set of markdown files with error details
|
||||
func GetMarkdownBox() *packr.Box {
|
||||
if markdownBox == (*packr.Box)(nil) {
|
||||
markdownBox = packr.New("Markdown", "../../docs")
|
||||
}
|
||||
return markdownBox
|
||||
}
|
||||
|
||||
// TemplateData is passed to the dashboard HTML template
|
||||
type TemplateData struct {
|
||||
AuditData validator.AuditData
|
||||
@@ -77,16 +91,22 @@ func GetBaseTemplate(name string) (*template.Template, error) {
|
||||
"getGrade": getGrade,
|
||||
"getScore": getScore,
|
||||
"getIcon": getIcon,
|
||||
"getCategoryLink": getCategoryLink,
|
||||
})
|
||||
|
||||
templateBox := GetTemplateBox()
|
||||
templateFileNames := []string{
|
||||
DashboardTemplateName,
|
||||
HeaderTemplateName,
|
||||
HeadTemplateName,
|
||||
NavbarTemplateName,
|
||||
PreambleTemplateName,
|
||||
FooterTemplateName,
|
||||
MainTemplateName,
|
||||
}
|
||||
return parseTemplateFiles(tmpl, templateFileNames)
|
||||
}
|
||||
|
||||
func parseTemplateFiles(tmpl *template.Template, templateFileNames []string) (*template.Template, error) {
|
||||
templateBox := GetTemplateBox()
|
||||
for _, fname := range templateFileNames {
|
||||
templateFile, err := templateBox.Find(fname)
|
||||
if err != nil {
|
||||
@@ -101,6 +121,16 @@ func GetBaseTemplate(name string) (*template.Template, error) {
|
||||
return tmpl, nil
|
||||
}
|
||||
|
||||
func writeTemplate(tmpl *template.Template, data *TemplateData, w http.ResponseWriter) {
|
||||
buf := &bytes.Buffer{}
|
||||
err := tmpl.Execute(buf, data)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
buf.WriteTo(w)
|
||||
}
|
||||
|
||||
// MainHandler gets template data and renders the dashboard with it.
|
||||
func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.AuditData) {
|
||||
jsonData, err := json.Marshal(auditData)
|
||||
@@ -120,23 +150,14 @@ func MainHandler(w http.ResponseWriter, r *http.Request, auditData validator.Aud
|
||||
http.Error(w, "Error getting template data", 500)
|
||||
return
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err = tmpl.ExecuteTemplate(buf, "main", templateData)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buf.WriteTo(w)
|
||||
writeTemplate(tmpl, &templateData, w)
|
||||
}
|
||||
|
||||
// EndpointHandler gets template data and renders json with it.
|
||||
func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, kubeResources *kube.ResourceProvider) {
|
||||
templateData, err := validator.RunAudit(c, kubeResources)
|
||||
if err != nil {
|
||||
http.Error(w, "Error Fetching Deployments", 500)
|
||||
http.Error(w, "Error Fetching Deployments", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -144,3 +165,31 @@ func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuratio
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(templateData)
|
||||
}
|
||||
|
||||
// DetailsHandler returns details for a given error type
|
||||
func DetailsHandler(w http.ResponseWriter, r *http.Request, category string) {
|
||||
box := GetMarkdownBox()
|
||||
contents, err := box.Find(category + ".md")
|
||||
if err != nil {
|
||||
http.Error(w, "Error details not found for category "+category, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
md := markdown.New(markdown.XHTMLOutput(true))
|
||||
detailsHTML := "{{ define \"details\" }}" + md.RenderToString(contents) + "{{ end }}"
|
||||
|
||||
templateFileNames := []string{
|
||||
HeadTemplateName,
|
||||
NavbarTemplateName,
|
||||
CheckDetailsTemplateName,
|
||||
FooterTemplateName,
|
||||
}
|
||||
tmpl := template.New("check-details")
|
||||
tmpl, err = parseTemplateFiles(tmpl, templateFileNames)
|
||||
if err != nil {
|
||||
logrus.Printf("Error getting template data %v", err)
|
||||
http.Error(w, "Error getting template data", 500)
|
||||
return
|
||||
}
|
||||
tmpl.Parse(detailsHTML)
|
||||
writeTemplate(tmpl, nil, w)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package dashboard
|
||||
|
||||
import (
|
||||
"github.com/reactiveops/fairwinds/pkg/validator"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getWarningWidth(counts validator.CountSummary, fullWidth int) uint {
|
||||
@@ -26,6 +27,10 @@ func getSuccessWidth(counts validator.CountSummary, fullWidth int) uint {
|
||||
return uint(float64(counts.Successes) / float64(counts.Successes+counts.Warnings+counts.Errors) * float64(fullWidth))
|
||||
}
|
||||
|
||||
func getCategoryLink(category string) string {
|
||||
return strings.Replace(strings.ToLower(category), " ", "-", -1)
|
||||
}
|
||||
|
||||
func getGrade(rs validator.ResultSummary) string {
|
||||
score := getScore(rs)
|
||||
if score >= 97 {
|
||||
|
||||
17
pkg/dashboard/templates/check-details.gohtml
Normal file
17
pkg/dashboard/templates/check-details.gohtml
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{{ template "head" . }}
|
||||
<link rel="stylesheet" href="/static/css/check-details.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{ template "navbar" . }}
|
||||
<div class="main-content">
|
||||
<div class="card">
|
||||
{{ template "details" . }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,9 +9,9 @@
|
||||
</div>
|
||||
<div class="result-messages">
|
||||
<ul class="message-list">
|
||||
<li class="success"><i class="fas fa-check"></i> {{ .AuditData.ClusterSummary.Results.Totals.Successes }} checks passed</li>
|
||||
<li class="warning"><i class="fas fa-exclamation"></i> {{ .AuditData.ClusterSummary.Results.Totals.Warnings }} checks had warnings</li>
|
||||
<li class="error"><i class="fas fa-times"></i> {{ .AuditData.ClusterSummary.Results.Totals.Errors }} checks had errors</li>
|
||||
<li class="success"><i class="message-icon fas fa-check"></i> {{ .AuditData.ClusterSummary.Results.Totals.Successes }} checks passed</li>
|
||||
<li class="warning"><i class="message-icon fas fa-exclamation"></i> {{ .AuditData.ClusterSummary.Results.Totals.Warnings }} checks had warnings</li>
|
||||
<li class="error"><i class="message-icon fas fa-times"></i> {{ .AuditData.ClusterSummary.Results.Totals.Errors }} checks had errors</li>
|
||||
</ul>
|
||||
</div>
|
||||
<canvas id="clusterScoreChart"></canvas>
|
||||
@@ -82,7 +82,13 @@
|
||||
<h4>Pod Spec:</h4>
|
||||
<ul class="message-list">
|
||||
{{ range $message := .PodResult.Messages}}
|
||||
<li class="{{ .Type }}"><i class="{{ getIcon $message }}"></i> {{ .Message }}</li>
|
||||
<li class="{{ .Type }}">
|
||||
<i class="message-icon {{ getIcon $message }}"></i>
|
||||
<a class="more-info" href="/details/{{ getCategoryLink .Category }}">
|
||||
<i class="far fa-question-circle"></i>
|
||||
</a>
|
||||
<span class="message">{{ .Message }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -91,7 +97,13 @@
|
||||
<h4>Container: {{ .Name }}</h4>
|
||||
<ul class="message-list">
|
||||
{{ range $message := .Messages}}
|
||||
<li class="{{ .Type }}"><i class="{{ getIcon $message }}"></i> {{ .Message }}</li>
|
||||
<li class="{{ .Type }}">
|
||||
<i class="message-icon {{ getIcon $message }}"></i>
|
||||
<a class="more-info" href="/details/{{ getCategoryLink .Category }}">
|
||||
<i class="far fa-question-circle"></i>
|
||||
</a>
|
||||
<span class="message">{{ .Message }}</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
14
pkg/dashboard/templates/head.gohtml
Normal file
14
pkg/dashboard/templates/head.gohtml
Normal file
@@ -0,0 +1,14 @@
|
||||
{{ define "head" }}
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="icon" type="image/png" href="/static/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/static/favicon-16x16.png" sizes="16x16" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:300,400,700" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/normalize.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
|
||||
{{ end }}
|
||||
@@ -2,19 +2,8 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<title>Fairwinds</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="icon" type="image/png" href="/static/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/static/favicon-16x16.png" sizes="16x16" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Muli:300,400,700" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/normalize.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
|
||||
|
||||
{{ template "head" . }}
|
||||
<link rel="stylesheet" href="/static/css/dashboard.css">
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cash/3.0.0-beta.3/cash.min.js"></script>
|
||||
<script>
|
||||
@@ -24,8 +13,8 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{ template "header" . }}
|
||||
<div class="dashboard-content">
|
||||
{{ template "navbar" . }}
|
||||
<div class="main-content">
|
||||
{{ template "preamble" . }}
|
||||
{{ template "dashboard" . }}
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{{define "header"}}
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<img class="logo" src="/static/images/polaris-logo.png" alt="Polaris" />
|
||||
<div class="header-right">
|
||||
{{define "navbar"}}
|
||||
<div class="navbar">
|
||||
<div class="navbar-content">
|
||||
<a href="/">
|
||||
<img class="logo" src="/static/images/polaris-logo.png" alt="Polaris" />
|
||||
</a>
|
||||
<div class="navbar-right">
|
||||
<a href="https://reactiveops.com?source=fairwinds" target="_blank">
|
||||
<span class="oss-text">Open Source Project By</span>
|
||||
<img class="ro-logo" src="/static/images/ro-logo.png" alt="ReactiveOps" />
|
||||
Reference in New Issue
Block a user