Reorganize repos
This commit is contained in:
18
app/templates/_macros.html.j2
Normal file
18
app/templates/_macros.html.j2
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- Put your reusable template code into macros here -->
|
||||
{% macro theme_icon(theme) %}
|
||||
<div class="theme-icon">
|
||||
{% if theme == "dark" %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="theme-icon" fill="none" viewBox="0 0 24 24" stroke="yellow"
|
||||
stroke-opacity="0.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||
</svg>
|
||||
{% else %}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="theme-icon" fill="none" viewBox="0 0 18 24" stroke="grey"
|
||||
stroke-opacity="0.6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
111
app/templates/base.html
Normal file
111
app/templates/base.html
Normal file
@ -0,0 +1,111 @@
|
||||
{% import '_macros.html.j2' as mc -%}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ config.APP_NAME }}</title>
|
||||
<!-- meta -->
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
{% block meta %}{% endblock %}
|
||||
<!-- styles -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/toggle-bootstrap.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/toggle-bootstrap-dark.min.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/toggle-bootstrap-print.min.css') }}">
|
||||
<!-- Century gothic font -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='fonts/century-gothic.css') }}">
|
||||
<!-- fontawesome -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
|
||||
|
||||
<link href="{{ url_for('static', filename='main.css') }}" rel="stylesheet" media="screen">
|
||||
<!-- Datatables -->
|
||||
<link href="{{ url_for('static', filename='datatables/datatables.min.css') }}" rel="stylesheet">
|
||||
{% block links %}{% endblock %}
|
||||
<link rel="icon" type="image/png" sizes="180x180" href="{{ url_for('static', filename='favicon/apple-touch-icon.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='favicon/favicon-32x32.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='favicon/favicon-16x16.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="{{ url_for('static', filename='favicon/android-chrome-192x192.png') }}">
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="{{ url_for('static', filename='favicon/android-chrome-512x512.png') }}">
|
||||
<link rel="manifest" href="{{ url_for('static', filename='favicon/site.webmanifest') }}">
|
||||
</head>
|
||||
|
||||
<body class="bootstrap bootstrap-dark">
|
||||
<!-- Header -->
|
||||
<header>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-themed">
|
||||
<!-- Navbar Brand -->
|
||||
<a class="navbar-brand" href="{{ url_for('main.index') }}">
|
||||
<img src="{{ url_for('static', filename='/hsman.png') }}">
|
||||
<!-- HSMAN -->
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('main.nodes') }}">nodes</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('main.users') }}">users</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('main.routes') }}">routes</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item me-right">
|
||||
<a href="{{url_for('main.logout') }}" id="themeSwitch">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<!-- <i class="fas fa-plug-circle-xmark"></i> -->
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
{% if g.is_mobile %}
|
||||
<div class="container-fluid">
|
||||
{% else %}
|
||||
<div class="container">
|
||||
{% endif %}
|
||||
<!-- Main Content -->
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<!-- Footer-->
|
||||
<footer class="footer text-center">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<!-- Copyrights -->
|
||||
<div class="col-lg-12 text-center">
|
||||
<p class="text-muted mb-0 py-2">
|
||||
<!-- <img src="/static/hsman.png" height="20px"> -->
|
||||
Headscale Manager |
|
||||
ver. {{ config.APP_VERSION }} ({{ config.APP_SHA }})
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- scripts -->
|
||||
<script src="{{ url_for('static', filename='bootstrap/jquery-3.7.1.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap/popper-1.12.9.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='bootstrap/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='datatables/datatables.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='main.js') }}" type="text/javascript"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
})
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
10
app/templates/error.html
Normal file
10
app/templates/error.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="jumbotron my-4">
|
||||
<div class="text-center">
|
||||
<h1>{{ '%s - %s' % (error.code, error.name) }}</h1>
|
||||
<p>{{ error.description }}.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
71
app/templates/index.html
Normal file
71
app/templates/index.html
Normal file
@ -0,0 +1,71 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Welcome, {{ session.userinfo.name }}</h3>
|
||||
<hr>
|
||||
<h4>authentication info</h4>
|
||||
<div class="row data">
|
||||
<div class="col col-2">
|
||||
<strong>email</strong>
|
||||
</div>
|
||||
<div class="col col-6">
|
||||
{{ session.userinfo.email }}
|
||||
<!-- {{ session.userinfo.email_verified | fancyBool | safe }} -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="row data">
|
||||
<div class="col col-2">
|
||||
<strong>username</strong>
|
||||
</div>
|
||||
<div class="col col-6">
|
||||
{{ session.userinfo.preferred_username }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row data">
|
||||
<div class="col col-2">
|
||||
<strong>groups</strong>
|
||||
</div>
|
||||
<div class="col col-6">
|
||||
<i class="fas fa-angle-right"></i>
|
||||
{{ session.userinfo.groups[0]}}
|
||||
</div>
|
||||
</div>
|
||||
{% for group in session.userinfo.groups[1:] |sort %}
|
||||
<div class="row data">
|
||||
<div class="col col-2">
|
||||
|
||||
</div>
|
||||
<div class="col col-6">
|
||||
<i class="fas fa-angle-right"></i> {{ group }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<hr>
|
||||
<h4>your devices</h4>
|
||||
<div class="row strong">
|
||||
<div class="col col-2"><strong></strong></div>
|
||||
<div class="col col-2"><strong>registered</strong></div>
|
||||
<div class="col col-2"><strong>last event</strong></div>
|
||||
<div class="col col-2"><strong>online</strong></div>
|
||||
</div>
|
||||
{% for node in userNodeList %}
|
||||
<div class="row data">
|
||||
<div class="col col-2">
|
||||
{{ node.givenName}}
|
||||
</div>
|
||||
<div class="col col-2">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.createdAt | fmt_datetime }}">
|
||||
{{node.createdAt | htime_dt }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col col-2">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.lastSeen | fmt_datetime }}">
|
||||
{{node.lastSeen | htime_dt }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col col-2">
|
||||
{{node.online | fancyBool | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
209
app/templates/node.html
Normal file
209
app/templates/node.html
Normal file
@ -0,0 +1,209 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3>
|
||||
<span id="givenName">
|
||||
{{node.givenName}}
|
||||
</span>
|
||||
<a href="#" data-toggle="modal" data-target="#renameModal">
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
title="rename node">
|
||||
<i class="fas fa-edit h6"></i>
|
||||
</span>
|
||||
</a>
|
||||
</h3>
|
||||
<hr>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>status</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
{% if node.online %}
|
||||
<span class="badge badge-pill badge-success">online</span>
|
||||
{% else %}
|
||||
<span class="badge badge-pill badge-danger">offline</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>registered</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.createdAt | fmt_datetime }}">
|
||||
{{ node.createdAt | htime_dt }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>expire</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.expiry | fmt_datetime }}">
|
||||
{{ node.expiry | htime_dt }}
|
||||
</span>
|
||||
{% if node.expireDate and not node.expired %}
|
||||
<a href="{{ url_for('rest.expireNode', nodeId=node.id) }}">
|
||||
<span data-toggle="tooltip" data-placement="right" title="expire/disconnect node">
|
||||
<i class="fas fa-plug"></i>
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>owner</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<a href='{{ url_for("main.user", userName=node.user.name) }}' class="plain">{{ node.user.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
|
||||
<!-- ADDRESSES -->
|
||||
<h5>addresses</h5>
|
||||
{% for ip in node.ipAddresses %}
|
||||
<div class="row data">
|
||||
<div class="col col-3">
|
||||
{{ ip }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p></p>
|
||||
|
||||
<!-- TAGS -->
|
||||
<h5>tags</h5>
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>
|
||||
announced
|
||||
</strong>
|
||||
</div>
|
||||
<div class="col col-6 float-left">
|
||||
{% if node.validTags %}
|
||||
{% for tag in node.validTags %}
|
||||
<span class="badge badge-pill badge-warning">
|
||||
{{ tag }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
None
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>forced</strong>
|
||||
</div>
|
||||
<div class="col col-6 float-left">
|
||||
{% if node.forced %}
|
||||
{% for tag in node.forcedTags %}
|
||||
<h3><span class="badge badge-pill badge-primary">
|
||||
{{ tag }}
|
||||
</span></h3>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
None
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KEYS -->
|
||||
<p></p>
|
||||
<h5>keys</h5>
|
||||
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>machineKey</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<code>{{ node.machineKey }}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>nodeKey</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<code>{{ node.nodeKey }}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>discoKey</strong>
|
||||
</div>
|
||||
<div class="col col-8 float-left">
|
||||
<code>{{ node.discoKey }}</code>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
|
||||
<!-- ROUTES -->
|
||||
<h5>routes
|
||||
{% if isExitNode %}
|
||||
<span class="small badge-pill badge-primary">Exit Node</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
{% if routes %}
|
||||
<div class="row">
|
||||
<div class="col col-3 float-left">
|
||||
<strong>prefix</strong>
|
||||
</div>
|
||||
<div class="col col-3 float-left">
|
||||
<strong>enabled</strong>
|
||||
</div>
|
||||
<div class="col col-3 float-left">
|
||||
<strong>primary</strong>
|
||||
</div>
|
||||
</div>
|
||||
{% for route in routes | sort(attribute='prefix') %}
|
||||
<div class="row data">
|
||||
<div class="col col-3 float-left">
|
||||
{{ route.prefix }}
|
||||
</div>
|
||||
<div class="col col-3 float-left">
|
||||
{{ route.enabled | fancyBool | safe }}
|
||||
</div>
|
||||
<div class="col col-3 float-left">
|
||||
{{ route.isPrimary | fancyBool | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col col-9 text-center">
|
||||
<h3>No routes announced</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- rename modal -->
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="renameModal" tabindex="-1" role="dialog" aria-labelledby="renameModal" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="renameModalLabel">Rename node</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="text" name="newName" id="newName" value="{{ node.givenName}}">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" onClick="renameNode(id={{node.id}})">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
98
app/templates/nodes.html
Normal file
98
app/templates/nodes.html
Normal file
@ -0,0 +1,98 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>nodes</h3>
|
||||
<hr>
|
||||
<p></p>
|
||||
<table id="nodes" class="display" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>user</th>
|
||||
<th>expire</th>
|
||||
<th>last event</th>
|
||||
<th>addresses</th>
|
||||
<th>online</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for node in nodes %}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="plain" href="{{ url_for('main.node', nodeId=node.id)}}">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.ipAddresses | join('\n') }}">
|
||||
{{node.givenName}}
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="plain" href="{{ url_for('main.user', userName=node.user.name)}}">
|
||||
{{node.user.name}}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span data-toggle="tooltip" data-placement="right"
|
||||
title="{{ node.expiry | fmt_datetime }}"
|
||||
class="{% if node.expired %}expired{% endif %}">
|
||||
{{node.expireDate | htime_dt | safe}}
|
||||
</span>
|
||||
</td>
|
||||
<td data-order="{{ node.lastSeen | fmt_datetime }}">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ node.lastSeen | fmt_datetime }}">
|
||||
{{node.lastSeen | htime_dt }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{ node.ipAddresses | join(', ') }}
|
||||
</td>
|
||||
<td data-filter="{{ node.online | fancyOnline }}">
|
||||
{{node.online | fancyBool | safe}}
|
||||
</td>
|
||||
<td class="no-sort">
|
||||
{% if node.expireDate and not node.expired %}
|
||||
<span data-toggle="tooltip" data-placement="right" title="expire/disconnect">
|
||||
<a class="nodeco" href="{{ url_for('rest.expireNodeList', nodeId=node.id) }}">
|
||||
<i class="fas fa-plug"></i>
|
||||
</a>
|
||||
</span>
|
||||
{% else %}
|
||||
<i class="fas fa-plug disabled"></i>
|
||||
{% endif %}
|
||||
<span data-toggle="tooltip" data-placement="right" title="delete">
|
||||
<a class="nodeco" href="{{ url_for('rest.deleteNode', nodeId=node.id) }}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function () {
|
||||
new DataTable('#nodes', {
|
||||
paging: true,
|
||||
lengthMenu: [15, 30, 50, 100, { label: 'All', value: -1 }],
|
||||
pageLength: 30,
|
||||
fixedHeader: false,
|
||||
select: false,
|
||||
keys: false,
|
||||
aoColumnDefs: [
|
||||
{ 'bSortable': false, 'aTargets': [ -1 ] }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
target: 4,
|
||||
visible: false,
|
||||
searchable: true
|
||||
}
|
||||
]
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
93
app/templates/routes.html
Normal file
93
app/templates/routes.html
Normal file
@ -0,0 +1,93 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h5>
|
||||
Routing table
|
||||
<small class="text-muted">
|
||||
click on the icon in <em>enabled</em> column to toggle route status
|
||||
</small>
|
||||
</h5>
|
||||
<hr>
|
||||
<p></p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-12">
|
||||
<h5>Exit nodes</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for exitNode in exitNodes %}
|
||||
<div class="row data">
|
||||
<div class="col col-12">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ exitNode.ipAddresses | join('\n') }}">
|
||||
{{ exitNode.givenName }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<p></p>
|
||||
{% for prefix, rts in routes.items() %}
|
||||
<div class="row">
|
||||
<div class="col col-4 float-left">
|
||||
<strong>prefix</strong>
|
||||
</div>
|
||||
<div class="col col-4 float-left">
|
||||
<strong>gateway</strong>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
<strong>enabled</strong>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
<strong>active</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row data">
|
||||
<div class="col col-4 float-left">
|
||||
{{ prefix}}
|
||||
</div>
|
||||
<div class="col col-4 float-left">
|
||||
<a class="plain route primary" href="{{ url_for('main.node', nodeId=rts[0].node.id) }}">
|
||||
<span data-toggle="tooltip" data-placement="right"
|
||||
title="{{ rts[0].node.ipAddresses | join('\n') }}">
|
||||
{{ rts[0].node.givenName}}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
<a class="routeToggle" href="{{ url_for('rest.routeToggle', routeId=rts[0].id) }}">
|
||||
{{ rts[0].enabled | fancyBool | safe}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
{{ rts[0].isPrimary | fancyBool | safe}}
|
||||
</div>
|
||||
</div>
|
||||
{% for rt in rts[1:] %}
|
||||
<div class="row data">
|
||||
<div class="col col-4 float-left" style="border: 1px red;">
|
||||
<span> </span>
|
||||
</div>
|
||||
<div class="col col-4">
|
||||
<a class="plain route {{rt.enabled}}" href="{{ url_for('main.node', nodeId=rt.node.id) }}">
|
||||
<span data-toggle="tooltip" data-placement="right"
|
||||
title="{{ rt.node.ipAddresses | join('\n') }}">
|
||||
{{ rt.node.givenName}}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
<a class="routeToggle" href="{{ url_for('rest.routeToggle', routeId=rt.id) }}">
|
||||
{{ rt.enabled | fancyBool | safe}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col col-2 float-left">
|
||||
{{ rt.isPrimary | fancyBool | safe}}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<p></p>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
208
app/templates/user.html
Normal file
208
app/templates/user.html
Normal file
@ -0,0 +1,208 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h3>{{ user.name }}</h3>
|
||||
<hr>
|
||||
<p></p>
|
||||
<div class="row">
|
||||
<div class="col col-3">
|
||||
<strong>registered</strong>
|
||||
</div>
|
||||
<div class="col col-8">
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
title="{{ user.createdAt | fmt_datetime }}">
|
||||
{{ user.createdAt | htime_dt }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p></p>
|
||||
<!-- NODES -->
|
||||
<h5>nodes</h5>
|
||||
<table id="nodes" class="display" style="width:80%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>last connect</th>
|
||||
<th>online</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for node in userNodeList %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('main.node', nodeId=node.id) }}" class="plain">
|
||||
{{ node.givenName }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
title="{{ node.lastSeen | fmt_datetime }}">
|
||||
{{node.lastSeen | htime_dt }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{node.online | fancyBool | safe}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p></p>
|
||||
<!-- PRE AUTH KEYS -->
|
||||
<h5>
|
||||
pre auth keys
|
||||
|
||||
<button class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#createPKA">create</button>
|
||||
|
||||
</h5>
|
||||
{% if preauthKeys %}
|
||||
<table id="paks" class="display" style="width:80%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label small" for="showExpired">
|
||||
show expired
|
||||
</label>
|
||||
<input type="checkbox" class="form-check-input form-control-sm" id="showExpired">
|
||||
</div>
|
||||
</th>
|
||||
<th>created</th>
|
||||
<th>expiration</th>
|
||||
<th>attributes</th>
|
||||
<!-- <th> </th> -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key in preauthKeys %}
|
||||
<tr class="pka{% if key.expired %} pka-expired pka-hide{% endif %}">
|
||||
<td>
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
value="{{ key.key}}"
|
||||
title="click to copy full value"
|
||||
class="pak_copy">{{ key.key[:5] }}…{{ key.key[-5:] }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
title="{{ key.createdAt | fmt_datetime }}">
|
||||
{{key.createdAt | htime_dt }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span data-toggle="tooltip"
|
||||
data-placement="right"
|
||||
title="{{ key.expiration | fmt_datetime }}">
|
||||
{{key.expiration | htime_dt }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if key.ephemeral %}
|
||||
<span class="badge badge-pill badge-primary">ephemereal</span>
|
||||
{% endif %}
|
||||
{% if key.reusable %}
|
||||
<span class="badge badge-pill badge-primary">reusable</span>
|
||||
{% endif %}
|
||||
{% if key.used %}
|
||||
<span class="badge badge-pill badge-primary">used</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<!-- <td>
|
||||
<span data-toggle="tooltip" data-placement="right" title="expire">
|
||||
<a class="nodeco" href="/user/{{user.name}}/expire/{{key.key}}">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</span>
|
||||
</td> -->
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col col-9 text-center">
|
||||
<h3>No preauth keys</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- new key modal -->
|
||||
<div class="modal fade" id="createPKA" tabindex="-1" role="dialog" aria-labelledby="createPKA" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="renameModalLabel">create new pre auth key</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="datetime-local" name="expiration" id="expiration" value="{{ defaultExpiry}}">
|
||||
<label class="form-check-label" for="ephemereal">expiration</label>
|
||||
</div>
|
||||
<p></p>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="reusable" id="reusable">
|
||||
<label class="form-check-label" for="reusable">reusable</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="ephemereal" id="ephemereal">
|
||||
<label class="form-check-label" for="ephemereal">ephemereal</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" onClick="createPKA(user='{{ user.name }}')">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function () {
|
||||
$('.pak_copy').on('click', function() {
|
||||
copyToClipboard(this)
|
||||
})
|
||||
$('#showExpired').on('change', function() {
|
||||
toggleExpired(this)
|
||||
})
|
||||
|
||||
new DataTable('#nodes', {
|
||||
scrollY: 130,
|
||||
scrollCollapse: true,
|
||||
paging: false,
|
||||
// lengthMenu: [5, 10, 30, 50, { label: 'All', value: -1 }],
|
||||
// pageLength: 10,
|
||||
fixedHeader: {
|
||||
header: true,
|
||||
footer: false
|
||||
},
|
||||
info: false,
|
||||
searching: false,
|
||||
select: false,
|
||||
keys: false,
|
||||
});
|
||||
new DataTable('#paks', {
|
||||
scrollY: 230,
|
||||
scrollCollapse: true,
|
||||
paging: false,
|
||||
// lengthMenu: [5, 10, 30, 50, { label: 'All', value: -1 }],
|
||||
// pageLength: 10,
|
||||
fixedHeader: {
|
||||
header: true,
|
||||
footer: false
|
||||
},
|
||||
info: false,
|
||||
searching: false,
|
||||
select: false,
|
||||
keys: false,
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
62
app/templates/users.html
Normal file
62
app/templates/users.html
Normal file
@ -0,0 +1,62 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h3>users</h3>
|
||||
<hr>
|
||||
<p></p>
|
||||
<table id="users" class="display" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>name</th>
|
||||
<th>registered on</th>
|
||||
<th>online</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="plain" href="{{ url_for('main.user', userName=user.name)}}">
|
||||
{{user.name}}
|
||||
</a>
|
||||
</td>
|
||||
<td data-order="{{ user.createdAt }}">
|
||||
<span data-toggle="tooltip" data-placement="right" title="{{ user.createdAt | fmt_datetime }}">
|
||||
{{user.createdAt | htime_dt }}
|
||||
</span>
|
||||
</td>
|
||||
<td data-filter="{{ online[user.name] | fancyOnline }}">
|
||||
{{online[user.name] | fancyBool | safe }}
|
||||
</td>
|
||||
<td class="no-sort">
|
||||
<span data-toggle="tooltip" data-placement="right" title="delete">
|
||||
<a class="nodeco" href="/user/{{user.name}}/delete">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function () {
|
||||
new DataTable('#users', {
|
||||
paging: true,
|
||||
lengthMenu: [15, 30, 50, 100, { label: 'All', value: -1 }],
|
||||
pageLength: 30,
|
||||
fixedHeader: false,
|
||||
select: false,
|
||||
keys: false,
|
||||
aoColumnDefs: [
|
||||
{ 'bSortable': false, 'aTargets': [ -1 ] }
|
||||
],
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user