new front end #33

This commit is contained in:
2024-07-30 20:47:46 -04:00
parent baad9b0eec
commit fc66225cf5
37 changed files with 1317 additions and 15375 deletions
+207 -109
View File
@@ -1,78 +1,106 @@
<%- include('top') %>
<script id="rowTemplate" type="text/html">
<tr action="api" class="<<fresh>>">
<input type="hidden" name="host" value="<< host >>" />
<td><a target="_blank" href="<<forcessl>><<host>>"><<forcessl>><<host>></a></td>
<td><< targetssl >><< ip >>:<< targetPort >></td>
<td class="hidden-xs"><<updated_on>></td>
<td>
<button type="button" data-host="<< host >>" onclick="editHost(this);" class="btn btn-sm btn-default">Edit</button>
<button type="button" onclick="app.host.remove({host:'<<host>>'}, function(){tableAJAX('Host <<host>> delete.')})" class="btn btn-sm btn-default">Delete</button>
</td>
</tr>
</script>
<script type="text/javascript">
var currentEditHost;
// Require login to see this page.
app.auth.forceLogin()
</script>
<style type="text/css">
label.control-label{
font-weight: bold;
margin-bottom: 1px;
}
.card-title{
font-weight: bold;
}
div.editWindow{
margin-bottom: 1em;
}
</style>
<script type="text/javascript">
function parseHostRow(host) {
host['updated_on_text'] = moment(host['updated_on'], "x").fromNow();
host['targetssl_text'] = host['targetssl'] ? 'https://' : 'http://';
host['forcessl_text'] = host['forcessl'] ? 'https://' : 'http://';
return host;
}
function populateHosts(){
app.host.list(function(error, res){
if(error) return app.util.actionMessage(error, $.scope.hosts.$this, 'danger');
for(let host of res){
$.scope.hosts.push(parseHostRow(host));
}
$.scope.hosts.__setPut(function($el, item, list){
$el.addClass('bg-success');
$el.fadeIn(1000, function(){
$el.removeClass('bg-success');
});
});
});
}
function cancleHostEdit(){
$('#hostsTable').find('tr').each(function(idx, el){
console.log('here?')
$(el).removeClass('table-warning');
});
$('.editWindow').slideUp('fast');
}
function editHost(btn, host){
cancleHostEdit();
$(btn).closest('tr').addClass('table-warning');
$('.editWindow .card-title').html("Edit "+ host);
$('div.editWindow .card-body span').html($('#addHost').html());
$('div.editWindow .card-body span button').remove();
$(".editWindow input[name='edit_host']").val(host);
function editHost(btn){
var btn = $(btn);
currentEditHost = btn.data('host');
$('.editWindow').slideDown('fast');
$('.editWindow .panel-title .pull-left').html("Edit "+ btn.data('host'))
$('div.editWindow .panel-body span').html($('#addHost').html())
$('div.editWindow .panel-body span button').remove()
$(".editWindow input[name='edit_host']").val(btn.data('host'));
app.host.get(currentEditHost, function(error, data){
console.log(data)
app.host.get(host, function(error, data){
$.each( data.results, function( key, value ) {
if(typeof value == "boolean"){
$(".editWindow #"+ key +"-"+ value).prop('checked', true)
}else{
$(".editWindow input[name='" + key + "']").val(value);
}
$('.editWindow .panel-body').slideDown('fast');
});
});
}
};
function tableAJAX(actionMessage){
$('#tableAJAX').html('').hide();
app.util.actionMessage('')
app.host.list(function(err, data){
if(err) return app.util.actionMessage(err, {type: 'danger'});
if(data){
$.each(data, function( key, value ) {
value['updated_on'] = moment(value['updated_on'], "x").fromNow();
value['targetssl'] = value['targetssl'] ? "https://" : "http://";
value['forcessl'] = value['forcessl'] ? "https://" : "http://";
host_row = ich.rowTemplate(value);
$('#tableAJAX').append(host_row);
});
app.util.actionMessage(actionMessage || '', {type: 'info'});
$('#tableAJAX').fadeIn('slow');
}else{
app.util.actionMessage('No hosts...', {type: 'info'});
}
function deleteHost(host){
app.host.remove({host: host}, function(err, data){
// app.util.actionMessage(`Host ${host} deleted!`, $.scope.hosts.$this, 'danger');
$.scope.hosts.remove(host);
});
}
$(document).ready(function(){
tableAJAX(); //populate the table
setInterval(tableAJAX, 30000);
populateHosts(); //populate the table
$.scope.hosts.__setTake(function($el, item, list){
$el.addClass('bg-danger');
$el.fadeOut(1000, function(){
$el.remove()
});
});
$('form.addHost').on('submit', function(){
event.preventDefault();
$form = $(this);
var action = $($form.find('button[type="submit"]')[0]).data('type')
app.util.actionMessage('')
var action = $($form.find('button[type="submit"]')[0]).data('type');
app.util.actionMessage('', $form);
if($form.attr('isValid') === 'true'){
var formdata = $form.serializeObject();
@@ -82,15 +110,18 @@
app.host[action](formdata, function(error, data){
if(error){
console.log('error data',data)
app.util.actionMessage(error + data.message, {type: 'danger'});
app.util.actionMessage(error + data.message, $form, 'danger');
return;
}
if($.scope.hosts.indexOf(data.__requestedHost) >= 0){
$.scope.hosts.update(data.__requestedHost, parseHostRow(data));
}else{
$.scope.hosts.splice(0,0, parseHostRow(data))
}
if(action == 'edit') $('.editWindow').slideUp('fast');
app.util.actionMessage(data.message || 'Error!', {type: 'info'});
tableAJAX("Added "+ formdata.host);
$form.trigger('reset');
})
}
@@ -98,38 +129,61 @@
});
</script>
<div class="row" style="display:none">
<div class="col-md-4">
<div class="panel panel-danger editWindow" style="display:none">
<div class="panel-heading">
<div class="panel-title">
<div class="pull-left">Edit $host!</div>
&nbsp;
<div class="pull-right">
<label class="glyphicon glyphicon-circle-arrow-down"></label>
<label class="glyphicon glyphicon-remove-circle"></label>
</div>
</div>
<div class="col col-md-12 col-lg-4 col-xl-3 col-xxl-2">
<!--
left column
-->
<div class="card shadow-lg editWindow" style="display:none">
<!--
Edit host card
-->
<div class="card-header text-center bg-warning">
<span class="card-icon float-start">
<i class="fa-solid fa-pencil"></i>
</span>
<span class="card-title">
</span>
<span class="float-end">
<i class="fa-solid fa-circle-minus"></i>
<i class="fa-solid fa-circle-xmark" onclick="cancleHostEdit()"></i>
</span>
</div>
<div class="panel-body">
<div class="card-body">
<form class="addHost" onsubmit="$(this).validate()">
<span></span>
<input type="hidden" name="edit_host" />
<button type="submit" data-type="edit" class="btn btn-danger host-submit">Update</button>
<button class="btn btn-link" type="reset">Cancel</button>
<button type="submit" data-type="edit" class="btn btn-warning">
<i class="fa-solid fa-pencil"></i>
Update
</button>
<button class="btn btn-secondary" type="reset" onclick="cancleHostEdit()">
<i class="fa-solid fa-ban"></i>
Cancel
</button>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
Add New Proxy
<div class="pull-right">
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
</div>
</div>
<div class="card shadow-lg">
<!--
Add new host card
-->
<div class="card-header text-center">
<span class="card-icon float-start">
<i class="fa-solid fa-plus"></i>
</span>
<span class="card-title">
New Entry
</span>
<span class="float-end">
<i class="fa-solid fa-circle-minus"></i>
</span>
</div>
<div class="panel-body">
<div class="card-header actionMessage" style="display:none"></div>
<div class="card-body">
<form class="addHost" id="addHost" onsubmit="$(this).validate()">
<div class="form-group">
@@ -149,7 +203,7 @@
</div>
<div class="form-group">
<label class="control-label">Hostname</label>
<label class="control-label">Incoming Host Name</label>
<input type="text" name="host" class="form-control" placeholder="ex: proxy.cloud-ops.net" validate=":3" >
</div>
@@ -178,42 +232,86 @@
</label>
</div>
</div>
<button type="submit" data-type="add" class="btn btn-default host-submit">Add</button>
<hr />
<button type="submit" data-type="add" class="btn btn-success">
<i class="fa-solid fa-plus"></i>
Add
</button>
</form>
</div>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<div class="col col-md-12 col-lg-8 col-xl-9 col-xxl-10">
<!--
Right column
-->
<div class="card shadow-lg">
<!--
List current hosts
-->
<div class="card-header text-center">
<span class="card-icon float-start">
<i class="fa-solid fa-network-wired"></i>
</span>
<span class="card-title">
Proxy List
<div class="pull-right">
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
<label class="glyphicon glyphicon-refresh"></label>
</div>
</div>
</div>
<div class="panel-body" style="padding-bottom:0">
<div class="alert alert-warning actionMessage" style="display:none">
<!-- Message after AJAX action is preformed -->
</div>
<div class="table-responsive">
<table class="table">
<thead>
<th>Hostname</th>
<th>target</th>
<th class="hidden-xs">Updated</th>
<th>Actions</th>
</thead>
<tbody id="tableAJAX">
<!-- ajax loaded table -->
</tbody>
</table>
</div>
</span>
<span class="float-end">
<i class="fa-solid fa-circle-minus"></i>
</span>
</div>
<div class="card-header actionMessage" style="display:none"></div>
<table class="card-body table table-striped" style="margin-bottom:0">
<thead>
<th>
Host Name
</th>
<th>
target
</th>
<th class="hidden-xs">
Updated
</th>
<th>
Actions
</th>
</thead>
<tbody id="hostsTable">
<tr action="api" jq-repeat="hosts" jq-repeat-index='host' style="display:none">
<td>
<a target="_blank" href="{{ forcessl_text }}{{ host }}">
{{{ forcessl_text }}}{{ host }}
</a>
</td>
<td>
{{{ targetssl_text }}}{{ ip }}:{{ targetPort }}
</td>
<td class="hidden-xs momentFromNow" data-date="{{ updated_on }}">
{{ updated_on_text }}
</td>
<td>
<div class="btn-group">
<!-- <button type="button" class="btn btn-info">
<i class="fa-brands fa-expeditedssl"></i>
Cert
</button> -->
<button type="button" onclick="editHost(this, '{{ host }}');" class="btn btn-sm btn-warning">
<i class="fa-solid fa-pencil"></i> Edit
</button>
<button type="button" onclick="deleteHost('{{ host }}')" class="btn btn-sm btn-danger">
<i class="fa-solid fa-trash-can"></i>
Delete
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
-2
View File
@@ -1,2 +0,0 @@
<% include top %>
<% include bottom %>
+28 -35
View File
@@ -3,57 +3,50 @@
app.auth.isLoggedIn(function(error, isLoggedIn){
if(isLoggedIn){
window.location.href = app.util.getUrlParameter('redirect') || '/';
app.auth.logInRedirect();
}
})
$(document).ready(function(){
$( "form[action='login']" ).submit(function( event ) {
event.preventDefault();
$form = $(this);
app.util.actionMessage('')
if($form.attr('isValid') !== 'true'){
console.log('')
return app.util.actionMessage('Please fix the errors bellow!')
}
app.auth.logIn($form.serializeObject(), function(error, data){
if(data){
app.util.actionMessage('Login successful!');
window.location.href = app.util.getUrlParameter('redirect') || '/';
}else{
app.util.actionMessage('Login Failed, please try again');
}
});
});
});
</script>
<div class="row">
<div class="row" style="display: none;">
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Log in</div>
<div class="shadow-lg card">
<div class="card-header shadow">
Password Log in
</div>
<div class="panel-body">
<div class="alert alert-warning actionMessage" style="display:none">
</div>
<form action="login" onsubmit="$(this).validate()">
<div class="card-header shadow actionMessage" style="display:none"></div>
<div class="card-body">
<form action="auth/login" onsubmit="formAJAX(this)" evalAJAX="
app.auth.setToken(data.token);
app.auth.logInRedirect();
">
<input type="hidden" name="redirect" value="<%= redirect %>">
<div class="form-group">
<label class="control-label">User name</label>
<input type="text" name="username" class="form-control" placeholder="User" validate="user:3" />
<div class="input-group mb-3 shadow">
<div class="input-group-prepend">
<span class="input-group-text" ><i class="fa-solid fa-user-tie"></i></span>
</div>
<input type="text" name="username" class="form-control" placeholder="jsmith" />
</div>
</div>
<div class="form-group">
<label class="control-label">Password</label>
<input type="password" name="password" class="form-control" placeholder="Password" validate="password:5" />
<div class="input-group mb-3 shadow">
<div class="input-group-prepend">
<span class="input-group-text" ><i class="fa-solid fa-key"></i></span>
</div>
<input type="password" name="password" class="form-control" placeholder="hunter123!"/>
</div>
</div>
<button type="submit" class="btn btn-default" >Log in</button>
<button type="submit" class="btn btn-outline-dark"><i class="fa-solid fa-right-to-bracket"></i> Log in</button>
</form>
</div>
</div>
</div>
</div>
<%- include('bottom') %>
<%- include('bottom') %>
+83 -34
View File
@@ -1,21 +1,28 @@
<!DOCTYPE html>
<html >
<head>
<title>Proxy - Theta 42</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Proxy - Theta 42 <%- title %></title>
<!-- CSS are placed here -->
<link rel='stylesheet' href='/static/css/bootstrap.min.css' />
<link rel="stylesheet" href="/static-modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/static-modules/@fortawesome/fontawesome-free/css/all.min.css">
<link rel='stylesheet' href='/static/css/styles.css' />
<!-- Scripts are placed here -->
<script type="text/javascript" src='/static/js/jquery.min.js'></script>
<script type="text/javascript" src='/static/js/bootstrap.min.js'></script>
<script type="text/javascript" src='/static/js/ICanHaz.js'></script>
<!-- <script type="text/javascript" src="/socket.io/socket.io.js"></script> -->
<script type="text/javascript" src='/static-modules/jquery/dist/jquery.js'></script>
<script type="text/javascript" src='/static-modules/jquery-ui/dist/jquery-ui.min.js'></script>
<!-- <script type="text/javascript" src="/static/lib/js/popper-1.16.0.min.js"></script> -->
<script type="text/javascript" src="/static-modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/static-modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="/static-modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
<script type="text/javascript" src='/static-modules/mustache/mustache.min.js'></script>
<script type="text/javascript" src='/static/lib/js/jq-repeat_new.js'></script>
<script type="text/javascript" src='/static/lib/js/val.js'></script>
<script type="text/javascript" src="/static-modules/moment/moment.js"></script>
<script type="text/javascript" src="/static/lib/js/app-base.js"></script>
<script type="text/javascript" src="/static/js/app.js"></script>
<script type="text/javascript" src="/static/js/val.js"></script>
<script type="text/javascript" src="/static/js/moment.js"></script>
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
@@ -23,27 +30,69 @@
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Dynamic Proxy</a>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<body>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="#">Dynamic Proxy <%- title %></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarCollapse">
<ul class="navbar-nav top-nav">
<li class="nav-item">
<a class="nav-link active" href="/hosts"><i class="fa-solid fa-network-wired"></i> Hosts</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/users"><i class="fa-solid fa-users"></i> Users Panel</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/topics"> Topics</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/theta42/proxy" target="_blank">
<i class="fa-brands fa-github"></i>
</a>
</li>
</ul>
<div class="form-inline mt-2 mt-md-0">
<!-- Show the login/logout button -->
<a id="cl-login-button" class="btn btn-outline-danger my-2 my-sm-0" onclick="app.auth.forceLogin()" style="display: none;">
<i class="fas fa-sign-out"></i>
Login
</a>
<button id="cl-logout-button" class="btn btn-outline-danger my-2 my-sm-0" onclick="app.auth.logOut(e => window.location.href='/')" style="display: none;">
<i class="fas fa-sign-out"></i>
Log Out
</button>
</div>
<div id="navbar-collapse-1" class="collapse navbar-collapse navbar-ex4-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/hosts">Hosts</a>
<li><a href="/users">User Panel</a>
<li><a href="/" onclick="app.auth.logOut()">Log out</a>
</ul>
</div>
</div>
<!-- <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> -->
</div>
</div>
</nav>
<script type="text/javascript">
$(document).ready(function(){
// window.location.pathname.toLocaleLowerCase()
// Set the correct link to active in the top nav bar
$('.top-nav a').each(function(index){
let $this = $(this);
$this.removeClass('active');
if($this.attr('href').toLocaleLowerCase() === window.location.pathname.toLocaleLowerCase()){
$this.addClass('active')
}
})
// Set the correct login/logout button
app.auth.isLoggedIn(function(error, data){
if(data) $('#cl-logout-button').show();
else $('#cl-login-button').show();
});
});
</script>
<!-- Container -->
<div class="container">
<div id="spa-shell" class="container-fluid">
+104 -82
View File
@@ -1,109 +1,131 @@
<%- include('top') %>
<script id="rowTemplate" type="text/html">
<tr action="user/password/<< username >>" method="put" evalAJAX="$form.trigger('reset')">
<td>
<< uid >>:<< username >>
</td>
<td>
<input type="hidden" name="username" value="<< username >>" />
<div class="col-xs-10 form-group">
<label class="control-label"></label>
<input type="password" size="15" class="form-control" name="password" placeholder="New password" validate="password:5"/>
</div>
<style type="text/css">
@include color-mode(dark) {
// CSS variable overrides here...
}
label.control-label{
font-weight: bold;
margin-bottom: 1px;
}
.card-title{
font-weight: bold;
}
</style>
<button type="button btn-warn" onclick="formAJAX(this)" class="btn btn-sm btn-warn">
Change
</button>
</td>
<td>
<button type="button" onclick="app.user.remove({username: '<<username>>'}, function(){tableAJAX('username <<username>> delete.')})" class="btn btn-sm btn-danger">
Delete
</button>
</td>
</tr>
</script>
<script type="text/javascript">
function tableAJAX(actionMessage){
$('#tableAJAX').html('').hide();
app.util.actionMessage('Refreshing user list...')
function populateUsers(actionMessage){
app.user.list(function(error, data){
$.each( data.results, function(key, value) {
if(value.uid+'' && value.uid < 1000) return;
user_row = ich.rowTemplate(value);
$('#tableAJAX').append(user_row);
});
$('#tableAJAX').fadeIn('slow');
app.util.actionMessage(actionMessage || '', {type: 'info'});
if(error) return app.util.actionMessage(error, $.scope.users.$this, 'danger');
for(let user of data.results){
$.scope.users.push(user);
}
$.scope.users.__setPut(function($el, item, list){
$el.addClass('bg-success');
$el.fadeIn(3000, function(){
$el.removeClass('bg-success');
});
})
});
}
function removeUser(username){
app.user.remove({username: username}, function(error, data){
if(error) return app.util.actionMessage(error, $.scope.users.$this, 'danger');
$.scope.users.remove(username);
});
}
$(document).ready(function(){
tableAJAX(); //populate the table
populateUsers(); //populate the table
$.scope.users.__setTake(function($el, item, list){
$el.addClass('bg-danger');
$el.fadeOut(1000, function(){
$el.remove()
});
});
});
</script>
<div class="row" style="display:none">
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
Add new user
<div class="pull-right">
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
</div>
<div class="card shadow-lg">
<div class="card-header">
<span class="card-header-icon">
<i class="fa-solid fa-user-plus"></i>
</span>
<span class="card-title mx-auto p-2">
Add New User
</span>
<div class="float-right">
<i class="fa-solid fa-circle-minus"></i>
</div>
</div>
<div class="panel-body">
<form action="user/" evalAJAX="$form.trigger('reset')">
<input type="hidden" class="form-control" name="delete" value="false" />
<div class="form-group">
<label class="control-label">User-name</label>
<input type="text" class="form-control" name="username" placeholder="Letter, numbers, -, _, . and @ only" validate="user:3" />
</div>
<div class="form-group">
<label class="control-label">Password</label>
<input type="password" class="form-control" name="password" placeholder="Atleast 5 char. long" validate="password:5"/>
</div>
<div class="form-group">
<label class="control-label">Again</label>
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:password"/>
</div>
<button type="button" onclick="formAJAX(this)" class="btn btn-default">Add</button>
</form>
<div class="card-header actionMessage" style="display:none"></div>
<div class="card-body">
<form action="user/" evalAJAX="
$.scope.users.splice(0, 0, data);
">
<input type="hidden" class="form-control" name="delete" value="false" />
<div class="form-group">
<label class="control-label">User-name</label>
<input type="text" class="form-control" name="username" placeholder="Letter, numbers, -, _, . and @ only" validate="user:3" />
</div>
<div class="form-group">
<label class="control-label">Password</label>
<input type="password" class="form-control" name="password" placeholder="Atleast 5 char. long" validate="password:5"/>
</div>
<div class="form-group">
<label class="control-label">Again</label>
<input type="password" class="form-control" name="passwordMatch" placeholder="Retype password" validate="eq:password"/>
</div>
<button type="button" onclick="formAJAX(this)" class="btn btn-info">Add</button>
</form>
</div>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<div class="card shadow-lg">
<div class="card-header">
<span class="card-title">
<i class="fa-solid fa-users"></i>
User List
<div class="pull-right">
<label class="glyphicon glyphicon-circle-arrow-down panel-toggle"></label>
</div>
</div>
</div>
<div class="panel-body" style="padding-bottom:0">
<div class="alert alert-warning actionMessage" style="display:none">
<!-- Message after AJAX action is preformed -->
</div>
<div class="table-responsive">
<table class="table">
<thead>
<th>Name</th>
<th>Password</th>
<th>Delete</th>
</thead>
<tbody id="tableAJAX">
<!-- ajax loaded table -->
</tbody>
</table>
</span>
<div class="float-right">
<i class="fa-solid fa-circle-minus"></i>
</div>
</div>
<div class="card-header actionMessage" style="display:none"></div>
<table class="card-body table table-striped" style="margin-bottom:0">
<thead>
<th>Name</th>
<th>Password</th>
<th>Delete</th>
</thead>
<tbody>
<tr jq-repeat="users" jq-repeat-index="username" style="display:none" >
<td class="align-middle">
{{ username }}
</td>
<td>
<form class="input-group" action="user/password/{{ username }}" method="put" onsubmit="formAJAX(this)">
<input type="password" name="password" class="form-control" placeholder="Change {{ username }} password" aria-label="Update password">
<button class="btn btn-warning" type="submit">Change</button>
</form>
</td>
<td class="align-middle">
<button type="button" class="btn btn-danger" onclick="removeUser('{{username}}')">
<i class="fa-solid fa-user-slash"></i>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>