refactor: html output custom style
parent
a14a72f212
commit
a27d993b13
|
@ -4,16 +4,28 @@
|
||||||
<title>Driftctl scan report</title>
|
<title>Driftctl scan report</title>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<link rel="shortcut icon"
|
||||||
|
href="https://raw.githubusercontent.com/cloudskiff/driftctl-docs/main/static/img/favicon.ico"/>
|
||||||
<style>{{.Stylesheet}}</style>
|
<style>{{.Stylesheet}}</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="heading d-flex justify-space-between align-center">
|
<div class="heading d-flex justify-space-between align-center">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="heading-title">Driftctl scan report</h1>
|
<h1 class="heading-title mb-1">Driftctl scan report</h1>
|
||||||
<span class="heading-subtitle">Coverage {{.Coverage}}%</span>
|
<span class="heading-subtitle">Coverage {{.Coverage}}%</span>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="heading-date">{{ .ScanDate }}</h2>
|
<div class="text--right">
|
||||||
|
<h2 class="heading-date mb-1">{{ .ScanDate }}</h2>
|
||||||
|
<span class="heading-subtitle">Scan duration {{.ScanDuration}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card d-flex justify-space-around mb-2 text--grey">
|
||||||
|
<span>Total resources: {{.Summary.TotalResources}}</span>
|
||||||
|
<span>Managed: {{rate .Summary.TotalManaged}}%</span>
|
||||||
|
<span>Changed: {{.Summary.TotalDrifted}}/{{.Summary.TotalManaged}}</span>
|
||||||
|
<span>Unmanaged: {{rate .Summary.TotalUnmanaged}}%</span>
|
||||||
|
<span>Missing: {{rate .Summary.TotalDeleted}}%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-content">
|
<div class="app-content">
|
||||||
{{ if (lt .Coverage 100) }}
|
{{ if (lt .Coverage 100) }}
|
||||||
|
@ -56,16 +68,24 @@
|
||||||
<div class="panels">
|
<div class="panels">
|
||||||
{{ if (gt (len .Unmanaged) 0) }}
|
{{ if (gt (len .Unmanaged) 0) }}
|
||||||
<div class="panel" id="one-panel">
|
<div class="panel" id="one-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
{{range $res := .Unmanaged}}
|
{{range $res := .Unmanaged}}
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">{{$res.TerraformId}}</span>
|
<span class="resource-item-id">{{$res.TerraformId}}</span>
|
||||||
<span class="resource-item-type text--bold">{{$res.TerraformType}}</span>
|
<span class="resource-item-type">{{$res.TerraformType}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ if (gt (len .Differences) 0) }}
|
{{ if (gt (len .Differences) 0) }}
|
||||||
<div class="panel" id="two-panel">
|
<div class="panel" id="two-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
{{range $diff := .Differences}}
|
{{range $diff := .Differences}}
|
||||||
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
||||||
<span class="resource-item-id">{{$diff.Res.TerraformId}}</span>
|
<span class="resource-item-id">{{$diff.Res.TerraformId}}</span>
|
||||||
|
@ -74,17 +94,21 @@
|
||||||
<div>{{ formatChange $change }}</div>
|
<div>{{ formatChange $change }}</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<span class="resource-item-type text--bold">{{$diff.Res.TerraformType}}</span>
|
<span class="resource-item-type">{{$diff.Res.TerraformType}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{ if (gt (len .Deleted) 0) }}
|
{{ if (gt (len .Deleted) 0) }}
|
||||||
<div class="panel" id="three-panel">
|
<div class="panel" id="three-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
{{range $res := .Deleted}}
|
{{range $res := .Deleted}}
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">{{$res.TerraformId}}</span>
|
<span class="resource-item-id">{{$res.TerraformId}}</span>
|
||||||
<span class="resource-item-type text--bold">{{$res.TerraformType}}</span>
|
<span class="resource-item-type">{{$res.TerraformType}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -94,8 +118,8 @@
|
||||||
{{range $type, $messages := .Alerts}}
|
{{range $type, $messages := .Alerts}}
|
||||||
{{range $el := $messages}}
|
{{range $el := $messages}}
|
||||||
<div class="resource-item resource-item-alerts">
|
<div class="resource-item resource-item-alerts">
|
||||||
<span class="resource-item-type text--bold">{{ $type }}</span>
|
<span class="resource-item-type">{{ $type }}</span>
|
||||||
<span>- {{ $el.Message }}</span>
|
<span>{{ $el.Message }}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;600&display=swap');
|
|
||||||
|
|
||||||
/* http://meyerweb.com/eric/tools/css/reset/
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
v2.0 | 20110126
|
v2.0 | 20110126
|
||||||
License: none (public domain)
|
License: none (public domain)
|
||||||
|
@ -20,7 +18,6 @@ time, mark, audio, video {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: 100%;
|
|
||||||
font: inherit;
|
font: inherit;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +42,6 @@ blockquote, q {
|
||||||
|
|
||||||
blockquote:before, blockquote:after,
|
blockquote:before, blockquote:after,
|
||||||
q:before, q:after {
|
q:before, q:after {
|
||||||
content: '';
|
|
||||||
content: none;
|
content: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +58,7 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
font-family: "Helvetica", sans-serif;
|
||||||
color: #1C1E21;
|
color: #1C1E21;
|
||||||
background-color: #F7F7F9;
|
background-color: #F7F7F9;
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
|
@ -127,6 +123,26 @@ div.container {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pa-1 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-1 {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-1 {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-1 {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-1 {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
select {
|
select {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -144,6 +160,7 @@ select:focus {
|
||||||
|
|
||||||
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -157,21 +174,32 @@ h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading-title {
|
.heading-title {
|
||||||
margin-bottom: 10px;
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-content {
|
.app-content {
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
border-top: 3px solid #71B2C3;
|
border-top: 3px solid #71B2C3;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 0 0 10px 10px;
|
box-shadow: 0 0 5px #0000000a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-item {
|
.resource-item {
|
||||||
border: 1px solid #ececec;
|
border-top: 1px solid #ececec;
|
||||||
padding: 10px;
|
border-left: 1px solid #ececec;
|
||||||
margin-top: 10px;
|
border-right: 1px solid #ececec;
|
||||||
|
padding: 15px;
|
||||||
color: #6e7071;
|
color: #6e7071;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:last-child {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-item:hover {
|
.resource-item:hover {
|
||||||
|
@ -182,6 +210,22 @@ h2 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text--grey {
|
||||||
|
color: #747578;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.reset-filter-btn {
|
.reset-filter-btn {
|
||||||
border: none;
|
border: none;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -206,6 +250,7 @@ h2 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: #747578;
|
color: #747578;
|
||||||
transition: background-color 200ms;
|
transition: background-color 200ms;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
|
@ -251,9 +296,8 @@ h2 {
|
||||||
#two:checked ~ .tabs #two-tab,
|
#two:checked ~ .tabs #two-tab,
|
||||||
#three:checked ~ .tabs #three-tab,
|
#three:checked ~ .tabs #three-tab,
|
||||||
#four:checked ~ .tabs #four-tab {
|
#four:checked ~ .tabs #four-tab {
|
||||||
background: transparent;
|
background: #71b2c3;
|
||||||
color: #747578;
|
color: #ffffff;
|
||||||
border-bottom: 2px solid #71b2c3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-message-container {
|
.empty-message-container {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -34,6 +35,7 @@ type HTMLTemplateParams struct {
|
||||||
Deleted []resource.Resource
|
Deleted []resource.Resource
|
||||||
Alerts alerter.Alerts
|
Alerts alerter.Alerts
|
||||||
Stylesheet template.CSS
|
Stylesheet template.CSS
|
||||||
|
ScanDuration string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTML(path string) *HTML {
|
func NewHTML(path string) *HTML {
|
||||||
|
@ -92,6 +94,12 @@ func (c *HTML) Write(analysis *analyser.Analysis) error {
|
||||||
|
|
||||||
return fmt.Sprintf("%s %s: %s => %s %s", prefix, strings.Join(ch.Path, "."), prettify(ch.From), prettify(ch.To), suffix)
|
return fmt.Sprintf("%s %s: %s => %s %s", prefix, strings.Join(ch.Path, "."), prettify(ch.From), prettify(ch.To), suffix)
|
||||||
},
|
},
|
||||||
|
"rate": func(count int) float64 {
|
||||||
|
if analysis.Summary().TotalResources == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return math.Round(100 * float64(count) / float64(analysis.Summary().TotalResources))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("main").Funcs(funcMap).Parse(string(tmplFile))
|
tmpl, err := template.New("main").Funcs(funcMap).Parse(string(tmplFile))
|
||||||
|
@ -108,6 +116,7 @@ func (c *HTML) Write(analysis *analyser.Analysis) error {
|
||||||
Deleted: analysis.Deleted(),
|
Deleted: analysis.Deleted(),
|
||||||
Alerts: analysis.Alerts(),
|
Alerts: analysis.Alerts(),
|
||||||
Stylesheet: template.CSS(styleFile),
|
Stylesheet: template.CSS(styleFile),
|
||||||
|
ScanDuration: analysis.Duration.Round(time.Second).String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tmpl.Execute(file, data)
|
err = tmpl.Execute(file, data)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||||
testresource "github.com/cloudskiff/driftctl/test/resource"
|
testresource "github.com/cloudskiff/driftctl/test/resource"
|
||||||
|
@ -21,12 +22,38 @@ func TestHTML_Write(t *testing.T) {
|
||||||
analysis func() *analyser.Analysis
|
analysis func() *analyser.Analysis
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "test html output when there's no resources",
|
||||||
|
goldenfile: "output_empty.html",
|
||||||
|
analysis: func() *analyser.Analysis {
|
||||||
|
a := &analyser.Analysis{}
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "test html output when infrastructure is in sync",
|
||||||
|
goldenfile: "output_sync.html",
|
||||||
|
analysis: func() *analyser.Analysis {
|
||||||
|
a := &analyser.Analysis{}
|
||||||
|
a.Duration = 72 * time.Second
|
||||||
|
a.AddManaged(
|
||||||
|
&testresource.FakeResource{
|
||||||
|
Id: "deleted-id-3",
|
||||||
|
Type: "aws_deleted_resource",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "test html output",
|
name: "test html output",
|
||||||
goldenfile: "output.html",
|
goldenfile: "output.html",
|
||||||
|
|
||||||
analysis: func() *analyser.Analysis {
|
analysis: func() *analyser.Analysis {
|
||||||
a := fakeAnalysisWithAlerts()
|
a := fakeAnalysisWithAlerts()
|
||||||
|
a.Duration = 91 * time.Second
|
||||||
a.AddDeleted(
|
a.AddDeleted(
|
||||||
&testresource.FakeResource{
|
&testresource.FakeResource{
|
||||||
Id: "deleted-id-3",
|
Id: "deleted-id-3",
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
<title>Driftctl scan report</title>
|
<title>Driftctl scan report</title>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<style>@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;600&display=swap');
|
<link rel="shortcut icon"
|
||||||
|
href="https://raw.githubusercontent.com/cloudskiff/driftctl-docs/main/static/img/favicon.ico"/>
|
||||||
/* http://meyerweb.com/eric/tools/css/reset/
|
<style>/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
v2.0 | 20110126
|
v2.0 | 20110126
|
||||||
License: none (public domain)
|
License: none (public domain)
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,6 @@ time, mark, audio, video {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: 100%;
|
|
||||||
font: inherit;
|
font: inherit;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +50,6 @@ blockquote, q {
|
||||||
|
|
||||||
blockquote:before, blockquote:after,
|
blockquote:before, blockquote:after,
|
||||||
q:before, q:after {
|
q:before, q:after {
|
||||||
content: '';
|
|
||||||
content: none;
|
content: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +66,7 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Source Sans Pro', sans-serif;
|
font-family: "Helvetica", sans-serif;
|
||||||
color: #1C1E21;
|
color: #1C1E21;
|
||||||
background-color: #F7F7F9;
|
background-color: #F7F7F9;
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
|
@ -133,6 +131,26 @@ div.container {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pa-1 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-1 {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-1 {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-1 {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-1 {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
select {
|
select {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -150,6 +168,7 @@ select:focus {
|
||||||
|
|
||||||
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -163,21 +182,32 @@ h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading-title {
|
.heading-title {
|
||||||
margin-bottom: 10px;
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-content {
|
.app-content {
|
||||||
padding: 25px;
|
padding: 25px;
|
||||||
border-top: 3px solid #71B2C3;
|
border-top: 3px solid #71B2C3;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 0 0 10px 10px;
|
box-shadow: 0 0 5px #0000000a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-item {
|
.resource-item {
|
||||||
border: 1px solid #ececec;
|
border-top: 1px solid #ececec;
|
||||||
padding: 10px;
|
border-left: 1px solid #ececec;
|
||||||
margin-top: 10px;
|
border-right: 1px solid #ececec;
|
||||||
|
padding: 15px;
|
||||||
color: #6e7071;
|
color: #6e7071;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:last-child {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resource-item:hover {
|
.resource-item:hover {
|
||||||
|
@ -188,6 +218,22 @@ h2 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text--grey {
|
||||||
|
color: #747578;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.reset-filter-btn {
|
.reset-filter-btn {
|
||||||
border: none;
|
border: none;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -212,6 +258,7 @@ h2 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: #747578;
|
color: #747578;
|
||||||
transition: background-color 200ms;
|
transition: background-color 200ms;
|
||||||
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
|
@ -257,9 +304,8 @@ h2 {
|
||||||
#two:checked ~ .tabs #two-tab,
|
#two:checked ~ .tabs #two-tab,
|
||||||
#three:checked ~ .tabs #three-tab,
|
#three:checked ~ .tabs #three-tab,
|
||||||
#four:checked ~ .tabs #four-tab {
|
#four:checked ~ .tabs #four-tab {
|
||||||
background: transparent;
|
background: #71b2c3;
|
||||||
color: #747578;
|
color: #ffffff;
|
||||||
border-bottom: 2px solid #71b2c3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-message-container {
|
.empty-message-container {
|
||||||
|
@ -270,10 +316,20 @@ h2 {
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="heading d-flex justify-space-between align-center">
|
<div class="heading d-flex justify-space-between align-center">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="heading-title">Driftctl scan report</h1>
|
<h1 class="heading-title mb-1">Driftctl scan report</h1>
|
||||||
<span class="heading-subtitle">Coverage 15%</span>
|
<span class="heading-subtitle">Coverage 15%</span>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="heading-date">Jun 07, 2021</h2>
|
<div class="text--right">
|
||||||
|
<h2 class="heading-date mb-1">Jun 08, 2021</h2>
|
||||||
|
<span class="heading-subtitle">Scan duration 1m31s</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card d-flex justify-space-around mb-2 text--grey">
|
||||||
|
<span>Total resources: 13</span>
|
||||||
|
<span>Managed: 15%</span>
|
||||||
|
<span>Changed: 2/2</span>
|
||||||
|
<span>Unmanaged: 38%</span>
|
||||||
|
<span>Missing: 46%</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-content">
|
<div class="app-content">
|
||||||
|
|
||||||
|
@ -320,36 +376,44 @@ h2 {
|
||||||
<div class="panels">
|
<div class="panels">
|
||||||
|
|
||||||
<div class="panel" id="one-panel">
|
<div class="panel" id="one-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">unmanaged-id-1</span>
|
<span class="resource-item-id">unmanaged-id-1</span>
|
||||||
<span class="resource-item-type text--bold">aws_unmanaged_resource</span>
|
<span class="resource-item-type">aws_unmanaged_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">unmanaged-id-2</span>
|
<span class="resource-item-id">unmanaged-id-2</span>
|
||||||
<span class="resource-item-type text--bold">aws_unmanaged_resource</span>
|
<span class="resource-item-type">aws_unmanaged_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">unmanaged-id-3</span>
|
<span class="resource-item-id">unmanaged-id-3</span>
|
||||||
<span class="resource-item-type text--bold">aws_unmanaged_resource</span>
|
<span class="resource-item-type">aws_unmanaged_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">unmanaged-id-4</span>
|
<span class="resource-item-id">unmanaged-id-4</span>
|
||||||
<span class="resource-item-type text--bold">aws_unmanaged_resource</span>
|
<span class="resource-item-type">aws_unmanaged_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
<div class="resource-item resource-item-unmanaged d-flex justify-space-between">
|
||||||
<span class="resource-item-id">unmanaged-id-5</span>
|
<span class="resource-item-id">unmanaged-id-5</span>
|
||||||
<span class="resource-item-type text--bold">aws_unmanaged_resource</span>
|
<span class="resource-item-type">aws_unmanaged_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="panel" id="two-panel">
|
<div class="panel" id="two-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
||||||
<span class="resource-item-id">diff-id-1</span>
|
<span class="resource-item-id">diff-id-1</span>
|
||||||
|
@ -362,7 +426,7 @@ h2 {
|
||||||
<div>- a: "oldValue" => <nil> </div>
|
<div>- a: "oldValue" => <nil> </div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<span class="resource-item-type text--bold">aws_diff_resource</span>
|
<span class="resource-item-type">aws_diff_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
<div class="resource-item resource-item-changed d-flex justify-space-between">
|
||||||
|
@ -372,42 +436,46 @@ h2 {
|
||||||
<div>- path.to.field: <nil> => ["value"] </div>
|
<div>- path.to.field: <nil> => ["value"] </div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<span class="resource-item-type text--bold">aws_diff_resource</span>
|
<span class="resource-item-type">aws_diff_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="panel" id="three-panel">
|
<div class="panel" id="three-panel">
|
||||||
|
<div class="d-flex justify-space-between text--grey pa-1">
|
||||||
|
<span>Resource id</span>
|
||||||
|
<span>Resource type</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-1</span>
|
<span class="resource-item-id">deleted-id-1</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-2</span>
|
<span class="resource-item-id">deleted-id-2</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-3</span>
|
<span class="resource-item-id">deleted-id-3</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-4</span>
|
<span class="resource-item-id">deleted-id-4</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-5</span>
|
<span class="resource-item-id">deleted-id-5</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
<div class="resource-item resource-item-deleted d-flex justify-space-between">
|
||||||
<span class="resource-item-id">deleted-id-6</span>
|
<span class="resource-item-id">deleted-id-6</span>
|
||||||
<span class="resource-item-type text--bold">aws_deleted_resource</span>
|
<span class="resource-item-type">aws_deleted_resource</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -417,18 +485,18 @@ h2 {
|
||||||
|
|
||||||
|
|
||||||
<div class="resource-item resource-item-alerts">
|
<div class="resource-item resource-item-alerts">
|
||||||
<span class="resource-item-type text--bold"></span>
|
<span class="resource-item-type"></span>
|
||||||
<span>- Ignoring aws_vpc from drift calculation: Listing aws_vpc is forbidden.</span>
|
<span>Ignoring aws_vpc from drift calculation: Listing aws_vpc is forbidden.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-alerts">
|
<div class="resource-item resource-item-alerts">
|
||||||
<span class="resource-item-type text--bold"></span>
|
<span class="resource-item-type"></span>
|
||||||
<span>- Ignoring aws_sqs from drift calculation: Listing aws_sqs is forbidden.</span>
|
<span>Ignoring aws_sqs from drift calculation: Listing aws_sqs is forbidden.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="resource-item resource-item-alerts">
|
<div class="resource-item resource-item-alerts">
|
||||||
<span class="resource-item-type text--bold"></span>
|
<span class="resource-item-type"></span>
|
||||||
<span>- Ignoring aws_sns from drift calculation: Listing aws_sns is forbidden.</span>
|
<span>Ignoring aws_sns from drift calculation: Listing aws_sns is forbidden.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,458 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Driftctl scan report</title>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<link rel="shortcut icon"
|
||||||
|
href="https://raw.githubusercontent.com/cloudskiff/driftctl-docs/main/static/img/favicon.ico"/>
|
||||||
|
<style>/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom style
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--transitionDuration: 400ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Helvetica", sans-serif;
|
||||||
|
color: #1C1E21;
|
||||||
|
background-color: #F7F7F9;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.container {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 1280px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
height: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-space-around {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-5 {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-5 {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-2 {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-1 {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-1 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pa-1 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-1 {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-1 {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-1 {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-1 {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
select {
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
outline: none;
|
||||||
|
transition: var(--transitionDuration);
|
||||||
|
color: #6e7071;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
select:focus {
|
||||||
|
border: 1px solid #71b2c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
||||||
|
width: 300px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-content {
|
||||||
|
padding: 25px;
|
||||||
|
border-top: 3px solid #71B2C3;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item {
|
||||||
|
border-top: 1px solid #ececec;
|
||||||
|
border-left: 1px solid #ececec;
|
||||||
|
border-right: 1px solid #ececec;
|
||||||
|
padding: 15px;
|
||||||
|
color: #6e7071;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:last-child {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:hover {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--grey {
|
||||||
|
color: #747578;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset-filter-btn {
|
||||||
|
border: none;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #5faabd;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tabs style */
|
||||||
|
.tabs-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 2px;
|
||||||
|
background: transparent;
|
||||||
|
display: inline-block;
|
||||||
|
color: #747578;
|
||||||
|
transition: background-color 200ms;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab:hover {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panels {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
display: none;
|
||||||
|
animation: fadein .8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadein {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#one:checked ~ .panels #one-panel,
|
||||||
|
#two:checked ~ .panels #two-panel,
|
||||||
|
#three:checked ~ .panels #three-panel,
|
||||||
|
#four:checked ~ .panels #four-panel {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
#one:checked ~ .tabs #one-tab,
|
||||||
|
#two:checked ~ .tabs #two-tab,
|
||||||
|
#three:checked ~ .tabs #three-tab,
|
||||||
|
#four:checked ~ .tabs #four-tab {
|
||||||
|
background: #71b2c3;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-message-container {
|
||||||
|
color: #747578;
|
||||||
|
}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="heading d-flex justify-space-between align-center">
|
||||||
|
<div>
|
||||||
|
<h1 class="heading-title mb-1">Driftctl scan report</h1>
|
||||||
|
<span class="heading-subtitle">Coverage 0%</span>
|
||||||
|
</div>
|
||||||
|
<div class="text--right">
|
||||||
|
<h2 class="heading-date mb-1">Jun 08, 2021</h2>
|
||||||
|
<span class="heading-subtitle">Scan duration 0s</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card d-flex justify-space-around mb-2 text--grey">
|
||||||
|
<span>Total resources: 0</span>
|
||||||
|
<span>Managed: 0%</span>
|
||||||
|
<span>Changed: 0/0</span>
|
||||||
|
<span>Unmanaged: 0%</span>
|
||||||
|
<span>Missing: 0%</span>
|
||||||
|
</div>
|
||||||
|
<div class="app-content">
|
||||||
|
|
||||||
|
<div class="d-flex justify-center mb-2">
|
||||||
|
<form id="filter-form" action="#">
|
||||||
|
<input type="text" name="resource-id-filter" placeholder="Search resources..." onkeyup="refreshState()">
|
||||||
|
<select name="resource-type-filter" onchange="refreshState()">
|
||||||
|
<option value="">Resource type</option>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
<button type="button" onclick="resetFilters()" class="reset-filter-btn">Reset filters</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs-wrapper">
|
||||||
|
<input class="radio" id="one" name="group" type="radio" checked>
|
||||||
|
<input class="radio" id="two" name="group" type="radio">
|
||||||
|
<input class="radio" id="three" name="group" type="radio">
|
||||||
|
<input class="radio" id="four" name="group" type="radio">
|
||||||
|
<div class="tabs">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="panels">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="empty-message-container mt-5 d-flex justify-center hide">
|
||||||
|
<p>There's nothing to see there...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script lang="js">
|
||||||
|
const resources = document.querySelectorAll('.resource-item')
|
||||||
|
|
||||||
|
function hideResource(res) {
|
||||||
|
res.classList.add('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResource(res) {
|
||||||
|
res.classList.remove('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourceIdContains(res, query) {
|
||||||
|
const el = res.querySelector('.resource-item-id')
|
||||||
|
if (!el) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return el.innerText.toLowerCase().includes(query.toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourceTypeEqual(res, type) {
|
||||||
|
const el = res.querySelector('.resource-item-type')
|
||||||
|
if (!el) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return el.innerText === type
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCounters() {
|
||||||
|
const counterClassMapping = {
|
||||||
|
'.resource-item-unmanaged': '.resource-count-unmanaged',
|
||||||
|
'.resource-item-changed': '.resource-count-changed',
|
||||||
|
'.resource-item-deleted': '.resource-count-deleted',
|
||||||
|
'.resource-item-alerts': '.resource-count-alerts',
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const resClass in counterClassMapping) {
|
||||||
|
const countEl = document.querySelector(counterClassMapping[resClass])
|
||||||
|
if (!countEl) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
countEl.textContent = Array.from(document.querySelectorAll(resClass)).filter(el => !el.classList.contains('hide')).length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeEmptyMessage() {
|
||||||
|
const msgEl = document.querySelector('.empty-message-container')
|
||||||
|
const wrapperEl = document.querySelector('.tabs-wrapper')
|
||||||
|
const count = Array.from(resources).filter(el => !el.classList.contains('hide')).length
|
||||||
|
if (count === 0) {
|
||||||
|
msgEl.classList.remove('hide')
|
||||||
|
wrapperEl.classList.add('hide')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msgEl.classList.add('hide')
|
||||||
|
wrapperEl.classList.remove('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshState() {
|
||||||
|
const queryFilterInput = document.querySelector('input[name=resource-id-filter]').value
|
||||||
|
const typeFilterInput = document.querySelector('select[name=resource-type-filter]').value
|
||||||
|
|
||||||
|
for (const res of resources) {
|
||||||
|
const matchId = !queryFilterInput.length || resourceIdContains(res, queryFilterInput)
|
||||||
|
const matchType = !typeFilterInput.length || resourceTypeEqual(res, typeFilterInput)
|
||||||
|
|
||||||
|
if (matchId && matchType) {
|
||||||
|
displayResource(res)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hideResource(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshCounters()
|
||||||
|
computeEmptyMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFilters() {
|
||||||
|
document.querySelector('input[name=resource-id-filter]').value = ""
|
||||||
|
document.querySelector('select[name=resource-type-filter]').value = ""
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshState()
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,428 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Driftctl scan report</title>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<link rel="shortcut icon"
|
||||||
|
href="https://raw.githubusercontent.com/cloudskiff/driftctl-docs/main/static/img/favicon.ico"/>
|
||||||
|
<style>/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom style
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--transitionDuration: 400ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Helvetica", sans-serif;
|
||||||
|
color: #1C1E21;
|
||||||
|
background-color: #F7F7F9;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.container {
|
||||||
|
max-width: 100%;
|
||||||
|
width: 1280px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
height: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-space-around {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-5 {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-5 {
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-2 {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-1 {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-1 {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pa-1 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-1 {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-1 {
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt-1 {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-1 {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"],
|
||||||
|
select {
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
outline: none;
|
||||||
|
transition: var(--transitionDuration);
|
||||||
|
color: #6e7071;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
select:focus {
|
||||||
|
border: 1px solid #71b2c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[name="resource-id-filter"], select[name="resource-type-filter"] {
|
||||||
|
width: 300px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-title {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-content {
|
||||||
|
padding: 25px;
|
||||||
|
border-top: 3px solid #71B2C3;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item {
|
||||||
|
border-top: 1px solid #ececec;
|
||||||
|
border-left: 1px solid #ececec;
|
||||||
|
border-right: 1px solid #ececec;
|
||||||
|
padding: 15px;
|
||||||
|
color: #6e7071;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:last-child {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-item:hover {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--grey {
|
||||||
|
color: #747578;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text--right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 5px #0000000a;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reset-filter-btn {
|
||||||
|
border: none;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #5faabd;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tabs style */
|
||||||
|
.tabs-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 2px;
|
||||||
|
background: transparent;
|
||||||
|
display: inline-block;
|
||||||
|
color: #747578;
|
||||||
|
transition: background-color 200ms;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab:hover {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panels {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
display: none;
|
||||||
|
animation: fadein .8s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadein {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#one:checked ~ .panels #one-panel,
|
||||||
|
#two:checked ~ .panels #two-panel,
|
||||||
|
#three:checked ~ .panels #three-panel,
|
||||||
|
#four:checked ~ .panels #four-panel {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
#one:checked ~ .tabs #one-tab,
|
||||||
|
#two:checked ~ .tabs #two-tab,
|
||||||
|
#three:checked ~ .tabs #three-tab,
|
||||||
|
#four:checked ~ .tabs #four-tab {
|
||||||
|
background: #71b2c3;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-message-container {
|
||||||
|
color: #747578;
|
||||||
|
}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="heading d-flex justify-space-between align-center">
|
||||||
|
<div>
|
||||||
|
<h1 class="heading-title mb-1">Driftctl scan report</h1>
|
||||||
|
<span class="heading-subtitle">Coverage 100%</span>
|
||||||
|
</div>
|
||||||
|
<div class="text--right">
|
||||||
|
<h2 class="heading-date mb-1">Jun 08, 2021</h2>
|
||||||
|
<span class="heading-subtitle">Scan duration 1m12s</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card d-flex justify-space-around mb-2 text--grey">
|
||||||
|
<span>Total resources: 1</span>
|
||||||
|
<span>Managed: 100%</span>
|
||||||
|
<span>Changed: 0/1</span>
|
||||||
|
<span>Unmanaged: 0%</span>
|
||||||
|
<span>Missing: 0%</span>
|
||||||
|
</div>
|
||||||
|
<div class="app-content">
|
||||||
|
|
||||||
|
<div class="d-flex justify-center mt-5 mb-5">
|
||||||
|
<h1>Congrats! Your infrastructure is in sync</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script lang="js">
|
||||||
|
const resources = document.querySelectorAll('.resource-item')
|
||||||
|
|
||||||
|
function hideResource(res) {
|
||||||
|
res.classList.add('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResource(res) {
|
||||||
|
res.classList.remove('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourceIdContains(res, query) {
|
||||||
|
const el = res.querySelector('.resource-item-id')
|
||||||
|
if (!el) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return el.innerText.toLowerCase().includes(query.toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourceTypeEqual(res, type) {
|
||||||
|
const el = res.querySelector('.resource-item-type')
|
||||||
|
if (!el) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return el.innerText === type
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshCounters() {
|
||||||
|
const counterClassMapping = {
|
||||||
|
'.resource-item-unmanaged': '.resource-count-unmanaged',
|
||||||
|
'.resource-item-changed': '.resource-count-changed',
|
||||||
|
'.resource-item-deleted': '.resource-count-deleted',
|
||||||
|
'.resource-item-alerts': '.resource-count-alerts',
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const resClass in counterClassMapping) {
|
||||||
|
const countEl = document.querySelector(counterClassMapping[resClass])
|
||||||
|
if (!countEl) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
countEl.textContent = Array.from(document.querySelectorAll(resClass)).filter(el => !el.classList.contains('hide')).length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeEmptyMessage() {
|
||||||
|
const msgEl = document.querySelector('.empty-message-container')
|
||||||
|
const wrapperEl = document.querySelector('.tabs-wrapper')
|
||||||
|
const count = Array.from(resources).filter(el => !el.classList.contains('hide')).length
|
||||||
|
if (count === 0) {
|
||||||
|
msgEl.classList.remove('hide')
|
||||||
|
wrapperEl.classList.add('hide')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msgEl.classList.add('hide')
|
||||||
|
wrapperEl.classList.remove('hide')
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshState() {
|
||||||
|
const queryFilterInput = document.querySelector('input[name=resource-id-filter]').value
|
||||||
|
const typeFilterInput = document.querySelector('select[name=resource-type-filter]').value
|
||||||
|
|
||||||
|
for (const res of resources) {
|
||||||
|
const matchId = !queryFilterInput.length || resourceIdContains(res, queryFilterInput)
|
||||||
|
const matchType = !typeFilterInput.length || resourceTypeEqual(res, typeFilterInput)
|
||||||
|
|
||||||
|
if (matchId && matchType) {
|
||||||
|
displayResource(res)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hideResource(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshCounters()
|
||||||
|
computeEmptyMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFilters() {
|
||||||
|
document.querySelector('input[name=resource-id-filter]').value = ""
|
||||||
|
document.querySelector('select[name=resource-type-filter]').value = ""
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshState()
|
||||||
|
</script>
|
||||||
|
</html>
|
Loading…
Reference in New Issue