add admin page,

move requestTicket and deleteAllCookies to login.js,
update to new auth paths
This commit is contained in:
Arthur Lu 2024-07-16 19:00:30 +00:00
parent 019a3a4455
commit db06522d15
11 changed files with 201 additions and 119 deletions

View File

@ -46,33 +46,32 @@
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav>
<nav id="navigation">
<a href="index.html">Instances</a>
<a href="account.html" aria-current="page">Account</a>
<a href="settings.html">Settings</a>
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
<a href="login.html">Logout</a>
</nav>
</header>
<main>
<section>
<h2>Account</h2>
<div class="w3-card w3-padding">
<h3>Account Details</h3>
<p id="username">Username:</p>
<p id="pool">Pools:</p>
<p id="vmid">VMID Range:</p>
<p id="nodes">Nodes:</p>
</div>
<div class="w3-card w3-padding">
<div class="flex row nowrap">
<h3>Password</h3>
<button class="w3-button w3-margin" id="change-password">Change Password</button>
</div>
</div>
<div class="w3-card w3-padding">
<h3>Cluster Resources</h3>
<div id="resource-container"></div>
</div>
<h2>Account</h2>
<section class="w3-card w3-padding">
<h3>Account Details</h3>
<p id="username">Username:</p>
<p id="pool">Pools:</p>
<p id="vmid">VMID Range:</p>
<p id="nodes">Nodes:</p>
</section>
<section class="w3-card w3-padding">
<div class="flex row nowrap">
<h3>Password</h3>
<button class="w3-button w3-margin" id="change-password">Change Password</button>
</div>
</section>
<section class="w3-card w3-padding">
<h3>Cluster Resources</h3>
<div id="resource-container"></div>
</section>
</main>
</body>

66
admin.html Normal file
View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>proxmox - dashboard</title>
<link rel="icon" href="images/favicon.svg" sizes="any" type="image/svg+xml">
<link rel="stylesheet" href="w3.css">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/nav.css">
<script src="scripts/admin.js" type="module"></script>
</head>
<body>
<header>
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav id="navigation">
<a href="index.html">Instances</a>
<a href="account.html">Account</a>
<a href="settings.html">Settings</a>
<a id="admin-link" href="admin.html" aria-current="page">Admin</a>
<a href="login.html">Logout</a>
</nav>
</header>
<main>
<h2>Cluster Administration</h2>
<section class="w3-card w3-padding">
<div class="flex row nowrap" style="margin-top: 1em; justify-content: space-between;">
<h3>Users</h3>
<button type="button" id="user-add" class="w3-button" aria-label="create new user">
<span class="large" style="margin: 0;">Create User</span>
<img class="small" style="height: 1lh; width: 1lh;" src="images/actions/user/add.svg" alt="Create New User">
</button>
</div>
<div>
<div class="w3-row" style="border-bottom: 1px solid;">
<p class="w3-col l4 m4 s6">User</p>
<p class="w3-col l4 m4 w3-hide-small">Groups</p>
<p class="w3-col l2 w3-hide-medium w3-hide-small">Admin</p>
<p class="w3-col l2 m4 s6">Actions</p>
</div>
<div id="user-container"></div>
</div>
</section>
<section class="w3-card w3-padding">
<div class="flex row nowrap" style="margin-top: 1em; justify-content: space-between;">
<h3>Groups</h3>
<button type="button" id="group-add" class="w3-button" aria-label="create new group">
<span class="large" style="margin: 0;">Create Group</span>
<img class="small" style="height: 1lh; width: 1lh;" src="images/actions/group/add.svg" alt="Create New Group">
</button>
</div>
<div>
<div class="w3-row" style="border-bottom: 1px solid;">
<p class="w3-col l4 m4 s6">Group</p>
<p class="w3-col l6 m4 w3-hide-small">Members</p>
<p class="w3-col l2 m4 s6">Actions</p>
</div>
<div id="group-container"></div>
</div>
</section>
</main>
</body>
</html>

View File

@ -18,10 +18,11 @@
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav>
<nav id="navigation">
<a href="index.html" aria-current="page">Instances</a>
<a href="account.html">Account</a>
<a href="settings.html">Settings</a>
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
<a href="login.html">Logout</a>
</nav>
</header>

View File

@ -136,6 +136,26 @@ hr, * {
min-height: 1em;
}
@media screen and (width >= 440px) {
button .large {
display: block;
}
button .small {
display: none;
}
}
@media screen and (width <= 440px) {
button .large {
display: none;
}
button .small {
display: block;
}
}
.w3-select, select {
padding: 8px;
appearance: none;
@ -143,4 +163,10 @@ hr, * {
background-repeat: no-repeat;
background-position: right 8px top 50%;
background-size: 1em auto;
}
@media (width >=993px) {
.w3-hide-large {
display: none !important;
}
}

View File

@ -24,23 +24,11 @@
#vm-search {
max-width: calc(100% - 10px - 152px);
}
button .large {
display: block;
}
button .small {
display: none;
}
}
@media screen and (width <= 440px) {
#vm-search {
max-width: calc(100% - 10px - 47px);
}
button .large {
display: none;
}
button .small {
display: block;
}
}
</style>
</head>
@ -49,10 +37,11 @@
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav>
<nav id="navigation">
<a href="index.html" aria-current="page">Instances</a>
<a href="account.html">Account</a>
<a href="settings.html">Settings</a>
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
<a href="login.html">Logout</a>
</nav>
</header>
@ -72,27 +61,13 @@
</div>
<div>
<div class="w3-row w3-hide-small" style="border-bottom: 1px solid;">
<div class="w3-col l1 m2">
<p>ID</p>
</div>
<div class="w3-col l2 m3">
<p>Name</p>
</div>
<div class="w3-col l1 m2">
<p>Type</p>
</div>
<div class="w3-col l2 m3">
<p>Status</p>
</div>
<div class="w3-col l2 w3-hide-medium">
<p>Host Name</p>
</div>
<div class="w3-col l2 w3-hide-medium">
<p>Host Status</p>
</div>
<div class="w3-col l2 m2">
<p>Actions</p>
</div>
<p class="w3-col l1 m2 w3-hide-small">ID</p>
<p class="w3-col l2 m3 w3-hide-small">Name</p>
<p class="w3-col l1 m2 w3-hide-small">Type</p>
<p class="w3-col l2 m3 w3-hide-small">Status</p>
<p class="w3-col l2 w3-hide-medium w3-hide-small">Host Name</p>
<p class="w3-col l2 w3-hide-medium w3-hide-small">Host Status</p>
<p class="w3-col l2 m2 w3-hide-small">Actions</p>
</div>
<div id="instance-container"></div>
</div>

View File

@ -16,7 +16,7 @@
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav>
<nav id="navigation">
<a href="login.html" aria-current="page">Login</a>
</nav>
</header>

View File

@ -131,7 +131,7 @@ function handlePasswordChangeForm () {
`;
const d = dialog("Change Password", body, async (result, form) => {
if (result === "confirm") {
const result = await requestAPI("/auth/password", "POST", { password: form.get("new-password") });
const result = await requestAPI("/access/password", "POST", { password: form.get("new-password") });
if (result.status !== 200) {
alert(result.error);
}

8
scripts/admin.js Normal file
View File

@ -0,0 +1,8 @@
import { setTitleAndHeader, setAppearance } from "./utils.js";
window.addEventListener("DOMContentLoaded", init);
function init () {
setAppearance();
setTitleAndHeader();
}

View File

@ -1,12 +1,12 @@
import { requestTicket, goToPage, deleteAllCookies, requestPVE, setTitleAndHeader, setAppearance } from "./utils.js";
import { goToPage, requestPVE, setTitleAndHeader, setAppearance, requestAPI } from "./utils.js";
import { alert } from "./dialog.js";
window.addEventListener("DOMContentLoaded", init);
async function init () {
await deleteAllCookies();
setAppearance();
setTitleAndHeader();
await deleteAllCookies();
const formSubmitButton = document.querySelector("#submit");
const realms = await requestPVE("/access/domains", "GET");
const realmSelect = document.querySelector("#realm");
@ -42,3 +42,12 @@ async function init () {
}
});
}
async function requestTicket (username, password, realm) {
const response = await requestAPI("/access/ticket", "POST", { username: `${username}@${realm}`, password }, false);
return response;
}
async function deleteAllCookies () {
await requestAPI("/access/ticket", "DELETE");
}

View File

@ -161,11 +161,6 @@ export function getCookie (cname) {
return "";
}
export async function requestTicket (username, password, realm) {
const response = await requestAPI("/auth/ticket", "POST", { username: `${username}@${realm}`, password }, false);
return response;
}
export async function requestPVE (path, method, body = null) {
const prms = new URLSearchParams(body);
const content = {
@ -259,13 +254,18 @@ export function getURIData () {
return Object.fromEntries(url.searchParams);
}
export async function deleteAllCookies () {
await requestAPI("/auth/ticket", "DELETE");
}
export function setTitleAndHeader () {
export async function setTitleAndHeader () {
document.title = `${organization} - dashboard`;
document.querySelector("h1").innerText = organization;
if (getCookie("auth") === "1") {
const userIsAdmin = (await requestAPI("/user/config/cluster")).admin;
if (userIsAdmin) {
const adminNavLink = document.querySelector("#navigation #admin-link");
adminNavLink.href = "admin.html";
adminNavLink.classList.remove("none");
adminNavLink.ariaDisabled = false;
}
}
}
const settingsDefault = {

View File

@ -37,63 +37,61 @@
<h1>proxmox</h1>
<label for="navtoggle">&#9776;</label>
<input type="checkbox" id="navtoggle">
<nav>
<nav id="navigation">
<a href="index.html">Instances</a>
<a href="account.html">Account</a>
<a href="settings.html" aria-current="page">Settings</a>
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
<a href="login.html">Logout</a>
</nav>
</header>
<main>
<section>
<h2>Settings</h2>
<form id = "settings">
<div class="w3-card w3-padding">
<h3>Synchronization Settings</h3>
<fieldset>
<legend>App Sync Method</legend>
<label><input class="w3-radio" type="radio" id="sync-always" name="sync-scheme" value="always" required>Always Sync</label>
<p>App will always periodically synchronize with Proxmox. High resource usage.</p>
<label><input class="w3-radio" type="radio" id="sync-hash" name="sync-scheme" value="hash" required>Check For Sync</label>
<p>App will periodically check for updates and synchronize only if needed. Medium resource usage.</p>
<label><input class="w3-radio" type="radio" id="sync-interrupt" name="sync-scheme" value="interrupt" required>Sync When Needed</label>
<p>App will react to changes and synchronize when changes are made. Low resource usage.</p>
</fieldset>
<fieldset>
<legend>App Sync Frequency</legend>
<div class="input-grid" style="grid-template-columns: auto auto 1fr;">
<p>Sync every</p><input aria-label="sync rate in seconds" class="w3-input w3-border" type="number" id="sync-rate" name="sync-rate" min="1" required><p>Second(s)</p>
</div>
</fieldset>
</div>
<div class="w3-card w3-padding">
<h3>Search Settings</h3>
<fieldset>
<legend>Instance Search Criteria</legend>
<label><input class="w3-radio" type="radio" id="search-exact" name="search-criteria" value="exact" required>Exact Match</label>
<p>Sorts by exact query match in instance name.</p>
<label><input class="w3-radio" type="radio" id="search-fuzzy" name="search-criteria" value="fuzzy" required>Fuzzy Match</label>
<p>Sorts by best matching to worst matching.</p>
</fieldset>
</div>
<div class="w3-card w3-padding">
<h3>Appearance</h3>
<fieldset>
<label>
Theme
<select class="w3-select w3-border" id="appearance-theme" name="appearance-theme" style="width: fit-content; padding-right: 24px;">
<option value="auto">Auto</option>
<option value="dark">Dark</option>
<option value="light">Light</option>
</select>
</label>
</fieldset>
</div>
<div class="w3-container w3-center" id="form-actions">
<button class="w3-button w3-margin" id="save" type="submit">SAVE</button>
</div>
</form>
</section>
<h2>Settings</h2>
<form id = "settings">
<section class="w3-card w3-padding">
<h3>Synchronization Settings</h3>
<fieldset>
<legend>App Sync Method</legend>
<label><input class="w3-radio" type="radio" id="sync-always" name="sync-scheme" value="always" required>Always Sync</label>
<p>App will always periodically synchronize with Proxmox. High resource usage.</p>
<label><input class="w3-radio" type="radio" id="sync-hash" name="sync-scheme" value="hash" required>Check For Sync</label>
<p>App will periodically check for updates and synchronize only if needed. Medium resource usage.</p>
<label><input class="w3-radio" type="radio" id="sync-interrupt" name="sync-scheme" value="interrupt" required>Sync When Needed</label>
<p>App will react to changes and synchronize when changes are made. Low resource usage.</p>
</fieldset>
<fieldset>
<legend>App Sync Frequency</legend>
<div class="input-grid" style="grid-template-columns: auto auto 1fr;">
<p>Sync every</p><input aria-label="sync rate in seconds" class="w3-input w3-border" type="number" id="sync-rate" name="sync-rate" min="1" required><p>Second(s)</p>
</div>
</fieldset>
</section>
<section class="w3-card w3-padding">
<h3>Search Settings</h3>
<fieldset>
<legend>Instance Search Criteria</legend>
<label><input class="w3-radio" type="radio" id="search-exact" name="search-criteria" value="exact" required>Exact Match</label>
<p>Sorts by exact query match in instance name.</p>
<label><input class="w3-radio" type="radio" id="search-fuzzy" name="search-criteria" value="fuzzy" required>Fuzzy Match</label>
<p>Sorts by best matching to worst matching.</p>
</fieldset>
</section>
<section class="w3-card w3-padding">
<h3>Appearance</h3>
<fieldset>
<legend>Default Theme</legend>
<label>Theme<select class="w3-select w3-border" id="appearance-theme" name="appearance-theme" style="width: fit-content; padding-right: 24px;">
<option value="auto">Auto</option>
<option value="dark">Dark</option>
<option value="light">Light</option>
</select>
</label>
</fieldset>
</section>
<div class="w3-container w3-center" id="form-actions">
<button class="w3-button w3-margin" id="save" type="submit">SAVE</button>
</div>
</form>
</main>
</body>
</html>