Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pkg/dashboard/assets/bootstrap-icons.min.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions pkg/dashboard/assets/bootstrap.bundle.min.js

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions pkg/dashboard/assets/bootstrap.min.css

Large diffs are not rendered by default.

Binary file added pkg/dashboard/assets/fonts/bootstrap-icons.woff
Binary file not shown.
Binary file added pkg/dashboard/assets/fonts/bootstrap-icons.woff2
Binary file not shown.
1 change: 1 addition & 0 deletions pkg/dashboard/assets/htmx.js

Large diffs are not rendered by default.

105 changes: 81 additions & 24 deletions pkg/dashboard/components.templ
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,22 @@ package dashboard

import "fmt"

templ Layout(data *dashboardData) {
templ Layout() {
<!DOCTYPE html>
<html lang="en" class="h-100">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/assets/favicon.png"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"/>
<script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
<link href="/assets/bootstrap.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="/assets/bootstrap-icons.min.css"/>
<script src="/assets/htmx.js"></script>
<style>
.htmx-request .icon-default { display: none; }
</style>
<title>KubeOne Dashboard</title>
</head>
<body class="d-flex flex-column h-100" hx-get="/" hx-trigger="every 10s" hx-target="body" hx-swap="outerHTML">
<body class="d-flex flex-column h-100">
<header class="navbar navbar-expand-lg sticky-top bd-navbar border-bottom py-3 bg-body px-4 shadow-sm">
<nav class="container-l bd-gutter d-flex flex-wrap flex-lg-nowrap align-items-center">
<img src="/assets/kubeone-logo.png" alt="logo" style="height: 30px;"/>
Expand All @@ -40,19 +43,35 @@ templ Layout(data *dashboardData) {
<div class="card shadow-sm">
<div class="card-body">
<h4 class="card-title pb-2">Control-Plane Nodes</h4>
@NodesTable(data.ControlPlaneNodes)
<div hx-get="/nodes/control-plane" hx-trigger="load, every 30s">
<div class="text-center py-3">
<div class="spinner-border text-secondary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
if len(data.WorkerNodes) > 0 {
<div id="worker-section" hx-get="/nodes/worker" hx-trigger="load, every 30s" hx-swap="outerHTML">
<div class="card-body">
<h4 class="card-title pb-2">Worker Nodes</h4>
@NodesTable(data.WorkerNodes)
<div class="text-center py-3">
<div class="spinner-border text-secondary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
}
</div>
</div>
<div class="card shadow-sm">
<div class="card-body">
<h4 class="card-title pb-2">Machine Deployments</h4>
@MachineDeploymentsTable(data.MachineDeployments)
<div id="machine-deployments" hx-get="/machine-deployments" hx-trigger="load, every 30s">
<div class="text-center py-3">
<div class="spinner-border text-secondary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
Expand All @@ -62,11 +81,7 @@ templ Layout(data *dashboardData) {
<span class="text-body-secondary">Powered by Kubermatic</span>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script>
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
</script>
<script src="/assets/bootstrap.bundle.min.js"></script>
</body>
</html>
}
Expand All @@ -85,6 +100,17 @@ templ StatusBadge(status string) {
<span class={ fmt.Sprintf("badge text-bg-%s rounded-pill", badgeClass(status)) }>{ status }</span>
}

templ WorkerNodesSection(nodes []node) {
if len(nodes) > 0 {
<div id="worker-section" class="card-body" hx-get="/nodes/worker" hx-trigger="every 30s" hx-swap="outerHTML">
<h4 class="card-title pb-2">Worker Nodes</h4>
@NodesTable(nodes)
</div>
} else {
<div id="worker-section" hx-get="/nodes/worker" hx-trigger="every 30s" hx-swap="outerHTML" style="display:none"></div>
}
}

templ NodesTable(nodes []node) {
<div class="row row-cols-1 row-cols-md-4 g-3">
for _, n := range nodes {
Expand Down Expand Up @@ -145,7 +171,13 @@ templ NodesTable(nodes []node) {
}

templ RolloutButton(md machineDeployment) {
<form method="POST" action="/rollout" hx-post="/rollout" hx-target="body" hx-swap="outerHTML">
<form
method="POST"
action="/rollout"
hx-post="/rollout"
hx-target="#machine-deployments"
hx-swap="innerHTML"
>
<input type="hidden" name="Namespace" value={ md.Namespace }/>
<input type="hidden" name="Name" value={ md.Name }/>
<button type="submit" class="btn btn-outline-warning btn-sm" title="Force rollout">
Expand All @@ -156,7 +188,13 @@ templ RolloutButton(md machineDeployment) {

templ ScaleButtons(md machineDeployment) {
<div class="d-flex align-items-center gap-2">
<form method="POST" action="/scale" hx-post="/scale" hx-target="body" hx-swap="outerHTML">
<form
method="POST"
action="/scale"
hx-post="/scale"
hx-target="#machine-deployments"
hx-swap="innerHTML"
>
<input type="hidden" name="Namespace" value={ md.Namespace }/>
<input type="hidden" name="Name" value={ md.Name }/>
<input type="hidden" name="Direction" value="down"/>
Expand All @@ -168,7 +206,13 @@ templ ScaleButtons(md machineDeployment) {
>−</button>
</form>
<span class="fw-semibold">{ fmt.Sprintf("%d", md.Replicas) }</span>
<form method="POST" action="/scale" hx-post="/scale" hx-target="body" hx-swap="outerHTML">
<form
method="POST"
action="/scale"
hx-post="/scale"
hx-target="#machine-deployments"
hx-swap="innerHTML"
>
<input type="hidden" name="Namespace" value={ md.Namespace }/>
<input type="hidden" name="Name" value={ md.Name }/>
<input type="hidden" name="Direction" value="up"/>
Expand All @@ -187,7 +231,9 @@ templ MachineDeploymentsTable(machineDeployments []machineDeployment) {
<th scope="col">Namespace</th>
<th scope="col">Replicas</th>
<th scope="col">Available</th>
<th scope="col">Scale</th> <th scope="col">Rollout</th> <th scope="col">Kubelet</th>
<th scope="col">Scale</th>
<th scope="col">Rollout</th>
<th scope="col">Kubelet</th>
<th scope="col">Age</th>
</tr>
</thead>
Expand All @@ -203,9 +249,12 @@ templ MachineDeploymentsTable(machineDeployments []machineDeployment) {
<td>{ md.Namespace }</td>
<td>{ fmt.Sprintf("%d", md.Replicas) }</td>
<td>{ fmt.Sprintf("%d", md.AvailableReplicas) }</td>
<td>@ScaleButtons(md)
</td>
<td>@RolloutButton(md)</td>
<td>
@ScaleButtons(md)
</td>
<td>
@RolloutButton(md)
</td>
<td>{ md.Kubelet }</td>
<td>{ md.Age.String() }</td>
</tr>
Expand Down Expand Up @@ -254,7 +303,13 @@ templ MachinesTable(machines []machine) {
<td>{ m.Address }</td>
<td>{ m.Age.String() }</td>
<td>
<form method="POST" action="/delete-machine" hx-post="/delete-machine" hx-target="body" hx-swap="outerHTML">
<form
method="POST"
action="/delete-machine"
hx-post="/delete-machine"
hx-target="#machine-deployments"
hx-swap="innerHTML"
>
<input type="hidden" name="Namespace" value={ m.Namespace }/>
<input type="hidden" name="Name" value={ m.Name }/>
<button
Expand Down Expand Up @@ -292,7 +347,9 @@ templ NodePodsTable(nodeName string, pods []pod) {
}
for _, p := range pods {
<tr>
<td>@PodStatusBadge(p.Status)</td>
<td>
@PodStatusBadge(p.Status)
</td>
<td>{ p.Name }</td>
<td>{ p.Namespace }</td>
<td>{ p.Ready }</td>
Expand Down
Loading