Skip to content

Commit

Permalink
Begin work on clustering ui
Browse files Browse the repository at this point in the history
  • Loading branch information
NHAS committed Jan 24, 2024
1 parent 32e92f7 commit 41e035e
Show file tree
Hide file tree
Showing 8 changed files with 433 additions and 64 deletions.
13 changes: 11 additions & 2 deletions internal/data/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type (
AclChangesFunc func(TargettedEvent[acls.Acl], int)
GroupChangesFunc func(TargettedEvent[[]string], int)

ClusterHealthFunc func(state string, dead int)
ClusterHealthFunc func(state string, serverID int)
)

var (
Expand Down Expand Up @@ -210,6 +210,7 @@ func checkClusterHealth() {

select {
case <-etcdServer.Server.LeaderChangedNotify():

execWatchers(clusterHealthWatchers, "changed", 0)
leader := etcdServer.Server.Leader()
if leader == 0 {
Expand All @@ -219,7 +220,7 @@ func checkClusterHealth() {
}

if leader != 0 {
execWatchers(clusterHealthWatchers, "healthy", 0)
notfyHealthy()
} else {
execWatchers(clusterHealthWatchers, "dead", 0)
}
Expand All @@ -228,3 +229,11 @@ func checkClusterHealth() {

}
}

func notfyHealthy() {
if etcdServer.Server.IsLearner() {
execWatchers(clusterHealthWatchers, "learner", 0)
} else {
execWatchers(clusterHealthWatchers, "healthy", 0)
}
}
200 changes: 200 additions & 0 deletions ui/src/js/clustering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@


// Call the dataTables jQuery plugin
function getIdSelections(table) {
return $.map(table.bootstrapTable('getSelections'), function (row) {
return row.internal_ip
})
}

function responseHandler(res) {
$.each(res.rows, function (i, row) {
row.state = $.inArray(row.internal_ip, selections) !== -1
})
return res
}

function ownersFormatter(values, row) {
let a = document.createElement('a')
a.href = '/management/users/?username=' + encodeURIComponent(row.owner)
a.innerText = row.owner

return a.outerHTML
}

function lockedFormatter(value) {
let p = document.createElement('p')
if (value === true) {
p.className = "badge badge-danger"
}
p.innerText = value
return p.outerHTML
}


$(function () {
let table = createTable('#devicesTable', [
{
field: 'state',
checkbox: true,
align: 'center',
escape: "true"
}, {
title: 'Owner',
field: 'owner',
align: 'center',
sortable: true,
formatter: ownersFormatter
}, {
field: 'active',
title: 'Active',
sortable: true,
align: 'center',
escape: "true"
}, {
field: 'is_locked',
title: 'Locked',
sortable: true,
align: 'center',
formatter: lockedFormatter
}, {
field: 'internal_ip',
title: 'Address',
sortable: true,
align: 'center',
escape: "true"
}, {
field: 'public_key',
title: 'Public Key',
sortable: true,
align: 'center',
escape: "true"
}, {
field: 'last_endpoint',
title: 'Last Endpoint Address',
sortable: true,
align: 'center',
escape: "true"
}
])

var $remove = $('#remove')
var $lock = $('#lock')
var $unlock = $('#unlock')


table.on('check.bs.table uncheck.bs.table ' +
'check-all.bs.table uncheck-all.bs.table',
function () {
let enableModifications = !table.bootstrapTable('getSelections').length;

$("#removeStart").prop('disabled', enableModifications)
$lock.prop('disabled', enableModifications)
$unlock.prop('disabled', enableModifications)

// save your data, here just save the current page
selections = getIdSelections(table)
// push or splice the selections if you want to save all data selections
})
$lock.on("click", function () {
var ids = getIdSelections(table)
action(ids, "lock", table)
})

$unlock.on("click", function () {
var ids = getIdSelections(table)
action(ids, "unlock", table)
})

$remove.on("click", function () {
var ids = getIdSelections(table)
table.bootstrapTable('remove', {
field: 'internal_ip',
values: ids
})


fetch("/management/devices/data", {
method: 'DELETE',
mode: 'same-origin',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
headers: {
'Content-Type': 'application/json',
'WAG-CSRF': $("#csrf_token").val()
},
body: JSON.stringify(ids)
}).then((response) => {
if (response.status == 200) {
table.bootstrapTable('refresh')
$("#issue").hide()
return
}

response.text().then(txt => {

$("#issue").text(txt)
$("#issue").show()
})
})
})

$('#clearFilter').on("click", function () {
table.bootstrapTable('filterBy', {})
$('#clearFilter').hide()
})

const urlParams = new URLSearchParams(window.location.search);
if (urlParams.toString().length > 0) {
$('#clearFilter').show()

let filter = {}

if (urlParams.has('owner')) {
filter.owner = urlParams.get('owner')
}

if (urlParams.has('is_locked')) {
filter.is_locked = urlParams.get('is_locked') == "true"
}

if (urlParams.has('active')) {
filter.active = urlParams.get('active') == "true"
}

table.bootstrapTable('filterBy', filter)
}

});

function action(onDevices, action, table) {
let data = {
"action": action,
"addresses": onDevices,
}

fetch("/management/devices/data", {
method: 'PUT',
mode: 'same-origin',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
headers: {
'Content-Type': 'application/json',
'WAG-CSRF': $("#csrf_token").val()
},
body: JSON.stringify(data)
}).then((response) => {
if (response.status == 200) {
table.bootstrapTable('refresh')
$("#issue").hide()
return
}

response.text().then(txt => {
$("#issue").text(txt)
$("#issue").show()
})
})
}
30 changes: 30 additions & 0 deletions ui/src/scss/_utilities.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,33 @@
@import "utilities/border.scss";
@import "utilities/progress.scss";
@import "utilities/rotate.scss";

.status {
&.open:before {
background-color: #94E185;
border-color: #78D965;
box-shadow: 0px 0px 4px 1px #94E185;
}

&.in-progress:before {
background-color: #FFC182;
border-color: #FFB161;
box-shadow: 0px 0px 4px 1px #FFC182;
}

&.dead:before {
background-color: #C9404D;
border-color: #C42C3B;
box-shadow: 0px 0px 4px 1px #C9404D;
}

&:before {
content: ' ';
display: inline-block;
width: 7px;
height: 7px;
margin-right: 10px;
border: 1px solid #000;
border-radius: 7px;
}
}
13 changes: 13 additions & 0 deletions ui/statemanager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ui

import "github.com/NHAS/wag/internal/data"

var (
clusterState string
serverID string
)

func watchClusterHealth(state string, _ int) {
clusterState = state
serverID = data.GetServerID()

Check failure on line 12 in ui/statemanager.go

View workflow job for this annotation

GitHub Actions / test

undefined: data.GetServerID
}
10 changes: 6 additions & 4 deletions ui/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package ui

type Page struct {
Update
Description string
Title string
User string
WagVersion string
Description string
Title string
User string
WagVersion string
ClusterState string
ServerID string
}

type Dashboard struct {
Expand Down
38 changes: 38 additions & 0 deletions ui/templates/management/clustering.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{define "Content"}}


<link href="/vendor/bootstrap-table/css/bootstrap-table.min.css" rel="stylesheet">

<div class="card shadow mb-4">
<div class="card-header py-3">
<h1 class="m-0 text-gray-900">Cluster</h1>
<div class="d-sm-flex justify-content-between">
<p>
Wag ETCd cluster nodes
</p>
</div>
</div>
<div class="card-body">
<div id="toolbar">
<button id="add" class="btn btn-primary">
<i class="icon-plus"></i> Add
</button>
<button id="removeStart" class="btn btn-danger" disabled data-toggle='modal' data-target='#deleteModal'>
<i class="icon-trash"></i> Remove
</button>
</div>
<table id="devicesTable" data-toolbar="#toolbar" data-search="true" data-show-refresh="true"
data-show-columns="true" data-show-columns-toggle-all="true" data-minimum-count-columns="2"
data-show-pagination-switch="true" data-pagination="true" data-id-field="username"
data-page-list="[10, 25, 50, 100, all]" data-side-pagination="client" data-url="/management/clustering/data"
data-response-handler="responseHandler">
</table>
</div>
</div>

<script src="/vendor/bootstrap-table/js/bootstrap-table.min.js"></script>
<script src="/vendor/bootstrap-table/js/bootstrap-table-locale-all.min.js"></script>
<script src="/js/default_table.min.js"></script>
<script src="/js/clustering.min.js"></script>

{{end}}
21 changes: 18 additions & 3 deletions ui/templates/menus.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@
<span>Devices</span></a>
</li>

<li class="nav-item">
<a class="nav-link" href="/management/clustering/">
<i class="icon icon-users
"></i>
<span>Clustering</span></a>
</li>


<!-- Divider -->
<hr class="sidebar-divider">
Expand Down Expand Up @@ -172,7 +179,17 @@ <h6 class="collapse-header">Tools:</h6>
<ul class="navbar-nav ml-auto">


{{if .Url}}
<li class="nav-item">
<div class="nav-link">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">
<div title="{{.ClusterState}}" class="status
{{if eq .ClusterState "healthy" }}open{{ else if eq .ClusterState "dead"
}}dead{{else}}in-progress{{end}}">{{.ServerID}}</div>
</span>
</div>
</li>


<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Expand All @@ -197,8 +214,6 @@ <h6 class="collapse-header">Tools:</h6>
</a>
</div>
</li>
{{end}}



<!-- Nav Item - User Information -->
Expand Down
Loading

0 comments on commit 41e035e

Please sign in to comment.