Compare commits
6 Commits
196cf900cc
...
v2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 159b08a7ca | |||
| 33db3c15b8 | |||
| 526b2a0ff0 | |||
| ff1f618ad7 | |||
| 47415fbdd9 | |||
| 3646bc1272 |
@@ -1,20 +1,25 @@
|
|||||||
.PHONY: build test clean wfa-js
|
.PHONY: build test clean wfa-js
|
||||||
|
|
||||||
build: clean wfa-js
|
build: clean build-wfa-js
|
||||||
@echo "======================== Building Binary ======================="
|
@echo "======================== Building Binary ======================="
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
# resolve symbolic links in web by copying it into dist/web/
|
# resolve symbolic links in web by copying it into dist/web/
|
||||||
cp -rL web/ dist/web/
|
cp -rL web/ dist/web/
|
||||||
CGO_ENABLED=0 go build -tags release -ldflags="-s -w" -v -o dist/ .
|
CGO_ENABLED=0 go build -tags release -ldflags="-s -w" -v -o dist/ .
|
||||||
|
|
||||||
wfa-js:
|
build-wfa-js:
|
||||||
$(MAKE) -C WFA-JS
|
$(MAKE) -C WFA-JS
|
||||||
cp -f WFA-JS/dist/* web/modules
|
cp -f WFA-JS/dist/* web/modules
|
||||||
|
|
||||||
test: clean
|
test: clean test-wfa-js
|
||||||
go run .
|
|
||||||
|
|
||||||
clean:
|
test-wfa-js:
|
||||||
|
$(MAKE) test -C WFA-JS
|
||||||
|
|
||||||
|
clean: clean-wfa-js
|
||||||
@echo "======================== Cleaning Project ======================"
|
@echo "======================== Cleaning Project ======================"
|
||||||
go clean
|
go clean
|
||||||
rm -rf dist/*
|
rm -rf dist/*
|
||||||
|
|
||||||
|
clean-wfa-js:
|
||||||
|
$(MAKE) clean -C WFA-JS
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ProxmoxAAS Dashboard provides users of a proxmox based compute on demand service
|
|||||||
|
|
||||||
## ProxmoxAAS System Installation Overview
|
## ProxmoxAAS System Installation Overview
|
||||||
|
|
||||||
The ProxmoxAAS project is large and is split into multiple components. There are three required components, the Dashboard, API, and Fabric. There is also an optional LDAP component for organizations that want to use LDAP as their authentication backend. The instalation order should start with the Dashboard and then proceed to the other backend components. This will require some foresight into the setup process.
|
The ProxmoxAAS project is large and is split into multiple components. There are four required components, the Dashboard, API, Fabric, and access-manager-api. The instalation order should start with the Dashboard and then proceed to the other backend components. This will require some foresight into the setup process.
|
||||||
|
|
||||||
The supported setup is to use a reverse proxy to serve both the original Proxmox web interface and ProxmoxAAS components. It is possible other setups can work. Rather than provide specific steps to duplicate a certain setup, the steps included are intended as a guideline of steps required for proper function in most setups. Consequently, the examples provided are only to highlight key settings and do not represent complete working configurations. The instructions also assume you have your own domain name which will substitute `domain.net` in some of the configs.
|
The supported setup is to use a reverse proxy to serve both the original Proxmox web interface and ProxmoxAAS components. It is possible other setups can work. Rather than provide specific steps to duplicate a certain setup, the steps included are intended as a guideline of steps required for proper function in most setups. Consequently, the examples provided are only to highlight key settings and do not represent complete working configurations. The instructions also assume you have your own domain name which will substitute `domain.net` in some of the configs.
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ We will assume different hosts for each component which are accessible by unique
|
|||||||
| ProxmoxAAS-Dashboard | dashboard.local | paas.domain.net |
|
| ProxmoxAAS-Dashboard | dashboard.local | paas.domain.net |
|
||||||
| ProxmoxAAS-API | api.local | paas.domain.net/api/ |
|
| ProxmoxAAS-API | api.local | paas.domain.net/api/ |
|
||||||
| ProxmoxAAS-Fabric | fabric.local | N/A |
|
| ProxmoxAAS-Fabric | fabric.local | N/A |
|
||||||
| ProxmoxAAS-LDAP | ldap.local | N/A|
|
| access-manager-api | access.local | N/A|
|
||||||
|
|
||||||
## Prerequisites - Dashboard
|
## Prerequisites - Dashboard
|
||||||
- Proxmox VE Cluster (v7.0+)
|
- Proxmox VE Cluster (v7.0+)
|
||||||
@@ -36,11 +36,11 @@ We will assume different hosts for each component which are accessible by unique
|
|||||||
1. Initialize any host, which will be the `ProxmoxAAS-Dashboard` component host
|
1. Initialize any host, which will be the `ProxmoxAAS-Dashboard` component host
|
||||||
2. Download `proxmoxaas-dashboard` binary and `template.config.json` file from [releases](https://git.tronnet.net/tronnet/ProxmoxAAS-LDAP/releases)
|
2. Download `proxmoxaas-dashboard` binary and `template.config.json` file from [releases](https://git.tronnet.net/tronnet/ProxmoxAAS-LDAP/releases)
|
||||||
Rename `template.config.json` to `config.json` and modify:
|
Rename `template.config.json` to `config.json` and modify:
|
||||||
- listenPort: port for PAAS-Dashboard to bind and listen on
|
- `listenPort`: port for PAAS-Dashboard to bind and listen on
|
||||||
- organization: name of your org which is displayed on the top left corner
|
- `organization`: name of your org which is displayed on the top left corner
|
||||||
- dashurl: url for the dashboard, ie. `https://paas.domain.net`
|
- `dashurl`: url for the dashboard, ie. `https://paas.domain.net`
|
||||||
- apiurl: url for PAAS-API, ie. `https://paas.domain.net/api`
|
- `apiurl`: url for PAAS-API, ie. `https://paas.domain.net/api`
|
||||||
- pveurl: url for the Proxmox endpoint, ie. `https://pve.domain.net`
|
- `pveurl`: url for the Proxmox endpoint, ie. `https://pve.domain.net`
|
||||||
3. Execute the binary or additionally download `proxmoxaas-dashboard.service` from [releases](https://git.tronnet.net/tronnet/ProxmoxAAS-LDAP/releases) to run using systemd
|
3. Execute the binary or additionally download `proxmoxaas-dashboard.service` from [releases](https://git.tronnet.net/tronnet/ProxmoxAAS-LDAP/releases) to run using systemd
|
||||||
|
|
||||||
After this step, the Dashboard should be available on the `ProxmoxAAS-Dashboard` host at the configured `listenPort`
|
After this step, the Dashboard should be available on the `ProxmoxAAS-Dashboard` host at the configured `listenPort`
|
||||||
@@ -53,9 +53,9 @@ To install the API component, go to [ProxmoxAAS-API](https://git.tronnet.net/tro
|
|||||||
|
|
||||||
To install the Fabric component, go to [ProxmoxAAS-Fabric](https://git.tronnet.net/tronnet/ProxmoxAAS-Fabric). This is required for the app to function. The Fabric installation will also have steps for setting up the reverse proxy server.
|
To install the Fabric component, go to [ProxmoxAAS-Fabric](https://git.tronnet.net/tronnet/ProxmoxAAS-Fabric). This is required for the app to function. The Fabric installation will also have steps for setting up the reverse proxy server.
|
||||||
|
|
||||||
## Installation - LDAP
|
## Installation - access-manager-api
|
||||||
|
|
||||||
To install the LDAP component, go to [ProxmoxAAS-LDAP](https://git.tronnet.net/tronnet/ProxmoxAAS-LDAP).This is an optional component which adds a lightweight REST API server ontop of a simplified LDAP environment. It is only used by the API as a potential authentication backend.
|
To install the access-manager-api component, go to [access-manager-api](https://git.tronnet.net/tronnet/access-manager-api). This is required for the app to function. The access-manager-api installation will also have steps for setting up the reverse proxy server.
|
||||||
|
|
||||||
## Installation - Reverse Proxy
|
## Installation - Reverse Proxy
|
||||||
1. Configure nginx or preferred reverse proxy to reverse proxy the dashboard. The configuration should include at least the following, ensuring that the configured ports are adjusted appropriately:
|
1. Configure nginx or preferred reverse proxy to reverse proxy the dashboard. The configuration should include at least the following, ensuring that the configured ports are adjusted appropriately:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module proxmoxaas-dashboard
|
module proxmoxaas-dashboard
|
||||||
|
|
||||||
go 1.26.4
|
go 1.26.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gerow/go-color v0.0.0-20140219113758-125d37f527f1
|
github.com/gerow/go-color v0.0.0-20140219113758-125d37f527f1
|
||||||
|
|||||||
+1
-2
@@ -4,8 +4,7 @@
|
|||||||
"description": "Front-end for ProxmoxAAS",
|
"description": "Front-end for ProxmoxAAS",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "html-validate --config dev_config/.htmlvalidate.json web/html/*; stylelint --config dev_config/.stylelintrc.json --formatter verbose --fix web/css/*.css; DEBUG=eslint:cli-engine eslint --config dev_config/eslint.config.mjs --fix web/scripts/",
|
"lint": "html-validate --config dev_config/.htmlvalidate.json web/html/*; stylelint --config dev_config/.stylelintrc.json --formatter verbose --fix web/css/*.css; DEBUG=eslint:cli-engine eslint --config dev_config/eslint.config.mjs --fix web/scripts/"
|
||||||
"update-modules": "rm -rf web/modules/wfa.js web/modules/wfa.wasm; curl https://git.tronnet.net/alu/WFA-JS/releases/download/latest/wfa.js -o web/modules/wfa.js; curl https://git.tronnet.net/alu/WFA-JS/releases/download/latest/wfa.wasm -o web/modules/wfa.wasm"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.5",
|
"@eslint/eslintrc": "^3.3.5",
|
||||||
|
|||||||
+1
-1
Submodule proxmoxaas-common-lib updated: 24904dde66...05519694e1
@@ -20,6 +20,12 @@
|
|||||||
p:last-child {
|
p:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
#save.disabled {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#save.enabled {
|
||||||
|
display: unset;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -70,7 +76,7 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</section>
|
</section>
|
||||||
<div class="w3-container w3-center" id="form-actions">
|
<div class="w3-container w3-center" id="form-actions">
|
||||||
<button class="w3-button w3-margin" id="save" type="submit">SAVE</button>
|
<button class="w3-button w3-margin disabled" id="save" type="submit">SAVE</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { getSyncSettings, requestAPI } from "./utils.js";
|
import { getSetting, requestAPI } from "./utils.js";
|
||||||
|
|
||||||
export async function setupClientSync (callback) {
|
export async function setupClientSync (callback) {
|
||||||
const { scheme, rate } = getSyncSettings();
|
const scheme = getSetting("sync-scheme");
|
||||||
|
const rate = getSetting("sync-rate");
|
||||||
if (scheme === "never") {
|
if (scheme === "never") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { requestPVE, requestAPI, setAppearance, getSearchSettings, requestDash, setIconSrc, setIconAlt } from "./utils.js";
|
import { requestPVE, requestAPI, setAppearance, getSetting, requestDash, setIconSrc, setIconAlt } from "./utils.js";
|
||||||
import { alert, dialog, error } from "./dialog.js";
|
import { alert, dialog, error } from "./dialog.js";
|
||||||
import { setupClientSync } from "./clientsync.js";
|
import { setupClientSync } from "./clientsync.js";
|
||||||
import wfaInit from "../modules/wfa.js";
|
import wfaInit from "../modules/wfa.js";
|
||||||
@@ -243,7 +243,7 @@ function initInstances () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sortInstances () {
|
function sortInstances () {
|
||||||
const searchCriteria = getSearchSettings();
|
const searchCriteria = getSetting("search-criteria");
|
||||||
const searchQuery = document.querySelector("#search").value || null;
|
const searchQuery = document.querySelector("#search").value || null;
|
||||||
let criteria;
|
let criteria;
|
||||||
if (!searchQuery) {
|
if (!searchQuery) {
|
||||||
|
|||||||
+45
-19
@@ -1,36 +1,62 @@
|
|||||||
import { setAppearance, getSyncSettings, getSearchSettings, getThemeSettings, setSyncSettings, setSearchSettings, setThemeSettings } from "./utils.js";
|
import { setAppearance, getSetting, setSetting } from "./utils.js";
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", init);
|
window.addEventListener("DOMContentLoaded", init);
|
||||||
|
|
||||||
function init () {
|
function init () {
|
||||||
setAppearance();
|
setAppearance();
|
||||||
|
|
||||||
const { scheme, rate } = getSyncSettings();
|
document.querySelectorAll("[id^=sync-]").forEach((v) => {
|
||||||
if (scheme) {
|
v.addEventListener("change", handleSettingsChange);
|
||||||
document.querySelector(`#sync-${scheme}`).checked = true;
|
});
|
||||||
}
|
document.querySelector(`#sync-${getSetting("sync-scheme")}`).checked = true;
|
||||||
if (rate) {
|
document.querySelector("#sync-rate").value = getSetting("sync-rate");
|
||||||
document.querySelector("#sync-rate").value = rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
const search = getSearchSettings();
|
document.querySelectorAll("[id^=search-]").forEach((v) => {
|
||||||
if (search) {
|
v.addEventListener("change", handleSettingsChange);
|
||||||
document.querySelector(`#search-${search}`).checked = true;
|
});
|
||||||
}
|
document.querySelector(`#search-${getSetting("search-criteria")}`).checked = true;
|
||||||
|
|
||||||
const theme = getThemeSettings();
|
document.querySelector("#appearance-theme").addEventListener("change", handleSettingsChange);
|
||||||
if (theme) {
|
document.querySelector("#appearance-theme").value = getSetting("appearance-theme");
|
||||||
document.querySelector("#appearance-theme").value = theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector("#settings").addEventListener("submit", handleSaveSettings, false);
|
document.querySelector("#settings").addEventListener("submit", handleSaveSettings, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSettingsChange (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const form = new FormData(document.querySelector("#settings"));
|
||||||
|
const saveBtn = document.querySelector("#save");
|
||||||
|
if (getSetting("sync-scheme") !== form.get("sync-scheme")) {
|
||||||
|
saveBtn.classList.remove("disabled");
|
||||||
|
saveBtn.classList.add("enabled");
|
||||||
|
}
|
||||||
|
else if (getSetting("sync-rate") !== Number(form.get("sync-rate"))) {
|
||||||
|
saveBtn.classList.remove("disabled");
|
||||||
|
saveBtn.classList.add("enabled");
|
||||||
|
}
|
||||||
|
else if (getSetting("search-criteria") !== form.get("search-criteria")) {
|
||||||
|
saveBtn.classList.remove("disabled");
|
||||||
|
saveBtn.classList.add("enabled");
|
||||||
|
}
|
||||||
|
else if (getSetting("appearance-theme") !== form.get("appearance-theme")) {
|
||||||
|
saveBtn.classList.remove("disabled");
|
||||||
|
saveBtn.classList.add("enabled");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
saveBtn.classList.remove("enabled");
|
||||||
|
saveBtn.classList.add("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleSaveSettings (event) {
|
function handleSaveSettings (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const form = new FormData(document.querySelector("#settings"));
|
const form = new FormData(document.querySelector("#settings"));
|
||||||
setSyncSettings(form.get("sync-scheme"), form.get("sync-rate"));
|
const saveBtn = document.querySelector("#save");
|
||||||
setSearchSettings(form.get("search-criteria"));
|
setSetting("sync-scheme", form.get("sync-scheme"));
|
||||||
setThemeSettings(form.get("appearance-theme"));
|
setSetting("sync-rate", Number(form.get("sync-rate")));
|
||||||
|
setSetting("search-criteria", form.get("search-criteria"));
|
||||||
|
setSetting("appearance-theme", form.get("appearance-theme"));
|
||||||
|
saveBtn.classList.remove("enabled");
|
||||||
|
saveBtn.classList.add("disabled");
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-46
@@ -125,60 +125,30 @@ export function getURIData () {
|
|||||||
return Object.fromEntries(url.searchParams);
|
return Object.fromEntries(url.searchParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsDefault = {
|
const settings = {
|
||||||
"sync-scheme": "always",
|
"sync-scheme": {"type": String, "default": "always"},
|
||||||
"sync-rate": 5,
|
"sync-rate": {"type": Number, "default": 5},
|
||||||
"search-criteria": "fuzzy",
|
"search-criteria": {"type": String, "default": "fuzzy"},
|
||||||
"appearance-theme": "auto"
|
"appearance-theme": {"type": String, "default": "auto"}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getSyncSettings () {
|
export function getSetting (key) {
|
||||||
let scheme = localStorage.getItem("sync-scheme");
|
const meta = settings[key];
|
||||||
let rate = Number(localStorage.getItem("sync-rate"));
|
let value = localStorage.getItem(key);
|
||||||
if (!scheme) {
|
if (value === null || meta === null) {
|
||||||
scheme = settingsDefault["sync-scheme"];
|
value = meta.default;
|
||||||
localStorage.setItem("sync-scheme", scheme);
|
localStorage.setItem(key, meta.default);
|
||||||
}
|
|
||||||
if (!rate) {
|
|
||||||
rate = settingsDefault["sync-rate"];
|
|
||||||
localStorage.setItem("sync-rate", rate);
|
|
||||||
}
|
|
||||||
return { scheme, rate };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSearchSettings () {
|
return meta.type(value);
|
||||||
let searchCriteria = localStorage.getItem("search-criteria");
|
|
||||||
if (!searchCriteria) {
|
|
||||||
searchCriteria = settingsDefault["search-criteria"];
|
|
||||||
localStorage.setItem("search-criteria", searchCriteria);
|
|
||||||
}
|
|
||||||
return searchCriteria;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getThemeSettings () {
|
export function setSetting (key, value) {
|
||||||
let theme = localStorage.getItem("appearance-theme");
|
localStorage.setItem(key, value);
|
||||||
if (!theme) {
|
|
||||||
theme = settingsDefault["appearance-theme"];
|
|
||||||
localStorage.setItem("appearance-theme", theme);
|
|
||||||
}
|
|
||||||
return theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setSyncSettings (scheme, rate) {
|
|
||||||
localStorage.setItem("sync-scheme", scheme);
|
|
||||||
localStorage.setItem("sync-rate", rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setSearchSettings (criteria) {
|
|
||||||
localStorage.setItem("search-criteria", criteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setThemeSettings (theme) {
|
|
||||||
localStorage.setItem("appearance-theme", theme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAppearance () {
|
export function setAppearance () {
|
||||||
const theme = getThemeSettings();
|
const theme = getSetting("appearance-theme");
|
||||||
if (theme === "auto") {
|
if (theme === "auto") {
|
||||||
document.querySelector(":root").classList.remove("dark-theme", "light-theme");
|
document.querySelector(":root").classList.remove("dark-theme", "light-theme");
|
||||||
}
|
}
|
||||||
@@ -192,7 +162,6 @@ export function setAppearance () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes href is path to svg, and id to grab is #symb
|
|
||||||
export function setIconSrc (icon, path) {
|
export function setIconSrc (icon, path) {
|
||||||
icon.setAttribute("src", path);
|
icon.setAttribute("src", path);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user