18 Commits

Author SHA1 Message Date
Andrei Pohilko
3c4d73665e Release 0.1.0 2022-10-04 09:12:14 +01:00
Andrei Pohilko
8b5f8e1031 Another test 2022-10-04 08:52:59 +01:00
Andrei Pohilko
44461bf5ab Test the workaround 2022-10-04 08:50:20 +01:00
Andrei Pohilko
061bd12f2f Fix release process 2022-10-04 08:45:13 +01:00
Andrei Pohilko
86c9f89acc Release 0.0.8 2022-10-04 08:40:48 +01:00
Itiel shwartz
890994d70d add datadog and heap (#16)
* add datadog

* also added heap
2022-10-04 08:32:41 +01:00
Itiel shwartz
35097fed45 Clean cluster name (#15)
* support GKE and AWS cluster name

* remove unused logs

Co-authored-by: Itiel Shwartz <itielshwartz@Itiels-MacBook-Pro.local>
2022-10-03 21:34:28 +01:00
Andrei Pohilko
11912e7b51 Use dry run instead of template 2022-10-02 16:06:31 +01:00
Andrei Pohilko
8e90c9f8d0 Update screenshot 2022-10-02 15:05:10 +01:00
Andrey Pokhilko
1e3a706698 Restyle fixes (#14)
* Applying style fixes

* Implement more notes

* Improvements

* Applying v2 design

* flyout restyle

* fix spec rev

* Status icons

* Restyle top line and footer

* Shorter err msg
2022-10-02 11:50:28 +01:00
Andrei Pohilko
1b6dc4159a Release 0.0.6 2022-09-29 09:01:05 +01:00
Andrei Pohilko
69609b1ee2 Fix wrapping and scrolls 2022-09-28 22:29:42 +01:00
Andrei Pohilko
bdd5b9b32e Workaround the wrap 2022-09-28 20:52:37 +01:00
Andrei Pohilko
870a1196f0 Make k8s context a URL param 2022-09-28 15:00:10 +01:00
Andrei Pohilko
c1732c86a5 Fix the binary path 2022-09-26 14:40:14 +01:00
Andrei Pohilko
388c330390 Fix unpacking 2022-09-26 14:37:53 +01:00
Andrei Pohilko
cb7c29de90 fix the name 2022-09-26 14:35:13 +01:00
Andrei Pohilko
fa6a38c50f Update install script 2022-09-26 14:33:10 +01:00
15 changed files with 342 additions and 193 deletions

View File

@@ -8,7 +8,7 @@ A simplified way of working with Helm.
The _Helm Dashboard_ plugin offers a UI-driven way to view the installed Helm charts, see their revision history and corresponding k8s resources. Also, you can perform simple actions like roll back to a revision or upgrade to newer version. The _Helm Dashboard_ plugin offers a UI-driven way to view the installed Helm charts, see their revision history and corresponding k8s resources. Also, you can perform simple actions like roll back to a revision or upgrade to newer version.
This project is part of [Komodor's](https://komodor.io) vision of helping Kubernetes users to navigate and troubleshoot their clusters. This project is part of [Komodor's](https://komodor.com/?utm_campaign=Helm-Dash&utm_source=helm-dash-gh) vision of helping Kubernetes users to navigate and troubleshoot their clusters.
## Installing ## Installing
@@ -18,6 +18,11 @@ To install it, simply run Helm command:
helm plugin install https://github.com/komodorio/helm-dashboard.git helm plugin install https://github.com/komodorio/helm-dashboard.git
``` ```
To update the plugin to the latest version, run:
```shell
helm plugin update dashboard
```
To uninstall, run: To uninstall, run:
```shell ```shell
@@ -45,7 +50,7 @@ If you want to increase the logging verbosity and see all the debug info, set `D
## Support Channels ## Support Channels
We have two main channels for supporting the Helm Dashboard users: [Slack community](https://komodorkommunity.slack.com/x-p3820586794880-3937175868755-4092688791734/archives/C042U85BD45/p1663573506220839) for general conversations We have two main channels for supporting the Helm Dashboard users: [Slack community](https://komodorkommunity.slack.com/archives/C044U1B0265) for general conversations
and [GitHub issues](https://github.com/komodorio/helm-dashboard/issues) for real bugs. and [GitHub issues](https://github.com/komodorio/helm-dashboard/issues) for real bugs.
@@ -108,7 +113,7 @@ To install, checkout the source code and run from source dir:
helm plugin install . helm plugin install .
``` ```
Local install of plugin just creates a symlink, so making the changes and rebuilding the binary would not require to Local installation of plugin just creates a symlink, so making the changes and rebuilding the binary would not require to
reinstall a plugin. reinstall a plugin.
To use the plugin, run in your terminal: To use the plugin, run in your terminal:

View File

@@ -10,6 +10,7 @@ import (
"github.com/hexops/gotextdiff/span" "github.com/hexops/gotextdiff/span"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"helm.sh/helm/v3/pkg/release"
"io/ioutil" "io/ioutil"
v1 "k8s.io/apimachinery/pkg/apis/testapigroup/v1" v1 "k8s.io/apimachinery/pkg/apis/testapigroup/v1"
"os" "os"
@@ -21,6 +22,17 @@ import (
"time" "time"
) )
type CmdError struct {
Command []string
OrigError error
StdErr []byte
}
func (e CmdError) Error() string {
//return fmt.Sprintf("failed to run command %s:\nError: %s\nSTDERR:%s", e.Command, e.OrigError, e.StdErr)
return string(e.StdErr)
}
type DataLayer struct { type DataLayer struct {
KubeContext string KubeContext string
Helm string Helm string
@@ -46,9 +58,18 @@ func (d *DataLayer) runCommand(cmd ...string) (string, error) {
log.Warnf("STDERR:\n%s", serr) log.Warnf("STDERR:\n%s", serr)
} }
if eerr, ok := err.(*exec.ExitError); ok { if eerr, ok := err.(*exec.ExitError); ok {
return "", fmt.Errorf("failed to run command %s:\nError: %s\nSTDERR:%s", cmd, eerr, serr) return "", CmdError{
Command: cmd,
StdErr: serr,
OrigError: eerr,
}
}
return "", CmdError{
Command: cmd,
StdErr: serr,
OrigError: err,
} }
return "", err
} }
sout := stdout.Bytes() sout := stdout.Bytes()
@@ -96,12 +117,10 @@ func (d *DataLayer) CheckConnectivity() error {
return errors.New("did not find any kubectl contexts configured") return errors.New("did not find any kubectl contexts configured")
} }
/* _, err = d.runCommandHelm("--help") // no point in doing is, since the default context may be invalid
_, err = d.runCommandHelm("env") // no point in doing is, since the default context may be invalid
if err != nil { if err != nil {
return err return err
} }
*/
return nil return nil
} }
@@ -365,12 +384,9 @@ func (d *DataLayer) ChartUpgrade(namespace string, name string, repoChart string
return "", err return "", err
} }
cmd := []string{name, repoChart, "--version", version, "--namespace", namespace, "--values", file.Name()} cmd := []string{"upgrade", name, repoChart, "--version", version, "--namespace", namespace, "--values", file.Name(), "--output", "json"}
if justTemplate { if justTemplate {
cmd = append([]string{"template", "--skip-tests"}, cmd...) cmd = append(cmd, "--dry-run")
} else {
cmd = append([]string{"upgrade"}, cmd...)
cmd = append(cmd, "--output", "json")
} }
out, err := d.runCommandHelm(cmd...) out, err := d.runCommandHelm(cmd...)
@@ -379,11 +395,17 @@ func (d *DataLayer) ChartUpgrade(namespace string, name string, repoChart string
} }
if justTemplate { if justTemplate {
res := release.Release{}
err = json.Unmarshal([]byte(out), &res)
if err != nil {
return "", err
}
manifests, err := d.RevisionManifests(namespace, name, 0, false) manifests, err := d.RevisionManifests(namespace, name, 0, false)
if err != nil { if err != nil {
return "", err return "", err
} }
out = getDiff(strings.TrimSpace(manifests), strings.TrimSpace(out), "current.yaml", "upgraded.yaml") out = getDiff(strings.TrimSpace(manifests), strings.TrimSpace(res.Manifest), "current.yaml", "upgraded.yaml")
} }
return out, nil return out, nil

View File

@@ -1,4 +0,0 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 20.5C16.2467 20.5 20.5 16.2467 20.5 11C20.5 5.75329 16.2467 1.5 11 1.5C5.75329 1.5 1.5 5.75329 1.5 11C1.5 16.2467 5.75329 20.5 11 20.5ZM11 22C17.0751 22 22 17.0751 22 11C22 4.92487 17.0751 0 11 0C4.92487 0 0 4.92487 0 11C0 17.0751 4.92487 22 11 22Z" fill="#3B3D45"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.4718 16.3004C10.6247 16.8115 8.56283 16.3411 7.11084 14.8891C5.65885 13.4371 5.18842 11.3753 5.69955 9.52809L4.51969 8.34823C3.48499 10.8798 3.99515 13.8947 6.05018 15.9498C8.10522 18.0048 11.1201 18.515 13.6517 17.4803L12.4718 16.3004ZM10.213 5.55627C11.8698 5.31807 13.6144 5.83629 14.889 7.11092C16.1636 8.38555 16.6819 10.1302 16.4437 11.7869L17.6973 13.0406C18.4242 10.6477 17.8416 7.94219 15.9497 6.05026C14.0577 4.15833 11.3523 3.57578 8.95934 4.3026L10.213 5.55627Z" fill="#3B3D45"/>
</svg>

Before

Width:  |  Height:  |  Size: 968 B

View File

@@ -4,6 +4,7 @@ $("#btnUpgradeCheck").click(function () {
self.find(".spinner-border").show() self.find(".spinner-border").show()
const repoName = self.data("repo") const repoName = self.data("repo")
$("#btnUpgrade span").text("Checking...") $("#btnUpgrade span").text("Checking...")
$("#btnUpgrade .icon").removeClass("bi-arrow-up bi-check-circle").addClass("bi-hourglass-split")
$.post("/api/helm/repo/update?name=" + repoName).fail(function (xhr) { $.post("/api/helm/repo/update?name=" + repoName).fail(function (xhr) {
reportError("Failed to update chart repo", xhr) reportError("Failed to update chart repo", xhr)
}).done(function () { }).done(function () {
@@ -20,7 +21,11 @@ function checkUpgradeable(name) {
$.getJSON("/api/helm/repo/search?name=" + name).fail(function (xhr) { $.getJSON("/api/helm/repo/search?name=" + name).fail(function (xhr) {
reportError("Failed to find chart in repo", xhr) reportError("Failed to find chart in repo", xhr)
}).done(function (data) { }).done(function (data) {
if (!data) { if (!data || !data.length) {
$("#btnUpgrade span").text("No upgrades")
$("#btnUpgrade .icon").removeClass("bi-hourglass-split").addClass("bi-x-octagon")
$("#btnUpgrade").prop("disabled", true)
$("#btnUpgradeCheck").prop("disabled", true)
return return
} }
@@ -38,8 +43,10 @@ function checkUpgradeable(name) {
$("#btnUpgradeCheck").prop("disabled", false) $("#btnUpgradeCheck").prop("disabled", false)
if (canUpgrade) { if (canUpgrade) {
$("#btnUpgrade span").text("Upgrade to " + elm.version) $("#btnUpgrade span").text("Upgrade to " + elm.version)
$("#btnUpgrade .icon").removeClass("bi-hourglass-split").addClass("bi-arrow-up")
} else { } else {
$("#btnUpgrade span").text("No upgrades") $("#btnUpgrade span").text("Up-to-date")
$("#btnUpgrade .icon").removeClass("bi-hourglass-split").addClass("bi-check-circle")
} }
$("#btnUpgrade").off("click").click(function () { $("#btnUpgrade").off("click").click(function () {
@@ -58,12 +65,11 @@ function popUpUpgrade(self, verCur, elm) {
$('#upgradeModalLabel select').val(elm.version).trigger("change") $('#upgradeModalLabel select').val(elm.version).trigger("change")
const myModal = new bootstrap.Offcanvas(document.getElementById('upgradeModal'), {}); const myModal = new bootstrap.Modal(document.getElementById('upgradeModal'), {});
myModal.show() myModal.show()
const btnConfirm = $("#upgradeModal .btn-confirm"); const btnConfirm = $("#upgradeModal .btn-confirm");
btnConfirm.prop("disabled", true).off('click').click(function () { btnConfirm.prop("disabled", true).off('click').click(function () {
console.log("working")
btnConfirm.prop("disabled", true).prepend('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>') btnConfirm.prop("disabled", true).prepend('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>')
$.ajax({ $.ajax({
url: url + "&version=" + $('#upgradeModalLabel select').val(), url: url + "&version=" + $('#upgradeModalLabel select').val(),
@@ -122,7 +128,7 @@ $("#btnUninstall").click(function () {
}) })
}) })
const myModal = new bootstrap.Offcanvas(document.getElementById('confirmModal')); const myModal = new bootstrap.Modal(document.getElementById('confirmModal'));
myModal.show() myModal.show()
let qstr = "name=" + chart + "&namespace=" + namespace + "&revision=" + revision let qstr = "name=" + chart + "&namespace=" + namespace + "&revision=" + revision
@@ -160,7 +166,7 @@ $("#btnRollback").click(function () {
}) })
}) })
const myModal = new bootstrap.Offcanvas(document.getElementById('confirmModal'), {}); const myModal = new bootstrap.Modal(document.getElementById('confirmModal'), {});
myModal.show() myModal.show()
let qstr = "name=" + chart + "&namespace=" + namespace + "&revision=" + revisionNew + "&revisionDiff=" + revisionCur let qstr = "name=" + chart + "&namespace=" + namespace + "&revision=" + revisionNew + "&revisionDiff=" + revisionCur

View File

@@ -0,0 +1,18 @@
(function(h,o,u,n,d) {
h=h[d]=h[d]||{q:[],onReady:function(c){h.q.push(c)}}
d=o.createElement(u);d.async=1;d.src=n
n=o.getElementsByTagName(u)[0];n.parentNode.insertBefore(d,n)
})(window,document,'script','https://www.datadoghq-browser-agent.com/datadog-rum-v4.js','DD_RUM')
DD_RUM.onReady(function() {
DD_RUM.init({
clientToken: 'pub16d64cd1c00cf073ce85af914333bf72',
applicationId: 'e75439e5-e1b3-46ba-a9e9-a2e58579a2e2',
site: 'datadoghq.com',
service: 'helm-dashboard',
version: 'v0.0.0',
trackInteractions: true,
trackResources: true,
trackLongTasks: true,
defaultPrivacyLevel: 'mask'
})
})

View File

@@ -4,15 +4,16 @@ function revisionClicked(namespace, name, self) {
revRow.find(".active").removeClass(active).addClass(inactive) revRow.find(".active").removeClass(active).addClass(inactive)
self.removeClass(inactive).addClass(active) self.removeClass(inactive).addClass(active)
const elm = self.data("elm") const elm = self.data("elm")
console.log(elm)
setHashParam("revision", elm.revision) setHashParam("revision", elm.revision)
$("#sectionDetails span.rev").text("#" + elm.revision) $("#sectionDetails span.rev").text("#" + elm.revision)
statusStyle(elm.status, $("#none"), $("#sectionDetails .rev-details .rev-status")) statusStyle(elm.status, $("#none"), $("#sectionDetails .rev-details .rev-status"))
$("#sectionDetails .rev-date").text(elm.updated.replace("T", " ").replace("+", " +")) const rdate = luxon.DateTime.fromISO(elm.updated);
$("#sectionDetails .rev-date").text(rdate.toJSDate().toLocaleString())
$("#sectionDetails .rev-tags .rev-chart").text(elm.chart) $("#sectionDetails .rev-tags .rev-chart").text(elm.chart)
$("#sectionDetails .rev-tags .rev-app").text(elm.app_version) $("#sectionDetails .rev-tags .rev-app").text(elm.app_version)
$("#sectionDetails .rev-tags .rev-ns").text(getHashParam("namespace")) $("#sectionDetails .rev-tags .rev-ns").text(getHashParam("namespace"))
$("#sectionDetails .rev-tags .rev-cluster").text(getHashParam("context"))
$("#revDescr").text(elm.description).removeClass("text-danger") $("#revDescr").text(elm.description).removeClass("text-danger")
if (elm.status === "failed") { if (elm.status === "failed") {
@@ -94,9 +95,11 @@ $('#specRev').keyup(function (event) {
if (keycode == '13') { if (keycode == '13') {
$("#diffModeRev").click() $("#diffModeRev").click()
} }
event.preventDefault()
}); });
$("form").submit(function(e){
e.preventDefault();
});
$("#userDefinedVals").change(function () { $("#userDefinedVals").change(function () {
const self = $(this) const self = $(this)
@@ -150,10 +153,11 @@ function showResources(namespace, chart, revision) {
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const res = data[i] const res = data[i]
const resBlock = $(` const resBlock = $(`
<div class="row px-3 py-2 mb-2"> <div class="row px-3 py-2 mb-3 bg-white rounded">
<div class="col-2 res-kind"></div> <div class="col-2 res-kind text-break"></div>
<div class="col-4 res-name"></div> <div class="col-3 res-name text-break fw-bold"></div>
<div class="col-5 res-status"><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> <span class="text-muted small">Getting status...</span></div> <div class="col-1 res-status"><span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span></div>
<div class="col-5 res-statusmsg"><span class="text-muted small">Getting status...</span></div>
<div class="col-1 res-actions"></div> <div class="col-1 res-actions"></div>
</div> </div>
`) `)
@@ -166,11 +170,11 @@ function showResources(namespace, chart, revision) {
$.getJSON("/api/kube/resources/" + res.kind.toLowerCase() + "?name=" + res.metadata.name + "&namespace=" + ns).fail(function () { $.getJSON("/api/kube/resources/" + res.kind.toLowerCase() + "?name=" + res.metadata.name + "&namespace=" + ns).fail(function () {
//reportError("Failed to get list of resources") //reportError("Failed to get list of resources")
}).done(function (data) { }).done(function (data) {
const badge = $("<span class='badge me-2'></span>").text(data.status.phase); const badge = $("<span class='badge me-2 fw-normal'></span>").text(data.status.phase);
if (["Available", "Active", "Established"].includes(data.status.phase)) { if (["Available", "Active", "Established"].includes(data.status.phase)) {
badge.addClass("bg-success") badge.addClass("bg-success text-dark")
} else if (["Exists"].includes(data.status.phase)) { } else if (["Exists"].includes(data.status.phase)) {
badge.addClass("bg-success bg-opacity-50") badge.addClass("bg-success text-dark bg-opacity-50")
} else if (["Progressing"].includes(data.status.phase)) { } else if (["Progressing"].includes(data.status.phase)) {
badge.addClass("bg-warning") badge.addClass("bg-warning")
} else { } else {
@@ -178,13 +182,15 @@ function showResources(namespace, chart, revision) {
} }
const statusBlock = resBlock.find(".res-status"); const statusBlock = resBlock.find(".res-status");
statusBlock.empty().append(badge).append("<span class='text-muted small'>" + (data.status.message ? data.status.message : '') + "</span>") statusBlock.empty().append(badge)
resBlock.find(".res-statusmsg").html("<span class='text-muted small'>" + (data.status.message ? data.status.message : '') + "</span>")
if (badge.text() !== "NotFound") { if (badge.text() !== "NotFound") {
resBlock.find(".res-actions") resBlock.find(".res-actions")
resBlock.find(".res-actions").append("<i class=\"btn bi-zoom-in float-end text-muted\"></i>") const btn = $("<button class=\"btn btn-sm btn-white border-secondary\">Describe</button>");
statusBlock.find(".bi-zoom-in").click(function () { resBlock.find(".res-actions").append(btn)
showDescribe(ns, res.kind, res.metadata.name) btn.click(function () {
showDescribe(ns, res.kind, res.metadata.name, badge.clone())
}) })
} }
}) })
@@ -192,8 +198,9 @@ function showResources(namespace, chart, revision) {
}) })
} }
function showDescribe(ns, kind, name) { function showDescribe(ns, kind, name, badge) {
$("#describeModalLabel").text("Describe " + kind + ": " + ns + " / " + name) $("#describeModal .offcanvas-header p").text(kind)
$("#describeModalLabel").text(name).append(badge.addClass("ms-3 small fw-normal"))
$("#describeModalBody").empty().append('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>') $("#describeModalBody").empty().append('<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>')
const myModal = new bootstrap.Offcanvas(document.getElementById('describeModal')); const myModal = new bootstrap.Offcanvas(document.getElementById('describeModal'));

View File

@@ -5,8 +5,9 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Helm Dashboard</title> <title>Helm Dashboard</title>
<script src="static/datadog.js"></script>
<link rel="stylesheet" <link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto&family=Inter&family=Poppins:wght@600&family=Inter:wght@500&family=Roboto+Slab:wght@400&family=Roboto+Slab:wght@700&family=Roboto:wght@700"/> href="https://fonts.googleapis.com/css2?family=Roboto&family=Inter&family=Poppins:wght@600&family=Poppins:wght@500&family=Inter:wght@500&family=Roboto+Slab:wght@400&family=Roboto+Slab:wght@700&family=Roboto:wght@700&family=Roboto:wght@500"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous"> integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
@@ -14,19 +15,21 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/lightfair.min.css"/> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/lightfair.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"/> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"/>
<link href="static/styles.css" rel="stylesheet"> <link href="static/styles.css" rel="stylesheet">
<script type="text/javascript">
window.heap=window.heap||[],heap.load=function(e,t){window.heap.appid=e,window.heap.config=t=t||{};var r=document.createElement("script");r.type="text/javascript",r.async=!0,r.src="https://cdn.heapanalytics.com/js/heap-"+e+".js";var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(r,a);for(var n=function(e){return function(){heap.push([e].concat(Array.prototype.slice.call(arguments,0)))}},p=["addEventProperties","addUserProperties","clearEventProperties","identify","resetIdentity","removeEventProperty","setEventProperties","track","unsetEventProperty"],o=0;o<p.length;o++)heap[p[o]]=n(p[o])};
heap.load("3615793373");
</script>
</head> </head>
<body> <body>
<div class="container-fluid gx-0"> <div class="container-fluid px-0">
<!-- TOP BAR --> <!-- TOP BAR -->
<nav class="navbar navbar-expand bg-white mb-0 p-0" id="topNav"> <nav class="navbar navbar-expand bg-white mb-0 p-0 b-shadow" id="topNav">
<div class="container-fluid m-0 p-0"> <div class="container-fluid m-0 p-0">
<div class="navbar-brand"> <div class="navbar-brand">
<a href="/"><img src="static/logo.png" alt="Logo"></a> <a href="/"><img src="static/logo.png" alt="Logo"></a>
<div> <div>
<h1><a href="/">Helm Dashboard</a></h1> <h1><a href="/">Helm Dashboard</a></h1>
<p><span class="mr-1">by</span><a href="https://komodor.io"><img src="static/komodor-logo.svg"
alt="komodor.io"></a></p>
</div> </div>
</div> </div>
@@ -47,13 +50,19 @@
</li> </li>
--> -->
</ul> </ul>
<div>
<a class="btn" href="https://komodor.com/?utm_campaign=Helm-Dash&utm_source=helm-dash"><img
src="https://komodor.com/wp-content/uploads/2021/05/favicon.png" alt="komodor.io" style="height: 1.2rem; vertical-align: text-bottom; filter: grayscale(00%);"></a>
<a class="btn me-2 text-muted" href="https://github.com/komodorio/helm-dashboard" title="Project page on GitHub"><i class="bi-github"></i></a>
</div>
<div class="separator-vertical"><span></span></div> <div class="separator-vertical"><span></span></div>
<i class="btn bi-power text-muted p-2 m-1 mx-2" title="Shut down the Helm Dashboard application"></i> <i class="btn bi-power text-muted p-2 m-1 mx-2" title="Shut down the Helm Dashboard application"></i>
</div> </div>
</nav> </nav>
<!-- /TOP BAR --> <!-- /TOP BAR -->
<div class="row mt-3 pt-3 mx-0 me-5" id="sectionList" style="display: none"> <div class="row mt-3 pt-3 me-5" id="sectionList" style="display: none">
<div class="col-2 ms-3"> <div class="col-2 ms-3">
<!-- FILTER BLOCK --> <!-- FILTER BLOCK -->
<div class="p-2 ps-2 bg-white rounded-1 b-shadow" id="filters"> <div class="p-2 ps-2 bg-white rounded-1 b-shadow" id="filters">
@@ -95,50 +104,52 @@
<!-- /INSTALLED LIST --> <!-- /INSTALLED LIST -->
</div> </div>
<div class="row flex-nowrap pt-0 mx-0" id="sectionDetails" style="display: none">
<div class="row pt-0 mx-0 me-0" id="sectionDetails" style="display: none"> <div class="col-2 px-4 py-4 pe-3 rev-list">
<div class="col-2 ms-3 ps-1 pt-4 rev-list">
<h3 class="fw-bold small">Revisions</h3> <h3 class="fw-bold small">Revisions</h3>
<ul class="list-unstyled"> <ul class="list-unstyled">
</ul> </ul>
</div> </div>
<div class="col ms-2 rev-details bg-white b-shadow pt-4 px-5">
<div class="col-10 rev-details bg-white b-shadow pt-4 px-5 overflow-auto">
<div><span class="rev-status fw-bold me-3"></span></div> <div><span class="rev-status fw-bold me-3"></span></div>
<div> <div>
<h1 class="name float-start">Name</h1> <h1 class="name float-start">Name</h1>
<div id="actionButtons" class="float-end"> <div id="actionButtons" class="float-end">
<span><button id="btnUpgrade" <span><button id="btnUpgrade"
class="opacity-10 btn btn-sm btn-light bg-white rounded-0 me-0 rounded-start border-secondary"> class="opacity-10 btn btn-sm btn-light bg-white me-2 border-secondary">
<img src="static/action.svg"> <span>Checking...</span> <i class="icon bi-hourglass-split"></i> <span></span>
</button></span><span><button </button></span>
id="btnUpgradeCheck"
class="btn btn-sm text-muted btn-light bg-white border-secondary rounded-0 rounded-end ms-0 me-2"
title="Check for newer chart version from repo"><i class="bi-repeat"></i><span
class="spinner-border spinner-border-sm" style="display: none" role="status"
aria-hidden="true"></span></button></span>
<button id="btnRollback" class="btn btn-sm btn-light bg-white border border-secondary me-2" <button id="btnRollback" class="btn btn-sm btn-light bg-white border border-secondary me-2"
title="Rollback to this revision"><img src="static/action.svg"> <span>Rollback</span> title="Rollback to this revision"><i class="bi-arrow-repeat"></i> <span>Rollback</span>
</button> </button>
<button id="btnUninstall" class="btn btn-sm btn-light bg-white border border-secondary" <button id="btnUninstall" class="btn btn-sm btn-light bg-white border border-secondary"
title="Uninstall the chart"><img src="static/action.svg"> Uninstall title="Uninstall the chart"><i class="bi-trash3"></i> Uninstall
</button> </button>
<br/>
<a class="link small" id="btnUpgradeCheck">Check for new version
<span class="spinner-border spinner-border-sm" style="display: none" role="status"
aria-hidden="true"></span>
</a>
</div> </div>
<div class="fs-2">&nbsp;</div> <div class="fs-2">&nbsp;</div>
</div> </div>
<div> <div>
Revision <span class="rev fw-bold me-4"></span> Revision <span class="rev fw-bold me-4"></span>
Upgraded on <span class="rev-date"></span> <span class="rev-date"></span>
</div> </div>
<div class="rev-tags mt-3"> <div class="rev-tags mt-3">
<span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">namespace: <span
class="rev-ns fw-bold"></span></span>
<span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">chart version: <span <span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">chart version: <span
class="rev-chart fw-bold"></span></span> class="rev-chart fw-bold"></span></span>
<span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">app version: <span <span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">app version: <span
class="rev-app fw-bold"></span></span> class="rev-app fw-bold"></span></span>
<span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">namespace: <span
class="rev-ns fw-bold"></span></span>
<span class="rounded rounded-1 me-2 p-1 px-2 bg-tag text-dark">cluster: <span
class="rev-cluster fw-bold"></span></span>
</div> </div>
<div id="revDescr" class="mt-3 mb-4"></div> <div id="revDescr" class="mt-3 mb-4"></div>
@@ -155,7 +166,7 @@
</button> </button>
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#nav-manifest" data-tab="values" <button class="nav-link" data-bs-toggle="tab" data-bs-target="#nav-manifest" data-tab="values"
type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" tabindex="-1"> type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" tabindex="-1">
Parameterized Values Values
</button> </button>
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#nav-manifest" data-tab="notes" <button class="nav-link" data-bs-toggle="tab" data-bs-target="#nav-manifest" data-tab="notes"
type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" tabindex="-1"> type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" tabindex="-1">
@@ -165,12 +176,13 @@
</nav> </nav>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane p-3 container-fluid" id="nav-resources" role="tabpanel"> <div class="tab-pane p-3 container-fluid" id="nav-resources" role="tabpanel">
<div class="row bg-secondary rounded px-3 py-2 mb-2 fw-bold small" <div class="row bg-secondary rounded px-3 py-2 mb-3 fw-bold small"
style="text-transform: uppercase"> style="text-transform: uppercase">
<div class="col-2">Kind</div> <div class="col-2">Resource Type</div>
<div class="col-4">Name</div> <div class="col-3">Name</div>
<div class="col-5">Status</div> <div class="col-1">Status</div>
<div class="col-1">Describe</div> <div class="col-5">Status Message</div>
<div class="col-1"></div>
</div> </div>
<div class="body"></div> <div class="body"></div>
</div> </div>
@@ -180,7 +192,7 @@
<label class="form-check-label" for="diffModeNone"> <label class="form-check-label" for="diffModeNone">
<input class="form-check-input" type="radio" name="diffMode" id="diffModeNone" <input class="form-check-input" type="radio" name="diffMode" id="diffModeNone"
data-mode="view"> data-mode="view">
View Current View
</label> </label>
<label class="form-check-label" for="diffModePrev"> <label class="form-check-label" for="diffModePrev">
<input class="form-check-input" type="radio" name="diffMode" id="diffModePrev" <input class="form-check-input" type="radio" name="diffMode" id="diffModePrev"
@@ -221,59 +233,56 @@
<div class="offcanvas offcanvas-end rounded-start" tabindex="-1" id="describeModal" <div class="offcanvas offcanvas-end rounded-start" tabindex="-1" id="describeModal"
aria-labelledby="describeModalLabel"> aria-labelledby="describeModalLabel">
<div class="offcanvas-header"> <div class="offcanvas-header border-bottom p-4">
<div>
<h5 id="describeModalLabel"></h5> <h5 id="describeModalLabel"></h5>
<p class="m-0 mt-4">ResourceType</p>
</div>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button> <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div> </div>
<div class="offcanvas-body" id="describeModalBody"> <div class="offcanvas-body p-2 ps-4" id="describeModalBody">
</div> </div>
</div> </div>
<div class="offcanvas offcanvas-end rounded-start" tabindex="-1" id="confirmModal" aria-labelledby="confirmModalLabel"> <div class="modal" id="confirmModal" tabindex="-1" aria-labelledby="describeModalLabel" aria-hidden="true">
<div class="offcanvas-header"> <div class="modal-dialog modal-dialog modal-dialog-scrollable modal-xl">
<h5 id="confirmModalLabel"></h5> <div class="modal-content">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button> <div class="modal-header">
<h5 class="modal-title" id="confirmModalLabel"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="confirmModalBody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-confirm">Confirm</button>
</div> </div>
<div class="offcanvas-body" id="confirmModalBody">
</div> </div>
<div class="offcanvas-footer p-3">
<button type="button" class="btn btn-primary float-end btn-confirm">Confirm</button>
</div> </div>
</div> </div>
<div class="offcanvas offcanvas-end rounded-start" tabindex="-1" id="upgradeModal" aria-labelledby="upgradeModalLabel"> <div class="modal" id="upgradeModal" tabindex="-1" aria-labelledby="describeModalLabel" aria-hidden="true">
<div class="offcanvas-header"> <div class="modal-dialog modal-dialog modal-dialog-scrollable modal-xl">
<h5 id="upgradeModalLabel"> <div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="upgradeModalLabel">
Upgrade <b class='text-success name'></b> from version <b class='text-success ver-old'></b> to Upgrade <b class='text-success name'></b> from version <b class='text-success ver-old'></b> to
<select class='fw-bold text-success ver-new'></select> <select class='fw-bold text-success ver-new'></select>
</h5> </h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="offcanvas-body" id="upgradeModalBody">
</div>
<div class="offcanvas-footer p-3">
<button type="button" class="btn btn-primary float-end btn-confirm">Confirm Upgrade</button>
</div>
</div> </div>
<div class="modal-body" id="upgradeModalBody">
<footer class="container-fluid small mt-3" style="z-index: -50">
<div class="row align-items-end justify-content-end">
<div class="col-3"></div>
<div class="col-4 text-center bg-white bg-opacity-50 p-2 px-3 rounded b-shadow">
Brought to you by <img src="https://komodor.com/wp-content/uploads/2021/05/favicon.png"
style="height: 1rem"> <a class="me-4"
href="https://komodor.io">Komodor.io</a>
<i class="bi-github"></i>
<a href="https://github.com/komodorio/helm-dashboard">Project page on GitHub</a>
</div> </div>
<div class="col-3"></div> <div class="modal-footer">
<button type="button" class="btn btn-primary btn-confirm">Confirm Upgrade</button>
</div>
</div>
</div>
</div> </div>
</footer>
<img src="static/topographic.svg" class="position-absolute bottom-0 left-0" style="z-index: -100; height: 100%;"/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
@@ -282,8 +291,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"
integrity="sha512-gU7kztaQEl7SHJyraPfZLQCNnrKdaQi5ndOyt4L4UPL/FHDd/uB9Je6KDARIqwnNNE27hnqoWLBq+Kpe4iHfeQ==" integrity="sha512-gU7kztaQEl7SHJyraPfZLQCNnrKdaQi5ndOyt4L4UPL/FHDd/uB9Je6KDARIqwnNNE27hnqoWLBq+Kpe4iHfeQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script> crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3.0.1/dist/js.cookie.min.js"
integrity="sha256-0H3Nuz3aug3afVbUlsu12Puxva3CP4EhJtPExqs54Vg=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon@3.0.3/build/global/luxon.min.js" <script src="https://cdn.jsdelivr.net/npm/luxon@3.0.3/build/global/luxon.min.js"
integrity="sha256-RH4TKnKcKyde0s2jc5BW3pXZl/5annY3fcZI9VrV5WQ=" crossorigin="anonymous"></script> integrity="sha256-RH4TKnKcKyde0s2jc5BW3pXZl/5annY3fcZI9VrV5WQ=" crossorigin="anonymous"></script>
<script src="static/list-view.js"></script> <script src="static/list-view.js"></script>

View File

@@ -1,16 +1,16 @@
<svg width="53" height="13" viewBox="0 0 53 13" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="77" height="19" viewBox="0 0 77 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_36_1097)"> <g clip-path="url(#clip0_231_1524)">
<path d="M5.86295 4.90639H4.0672L1.355 7.52039V2.1665H0V11.0071H1.355V8.93513L2.42853 7.98768L4.57123 11.0071H6.23823L3.39732 7.11706L5.86295 4.90639Z" fill="#1347FF"/> <path d="M8.51786 7.17108H5.90895L1.96859 10.9915V3.16663H0V16.0875H1.96859V13.0592L3.52824 11.6745L6.64123 16.0875H9.06309L4.93573 10.4021L8.51786 7.17108Z" fill="#1347FF"/>
<path d="M19.4109 4.90652L18.7279 5.58935L18.0559 4.90652H15.6142L14.8004 5.74086V4.90652H13.5217V11.0073H14.8789V6.73737L15.6011 6.01827H17.1634L17.5387 6.38531V11.0073H18.8959V6.49839L19.3847 6.01827H21.1804L21.5557 6.38531V11.0073H22.9108V5.99267L21.8263 4.90652H19.4109Z" fill="#1347FF"/> <path d="M28.2007 7.17127L27.2085 8.16924L26.2321 7.17127H22.6848L21.5024 8.39069V7.17127H19.6448V16.0877H21.6165V9.84712L22.6658 8.79613H24.9356L25.4808 9.33257V16.0877H27.4526V9.49785L28.1627 8.79613H30.7716L31.3168 9.33257V16.0877H33.2854V8.75871L31.7099 7.17127H28.2007Z" fill="#1347FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.46283 5.99267L7.54726 4.90652H11.2544L12.3389 5.99267V9.92112L11.2544 11.0073H7.54726L6.46283 9.92112V5.99267ZM10.6086 9.89549L10.9708 9.52848H10.973V6.38531L10.6107 6.01827H8.19531L7.8331 6.38531V9.52848L8.19315 9.89549H10.6086Z" fill="#1347FF"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.38939 8.75871L10.9649 7.17127H16.3508L17.9263 8.75871V14.5003L16.3508 16.0877H10.9649L9.38939 14.5003V8.75871ZM15.4124 14.4628L15.9387 13.9264H15.9418V9.33257L15.4156 8.79613H11.9064L11.3802 9.33257V13.9264L11.9033 14.4628H15.4124Z" fill="#1347FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.2791 4.90652L42.1947 5.99267V9.92112L43.2791 11.0073H46.9863L48.0707 9.92112V5.99267L46.9863 4.90652H43.2791ZM46.7028 9.52848L46.3405 9.89549H43.9252L43.5629 9.52848V6.38531L43.9252 6.01827H46.3405L46.7028 6.38531V9.52848Z" fill="#1347FF"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M62.8772 7.17127L61.3017 8.75871V14.5003L62.8772 16.0877H68.2631L69.8385 14.5003V8.75871L68.2631 7.17127H62.8772ZM67.8513 13.9264L67.3249 14.4628H63.8158L63.2895 13.9264V9.33257L63.8158 8.79613H67.3249L67.8513 9.33257V13.9264Z" fill="#1347FF"/>
<path d="M50.5323 5.81555L51.4355 4.90652H53.0002V6.16979H51.3332L50.6108 6.8782V11.0073H49.2536V4.90652H50.5323V5.81555Z" fill="#1347FF"/> <path d="M73.4148 8.49984L74.7271 7.17127H77.0003V9.01758H74.5785L73.5289 10.053V16.0877H71.5571V7.17127H73.4148V8.49984Z" fill="#1347FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.0906 4.90652L24.0061 5.99267V9.92112L25.0906 11.0073H33.1027L34.1871 9.92112V5.99267L33.1027 4.90652H25.0906ZM32.817 9.52848L32.4547 9.89549H25.7343L25.3721 9.52848V6.38531L25.7343 6.01827H32.4547L32.817 6.38531V9.52848Z" fill="#1347FF"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M36.4523 7.17127L34.8768 8.75871V14.5003L36.4523 16.0877H48.0926L49.668 14.5003V8.75871L48.0926 7.17127H36.4523ZM47.6776 13.9264L47.1512 14.4628H37.3875L36.8613 13.9264V9.33257L37.3875 8.79613H47.1512L47.6776 9.33257V13.9264Z" fill="#1347FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.895 4.90639L39.6437 5.66392V2.1665H40.9984V11.0071H39.6437V10.2624L38.895 11.0071H36.3116L35.2272 9.92098V5.99252L36.3116 4.90639H38.895ZM38.9213 9.89538L39.6437 9.18905V6.73725L38.9213 6.01813H36.9577L36.5823 6.38516V9.52834L36.9577 9.89538H38.9213Z" fill="#1347FF"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M56.5078 7.17108L57.5955 8.27823V3.16663H59.5637V16.0875H57.5955V14.9991L56.5078 16.0875H52.7546L51.1792 14.5001V8.7585L52.7546 7.17108H56.5078ZM56.546 14.4627L57.5955 13.4303V9.84695L56.546 8.79592H53.6933L53.1478 9.33236V13.9262L53.6933 14.4627H56.546Z" fill="#1347FF"/>
</g> </g>
<defs> <defs>
<clipPath id="clip0_36_1097"> <clipPath id="clip0_231_1524">
<rect width="53" height="13" fill="white"/> <rect width="77" height="19" fill="white"/>
</clipPath> </clipPath>
</defs> </defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,4 +1,5 @@
function loadChartsList() { function loadChartsList() {
$("body").removeClass("bg-variant1 bg-variant2").addClass("bg-variant1")
$("#sectionList").show() $("#sectionList").show()
const chartsCards = $("#installedList .body") const chartsCards = $("#installedList .body")
chartsCards.empty().append("<div><span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\"></span> Loading...</div>") chartsCards.empty().append("<div><span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\"></span> Loading...</div>")
@@ -33,7 +34,7 @@ function buildChartCard(elm) {
statusStyle(elm.status, card, card.find(".rel-status span")) statusStyle(elm.status, card, card.find(".rel-status span"))
card.find("a").attr("href", '#namespace=' + elm.namespace + '&name=' + elm.name) card.find("a").attr("href", '#context=' + getHashParam('context') + '&namespace=' + elm.namespace + '&name=' + elm.name)
card.find(".rel-name span").data("chart", elm).click(function () { card.find(".rel-name span").data("chart", elm).click(function () {
const self = $(this) const self = $(this)

View File

@@ -1,6 +1,7 @@
const revRow = $("#sectionDetails .rev-list ul"); const revRow = $("#sectionDetails .rev-list ul");
function loadChartHistory(namespace, name) { function loadChartHistory(namespace, name) {
$("body").removeClass("bg-variant1 bg-variant2").addClass("bg-variant2")
$("#sectionDetails").show() $("#sectionDetails").show()
$("#sectionDetails .name").text(name) $("#sectionDetails .name").text(name)
revRow.empty().append("<li><span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\"></span></li>") revRow.empty().append("<li><span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\"></span></li>")
@@ -25,10 +26,10 @@ function fillChartHistory(data, namespace, name) {
data.reverse() data.reverse()
for (let x = 0; x < data.length; x++) { for (let x = 0; x < data.length; x++) {
const elm = data[x] const elm = data[x]
$("#specRev").val(elm.revision).data("first-rev", elm.revision) $("#specRev").data("first-rev", elm.revision)
if (!x) { if (!x) {
$("#specRev").data("last-rev", elm.revision).data("last-chart-ver", elm.chart_ver) $("#specRev").val(elm.revision).data("last-rev", elm.revision).data("last-chart-ver", elm.chart_ver)
} }
const rev = $(`<li class="px-2 pt-5 pb-4 mb-2 rounded border border-secondary bg-secondary position-relative"> const rev = $(`<li class="px-2 pt-5 pb-4 mb-2 rounded border border-secondary bg-secondary position-relative">
@@ -45,6 +46,11 @@ function fillChartHistory(data, namespace, name) {
rev.find(".rev-age").text(getAge(elm, data[x - 1])).parent().attr("title", elm.updated) rev.find(".rev-age").text(getAge(elm, data[x - 1])).parent().attr("title", elm.updated)
statusStyle(elm.status, rev.find(".rev-status"), rev.find(".rev-status")) statusStyle(elm.status, rev.find(".rev-status"), rev.find(".rev-status"))
if (elm.description.startsWith("Rollback to ")) {
//rev.find(".rev-status").append(" <span class='small fw-normal text-lowercase'>(rollback)</span>")
rev.find(".rev-status").append(" <i class='bi-arrow-counterclockwise text-muted' title='"+elm.description+"'></i>")
}
const nxt = data[x + 1]; const nxt = data[x + 1];
if (nxt && isNewerVersion(elm.chart_ver, nxt.chart_ver)) { if (nxt && isNewerVersion(elm.chart_ver, nxt.chart_ver)) {
rev.find(".rev-changes").html("<span class='strike'>" + nxt.chart_ver + "</span> <i class='text-danger bi-arrow-down-right'></i> " + elm.chart_ver) rev.find(".rev-changes").html("<span class='strike'>" + nxt.chart_ver + "</span> <i class='text-danger bi-arrow-down-right'></i> " + elm.chart_ver)

View File

@@ -1,14 +1,14 @@
$(function () { $(function () {
const clusterSelect = $("#cluster"); const clusterSelect = $("#cluster");
clusterSelect.change(function () { clusterSelect.change(function () {
Cookies.set("context", clusterSelect.find("input:radio:checked").val()) window.location.href = "/#context=" + clusterSelect.find("input:radio:checked").val()
window.location.href = "/" window.location.reload()
}) })
$.getJSON("/api/kube/contexts").fail(function (xhr) { $.getJSON("/api/kube/contexts").fail(function (xhr) {
reportError("Failed to get list of clusters", xhr) reportError("Failed to get list of clusters", xhr)
}).done(function (data) { }).done(function (data) {
const context = Cookies.get("context") const context = getHashParam("context")
fillClusterList(data, context); fillClusterList(data, context);
const namespace = getHashParam("namespace") const namespace = getHashParam("namespace")
@@ -31,7 +31,6 @@ function reportError(err, xhr) {
} }
function getHashParam(name) { function getHashParam(name) {
const params = new URLSearchParams(window.location.hash.substring(1)) const params = new URLSearchParams(window.location.hash.substring(1))
return params.get(name) return params.get(name)
@@ -63,6 +62,20 @@ function statusStyle(status, card, txt) {
} }
} }
function getCleanClusterName(rawClusterName) {
if (rawClusterName.indexOf('arn')==0) {
// AWS cluster
clusterSplit = rawClusterName.split(':')
clusterName = clusterSplit.at(-1).split("/").at(-1)
region = clusterSplit.at(-3)
return region + "/" + clusterName + ' [AWS]'
}
if (rawClusterName.indexOf('gke')==0) {
// GKE cluster
return rawClusterName.split('_').at(-2) + '/' + rawClusterName.split('_').at(-1) + ' [GKE]'
}
return rawClusterName
}
function fillClusterList(data, context) { function fillClusterList(data, context) {
data.forEach(function (elm) { data.forEach(function (elm) {
@@ -72,21 +85,27 @@ function fillClusterList(data, context) {
let opt = $('<li><label><input type="radio" name="cluster" class="me-2"/><span></span></label></li>'); let opt = $('<li><label><input type="radio" name="cluster" class="me-2"/><span></span></label></li>');
opt.attr('title', label) opt.attr('title', label)
opt.find("input").val(elm.Name).text(label) opt.find("input").val(elm.Name).text(label)
opt.find("span").text(label) opt.find("span").text(getCleanClusterName(label))
if (elm.IsCurrent && !context) { if (elm.IsCurrent && !context) {
opt.find("input").prop("checked", true) opt.find("input").prop("checked", true)
setCurrentContext(elm.Name)
} else if (context && elm.Name === context) { } else if (context && elm.Name === context) {
opt.find("input").prop("checked", true) opt.find("input").prop("checked", true)
$.ajaxSetup({ setCurrentContext(elm.Name)
headers: {
'x-kubecontext': context
}
});
} }
$("#cluster").append(opt) $("#cluster").append(opt)
}) })
} }
function setCurrentContext(ctx) {
setHashParam("context", ctx)
$.ajaxSetup({
headers: {
'x-kubecontext': ctx
}
});
}
function getAge(obj1, obj2) { function getAge(obj1, obj2) {
const date = luxon.DateTime.fromISO(obj1.updated); const date = luxon.DateTime.fromISO(obj1.updated);
let dateNext = luxon.DateTime.now() let dateNext = luxon.DateTime.now()

View File

@@ -46,6 +46,22 @@
color: #333333 !important; color: #333333 !important;
} }
.bg-danger {
background-color: #FC1683 !important;
}
.bg-success {
background-color: #A4F8D7 !important;
}
.btn {
font-weight: 500;
}
.btn-primary {
background-color: #1347FF;
}
.text-uppercase { .text-uppercase {
text-transform: uppercase; text-transform: uppercase;
} }
@@ -56,11 +72,11 @@
min-width: 60%; min-width: 60%;
} }
html {
min-height: 100%;
}
body { body {
margin: 0;
padding: 0;
height: 100%;
min-height: 50rem;
font-size: 14px; font-size: 14px;
background-color: #F4F7FA; background-color: #F4F7FA;
@@ -68,21 +84,23 @@ body {
color: #3D4048; color: #3D4048;
} }
body.bg-variant1 {
background-color: #F4F7FA;
background-image: url("topographic.svg");
background-repeat: no-repeat;
background-position: bottom left;
background-size: auto 100%;
}
body.bg-variant2 {
background-color: #E8EDF2;
}
body > .container-fluid { body > .container-fluid {
min-height: 100% !important; min-height: 100% !important;
} }
#topNav.navbar { #topNav.navbar {
box-shadow: 0 1px 4px rgba(22, 24, 31, 0.1);
}
.navbar-brand > div {
display: inline-block;
vertical-align: top;
}
.navbar-brand > div p span {
vertical-align: baseline;
} }
.navbar-brand { .navbar-brand {
@@ -90,18 +108,6 @@ body > .container-fluid {
font-size: 0.6rem !important; font-size: 0.6rem !important;
color: #707583; color: #707583;
font-weight: 500; font-weight: 500;
}
.navbar-brand h1 {
font-weight: 600;
margin: 0;
padding: 0;
line-height: 50%;
}
.navbar-brand h1 a {
font-size: 1.1rem !important;
color: #0023A3 !important;
text-decoration: none; text-decoration: none;
} }
@@ -112,17 +118,16 @@ body > .container-fluid {
margin: 0.5rem 0.8rem margin: 0.5rem 0.8rem
} }
.navbar-brand p { .navbar-brand > div {
margin-bottom: 0; display: inline-block;
vertical-align: top;
} }
.navbar-brand p a { .navbar-brand h1 a {
vertical-align: text-bottom; font-size: 1.2rem !important;
} color: #0023A3 !important;
text-decoration: none;
.navbar-brand p img { vertical-align: middle;
height: 1.25rem;
margin-left: 0.25rem;
} }
#topNav .navbar i.btn { #topNav .navbar i.btn {
@@ -267,6 +272,10 @@ span.link {
color: #707583; color: #707583;
} }
#actionButtons .link {
cursor: pointer;
}
#actionButtons button > * { #actionButtons button > * {
vertical-align: bottom; vertical-align: bottom;
} }
@@ -282,9 +291,62 @@ span.link {
.nav-tabs .nav-link { .nav-tabs .nav-link {
padding-bottom: 0.25rem; padding-bottom: 0.25rem;
color: #3B3D45;
} }
.nav-tabs .nav-link.active { .nav-tabs .nav-link.active {
border: none; border: none;
border-bottom: 3px solid #3B3D45; border-bottom: 3px solid #3B3D45;
background-color: transparent;
}
#installedList .b-shadow:hover {
box-shadow: 0 3px 15px rgba(0, 0, 0, 0.18);
}
#btnUpgradeCheck {
color: #3B3D45;
}
#btnUpgrade {
min-width: 9rem;
}
#sectionDetails > .bg-white {
background-color: #F4F7FA !important;
}
#sectionDetails .list-unstyled .bg-secondary {
background-color: #F4F7FA !important;
}
#nav-resources .badge {
font-size: inherit;
}
#nav-resources .bg-secondary {
background-color: #E6E7EB!important;
}
.res-actions .btn-sm {
font-size: 0.75rem;
}
.offcanvas-header h5 {
font-family: Poppins, serif;
font-weight: 500;
}
.offcanvas-header h5 .badge {
font-family: Roboto, serif;
font-weight: normal;
font-size: 0.8rem;
}
.offcanvas-header p {
font-family: Inter, serif;
}
#describeModalBody pre {
font-size: 1rem;
} }

View File

@@ -1,8 +1,8 @@
name: "dashboard" name: "dashboard"
version: "0.0.5" version: "0.1.0"
usage: "A simplified way of working with Helm" usage: "A simplified way of working with Helm"
description: "View HELM situation in nice web UI" description: "View HELM situation in nice web UI"
command: "$HELM_PLUGIN_DIR/bin/dashboard" command: "$HELM_PLUGIN_DIR/bin/helm-dashboard"
hooks: hooks:
install: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh" install: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh"
update: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh" update: "cd $HELM_PLUGIN_DIR; scripts/install_plugin.sh"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 270 KiB

View File

@@ -2,7 +2,7 @@
# Copied w/ love from the chartmuseum/helm-push :) # Copied w/ love from the chartmuseum/helm-push :)
name="helm-push" name="helm-dashboard"
repo="https://github.com/komodorio/${name}" repo="https://github.com/komodorio/${name}"
if [ -n "${HELM_PUSH_PLUGIN_NO_INSTALL_HOOK}" ]; then if [ -n "${HELM_PUSH_PLUGIN_NO_INSTALL_HOOK}" ]; then
@@ -41,9 +41,9 @@ esac
if [ "$(uname)" = "Darwin" ]; then if [ "$(uname)" = "Darwin" ]; then
url="${repo}/releases/download/v${version}/${name}_${version}_darwin_${arch}.tar.gz" url="${repo}/releases/download/v${version}/${name}_${version}_Darwin_${arch}.tar.gz"
elif [ "$(uname)" = "Linux" ] ; then elif [ "$(uname)" = "Linux" ] ; then
url="${repo}/releases/download/v${version}/${name}_${version}_linux_${arch}.tar.gz" url="${repo}/releases/download/v${version}/${name}_${version}_Linux_${arch}.tar.gz"
else else
url="${repo}/releases/download/v${version}/${name}_${version}_windows_${arch}.tar.gz" url="${repo}/releases/download/v${version}/${name}_${version}_windows_${arch}.tar.gz"
fi fi
@@ -55,10 +55,10 @@ mkdir -p "releases/v${version}"
# Download with curl if possible. # Download with curl if possible.
if [ -x "$(which curl 2>/dev/null)" ]; then if [ -x "$(which curl 2>/dev/null)" ]; then
curl -sSL "${url}" -o "releases/v${version}.tar.gz" curl --fail -sSL "${url}" -o "releases/v${version}.tar.gz"
else else
wget -q "${url}" -O "releases/v${version}.tar.gz" wget -q "${url}" -O "releases/v${version}.tar.gz"
fi fi
tar xzf "releases/v${version}.tar.gz" -C "releases/v${version}" tar xzf "releases/v${version}.tar.gz" -C "releases/v${version}"
mv "releases/v${version}/bin/${name}" "bin/${name}" || \ mv "releases/v${version}/${name}" "bin/${name}" || \
mv "releases/v${version}/bin/${name}.exe" "bin/${name}" mv "releases/v${version}/${name}.exe" "bin/${name}"