add admin page,
move requestTicket and deleteAllCookies to login.js, update to new auth paths
This commit is contained in:
parent
019a3a4455
commit
db06522d15
39
account.html
39
account.html
@ -46,33 +46,32 @@
|
|||||||
<h1>proxmox</h1>
|
<h1>proxmox</h1>
|
||||||
<label for="navtoggle">☰</label>
|
<label for="navtoggle">☰</label>
|
||||||
<input type="checkbox" id="navtoggle">
|
<input type="checkbox" id="navtoggle">
|
||||||
<nav>
|
<nav id="navigation">
|
||||||
<a href="index.html">Instances</a>
|
<a href="index.html">Instances</a>
|
||||||
<a href="account.html" aria-current="page">Account</a>
|
<a href="account.html" aria-current="page">Account</a>
|
||||||
<a href="settings.html">Settings</a>
|
<a href="settings.html">Settings</a>
|
||||||
|
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
|
||||||
<a href="login.html">Logout</a>
|
<a href="login.html">Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<section>
|
<h2>Account</h2>
|
||||||
<h2>Account</h2>
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<h3>Account Details</h3>
|
||||||
<h3>Account Details</h3>
|
<p id="username">Username:</p>
|
||||||
<p id="username">Username:</p>
|
<p id="pool">Pools:</p>
|
||||||
<p id="pool">Pools:</p>
|
<p id="vmid">VMID Range:</p>
|
||||||
<p id="vmid">VMID Range:</p>
|
<p id="nodes">Nodes:</p>
|
||||||
<p id="nodes">Nodes:</p>
|
</section>
|
||||||
</div>
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<div class="flex row nowrap">
|
||||||
<div class="flex row nowrap">
|
<h3>Password</h3>
|
||||||
<h3>Password</h3>
|
<button class="w3-button w3-margin" id="change-password">Change Password</button>
|
||||||
<button class="w3-button w3-margin" id="change-password">Change Password</button>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</div>
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<h3>Cluster Resources</h3>
|
||||||
<h3>Cluster Resources</h3>
|
<div id="resource-container"></div>
|
||||||
<div id="resource-container"></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
66
admin.html
Normal file
66
admin.html
Normal 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">☰</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>
|
@ -18,10 +18,11 @@
|
|||||||
<h1>proxmox</h1>
|
<h1>proxmox</h1>
|
||||||
<label for="navtoggle">☰</label>
|
<label for="navtoggle">☰</label>
|
||||||
<input type="checkbox" id="navtoggle">
|
<input type="checkbox" id="navtoggle">
|
||||||
<nav>
|
<nav id="navigation">
|
||||||
<a href="index.html" aria-current="page">Instances</a>
|
<a href="index.html" aria-current="page">Instances</a>
|
||||||
<a href="account.html">Account</a>
|
<a href="account.html">Account</a>
|
||||||
<a href="settings.html">Settings</a>
|
<a href="settings.html">Settings</a>
|
||||||
|
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
|
||||||
<a href="login.html">Logout</a>
|
<a href="login.html">Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
@ -136,6 +136,26 @@ hr, * {
|
|||||||
min-height: 1em;
|
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 {
|
.w3-select, select {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
@ -143,4 +163,10 @@ hr, * {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: right 8px top 50%;
|
background-position: right 8px top 50%;
|
||||||
background-size: 1em auto;
|
background-size: 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (width >=993px) {
|
||||||
|
.w3-hide-large {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
43
index.html
43
index.html
@ -24,23 +24,11 @@
|
|||||||
#vm-search {
|
#vm-search {
|
||||||
max-width: calc(100% - 10px - 152px);
|
max-width: calc(100% - 10px - 152px);
|
||||||
}
|
}
|
||||||
button .large {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
button .small {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@media screen and (width <= 440px) {
|
@media screen and (width <= 440px) {
|
||||||
#vm-search {
|
#vm-search {
|
||||||
max-width: calc(100% - 10px - 47px);
|
max-width: calc(100% - 10px - 47px);
|
||||||
}
|
}
|
||||||
button .large {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
button .small {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@ -49,10 +37,11 @@
|
|||||||
<h1>proxmox</h1>
|
<h1>proxmox</h1>
|
||||||
<label for="navtoggle">☰</label>
|
<label for="navtoggle">☰</label>
|
||||||
<input type="checkbox" id="navtoggle">
|
<input type="checkbox" id="navtoggle">
|
||||||
<nav>
|
<nav id="navigation">
|
||||||
<a href="index.html" aria-current="page">Instances</a>
|
<a href="index.html" aria-current="page">Instances</a>
|
||||||
<a href="account.html">Account</a>
|
<a href="account.html">Account</a>
|
||||||
<a href="settings.html">Settings</a>
|
<a href="settings.html">Settings</a>
|
||||||
|
<a id="admin-link" aria-disabled="true" class="none">Admin</a>
|
||||||
<a href="login.html">Logout</a>
|
<a href="login.html">Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
@ -72,27 +61,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="w3-row w3-hide-small" style="border-bottom: 1px solid;">
|
<div class="w3-row w3-hide-small" style="border-bottom: 1px solid;">
|
||||||
<div class="w3-col l1 m2">
|
<p class="w3-col l1 m2 w3-hide-small">ID</p>
|
||||||
<p>ID</p>
|
<p class="w3-col l2 m3 w3-hide-small">Name</p>
|
||||||
</div>
|
<p class="w3-col l1 m2 w3-hide-small">Type</p>
|
||||||
<div class="w3-col l2 m3">
|
<p class="w3-col l2 m3 w3-hide-small">Status</p>
|
||||||
<p>Name</p>
|
<p class="w3-col l2 w3-hide-medium w3-hide-small">Host Name</p>
|
||||||
</div>
|
<p class="w3-col l2 w3-hide-medium w3-hide-small">Host Status</p>
|
||||||
<div class="w3-col l1 m2">
|
<p class="w3-col l2 m2 w3-hide-small">Actions</p>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="instance-container"></div>
|
<div id="instance-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<h1>proxmox</h1>
|
<h1>proxmox</h1>
|
||||||
<label for="navtoggle">☰</label>
|
<label for="navtoggle">☰</label>
|
||||||
<input type="checkbox" id="navtoggle">
|
<input type="checkbox" id="navtoggle">
|
||||||
<nav>
|
<nav id="navigation">
|
||||||
<a href="login.html" aria-current="page">Login</a>
|
<a href="login.html" aria-current="page">Login</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
@ -131,7 +131,7 @@ function handlePasswordChangeForm () {
|
|||||||
`;
|
`;
|
||||||
const d = dialog("Change Password", body, async (result, form) => {
|
const d = dialog("Change Password", body, async (result, form) => {
|
||||||
if (result === "confirm") {
|
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) {
|
if (result.status !== 200) {
|
||||||
alert(result.error);
|
alert(result.error);
|
||||||
}
|
}
|
||||||
|
8
scripts/admin.js
Normal file
8
scripts/admin.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { setTitleAndHeader, setAppearance } from "./utils.js";
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", init);
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
setAppearance();
|
||||||
|
setTitleAndHeader();
|
||||||
|
}
|
@ -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";
|
import { alert } from "./dialog.js";
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", init);
|
window.addEventListener("DOMContentLoaded", init);
|
||||||
|
|
||||||
async function init () {
|
async function init () {
|
||||||
|
await deleteAllCookies();
|
||||||
setAppearance();
|
setAppearance();
|
||||||
setTitleAndHeader();
|
setTitleAndHeader();
|
||||||
await deleteAllCookies();
|
|
||||||
const formSubmitButton = document.querySelector("#submit");
|
const formSubmitButton = document.querySelector("#submit");
|
||||||
const realms = await requestPVE("/access/domains", "GET");
|
const realms = await requestPVE("/access/domains", "GET");
|
||||||
const realmSelect = document.querySelector("#realm");
|
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");
|
||||||
|
}
|
||||||
|
@ -161,11 +161,6 @@ export function getCookie (cname) {
|
|||||||
return "";
|
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) {
|
export async function requestPVE (path, method, body = null) {
|
||||||
const prms = new URLSearchParams(body);
|
const prms = new URLSearchParams(body);
|
||||||
const content = {
|
const content = {
|
||||||
@ -259,13 +254,18 @@ export function getURIData () {
|
|||||||
return Object.fromEntries(url.searchParams);
|
return Object.fromEntries(url.searchParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteAllCookies () {
|
export async function setTitleAndHeader () {
|
||||||
await requestAPI("/auth/ticket", "DELETE");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setTitleAndHeader () {
|
|
||||||
document.title = `${organization} - dashboard`;
|
document.title = `${organization} - dashboard`;
|
||||||
document.querySelector("h1").innerText = organization;
|
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 = {
|
const settingsDefault = {
|
||||||
|
@ -37,63 +37,61 @@
|
|||||||
<h1>proxmox</h1>
|
<h1>proxmox</h1>
|
||||||
<label for="navtoggle">☰</label>
|
<label for="navtoggle">☰</label>
|
||||||
<input type="checkbox" id="navtoggle">
|
<input type="checkbox" id="navtoggle">
|
||||||
<nav>
|
<nav id="navigation">
|
||||||
<a href="index.html">Instances</a>
|
<a href="index.html">Instances</a>
|
||||||
<a href="account.html">Account</a>
|
<a href="account.html">Account</a>
|
||||||
<a href="settings.html" aria-current="page">Settings</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>
|
<a href="login.html">Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<section>
|
<h2>Settings</h2>
|
||||||
<h2>Settings</h2>
|
<form id = "settings">
|
||||||
<form id = "settings">
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<h3>Synchronization Settings</h3>
|
||||||
<h3>Synchronization Settings</h3>
|
<fieldset>
|
||||||
<fieldset>
|
<legend>App Sync Method</legend>
|
||||||
<legend>App Sync Method</legend>
|
<label><input class="w3-radio" type="radio" id="sync-always" name="sync-scheme" value="always" required>Always Sync</label>
|
||||||
<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>
|
||||||
<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>
|
||||||
<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>
|
||||||
<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>
|
||||||
<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>
|
||||||
<p>App will react to changes and synchronize when changes are made. Low resource usage.</p>
|
</fieldset>
|
||||||
</fieldset>
|
<fieldset>
|
||||||
<fieldset>
|
<legend>App Sync Frequency</legend>
|
||||||
<legend>App Sync Frequency</legend>
|
<div class="input-grid" style="grid-template-columns: auto auto 1fr;">
|
||||||
<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>
|
||||||
<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>
|
||||||
</div>
|
</fieldset>
|
||||||
</fieldset>
|
</section>
|
||||||
</div>
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<h3>Search Settings</h3>
|
||||||
<h3>Search Settings</h3>
|
<fieldset>
|
||||||
<fieldset>
|
<legend>Instance Search Criteria</legend>
|
||||||
<legend>Instance Search Criteria</legend>
|
<label><input class="w3-radio" type="radio" id="search-exact" name="search-criteria" value="exact" required>Exact Match</label>
|
||||||
<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>
|
||||||
<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>
|
||||||
<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>
|
||||||
<p>Sorts by best matching to worst matching.</p>
|
</fieldset>
|
||||||
</fieldset>
|
</section>
|
||||||
</div>
|
<section class="w3-card w3-padding">
|
||||||
<div class="w3-card w3-padding">
|
<h3>Appearance</h3>
|
||||||
<h3>Appearance</h3>
|
<fieldset>
|
||||||
<fieldset>
|
<legend>Default Theme</legend>
|
||||||
<label>
|
<label>Theme<select class="w3-select w3-border" id="appearance-theme" name="appearance-theme" style="width: fit-content; padding-right: 24px;">
|
||||||
Theme
|
<option value="auto">Auto</option>
|
||||||
<select class="w3-select w3-border" id="appearance-theme" name="appearance-theme" style="width: fit-content; padding-right: 24px;">
|
<option value="dark">Dark</option>
|
||||||
<option value="auto">Auto</option>
|
<option value="light">Light</option>
|
||||||
<option value="dark">Dark</option>
|
</select>
|
||||||
<option value="light">Light</option>
|
</label>
|
||||||
</select>
|
</fieldset>
|
||||||
</label>
|
</section>
|
||||||
</fieldset>
|
<div class="w3-container w3-center" id="form-actions">
|
||||||
</div>
|
<button class="w3-button w3-margin" id="save" type="submit">SAVE</button>
|
||||||
<div class="w3-container w3-center" id="form-actions">
|
</div>
|
||||||
<button class="w3-button w3-margin" id="save" type="submit">SAVE</button>
|
</form>
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user