simplify addResourceLine interface,
add update modules script to npm scripts, add value to DraggableItem
This commit is contained in:
parent
9b3d9767e1
commit
68fafc1e37
@ -10,7 +10,7 @@
|
|||||||
<link rel="stylesheet" href="css/style.css">
|
<link rel="stylesheet" href="css/style.css">
|
||||||
<link rel="stylesheet" href="css/nav.css">
|
<link rel="stylesheet" href="css/nav.css">
|
||||||
<link rel="stylesheet" href="css/form.css">
|
<link rel="stylesheet" href="css/form.css">
|
||||||
<script src="scripts/config.js" type="module"></script>
|
<script src="scripts/instance.js" type="module"></script>
|
||||||
<script src="scripts/draggable.js" type="module"></script>
|
<script src="scripts/draggable.js" type="module"></script>
|
||||||
<script src="modules/Sortable.min.js"></script>
|
<script src="modules/Sortable.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
@ -4,7 +4,8 @@
|
|||||||
"description": "Front-end for ProxmoxAAS",
|
"description": "Front-end for ProxmoxAAS",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "html-validator --continue; stylelint --formatter verbose --fix css/*.css; DEBUG=eslint:cli-engine eslint --fix scripts/"
|
"lint": "html-validator --continue; stylelint --formatter verbose --fix css/*.css; DEBUG=eslint:cli-engine eslint --fix scripts/",
|
||||||
|
"update-modules": "rm -rf modules/wfa.js modules/wfa.wasm; curl https://git.tronnet.net/alu/WFA-JS/releases/download/latest/wfa.js -o modules/wfa.js; curl https://git.tronnet.net/alu/WFA-JS/releases/download/latest/wfa.wasm -o modules/wfa.wasm"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8.43.0",
|
"eslint": "^8.43.0",
|
||||||
|
@ -74,6 +74,7 @@ class DraggableContainer extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DraggableItem extends HTMLElement {
|
class DraggableItem extends HTMLElement {
|
||||||
|
#value = null;
|
||||||
uuid = null;
|
uuid = null;
|
||||||
constructor () {
|
constructor () {
|
||||||
super();
|
super();
|
||||||
@ -103,6 +104,14 @@ class DraggableItem extends HTMLElement {
|
|||||||
set innerHTML (innerHTML) {
|
set innerHTML (innerHTML) {
|
||||||
this.content.innerHTML = innerHTML;
|
this.content.innerHTML = innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get value () {
|
||||||
|
return this.#value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value (value) {
|
||||||
|
this.#value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("draggable-container", DraggableContainer);
|
customElements.define("draggable-container", DraggableContainer);
|
||||||
|
@ -105,12 +105,12 @@ async function populateResources () {
|
|||||||
return a.localeCompare(b);
|
return a.localeCompare(b);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addResourceLine(resourcesConfigPage, field, "cpu", { value: config.data.cpu, options });
|
addResourceLine(resourcesConfigPage.cpu, field, { value: config.data.cpu, options });
|
||||||
}
|
}
|
||||||
addResourceLine(resourcesConfigPage, field, "cores", { value: config.data.cores, min: 1, max: 8192 });
|
addResourceLine(resourcesConfigPage.cores, field, { value: config.data.cores, min: 1, max: 8192 });
|
||||||
addResourceLine(resourcesConfigPage, field, "memory", { value: config.data.memory, min: 16, step: 1 });
|
addResourceLine(resourcesConfigPage.memory, field, { value: config.data.memory, min: 16, step: 1 });
|
||||||
if (type === "lxc") {
|
if (type === "lxc") {
|
||||||
addResourceLine(resourcesConfigPage, field, "swap", { value: config.data.swap, min: 0, step: 1 });
|
addResourceLine(resourcesConfigPage.swap, field, { value: config.data.swap, min: 0, step: 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
243
scripts/user.js
243
scripts/user.js
@ -10,36 +10,53 @@ let allNodes;
|
|||||||
let allPools;
|
let allPools;
|
||||||
let clusterResourceConfig;
|
let clusterResourceConfig;
|
||||||
|
|
||||||
|
const resourceRulesLines = {}; // list of all resource rules fieldsets on the page
|
||||||
|
|
||||||
const resourceInputTypes = { // input types for each resource for config page
|
const resourceInputTypes = { // input types for each resource for config page
|
||||||
cpu: {
|
cpu: {
|
||||||
|
type: "list",
|
||||||
element: "interactive-list",
|
element: "interactive-list",
|
||||||
align: "start"
|
align: "start"
|
||||||
},
|
},
|
||||||
cores: {
|
cores: {
|
||||||
|
type: "numeric",
|
||||||
element: "input",
|
element: "input",
|
||||||
attributes: {
|
attributes: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
memory: {
|
memory: {
|
||||||
|
type: "numeric",
|
||||||
element: "input",
|
element: "input",
|
||||||
attributes: {
|
attributes: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
swap: {
|
swap: {
|
||||||
|
type: "numeric",
|
||||||
element: "input",
|
element: "input",
|
||||||
attributes: {
|
attributes: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
network: {
|
network: {
|
||||||
|
type: "numeric",
|
||||||
element: "input",
|
element: "input",
|
||||||
attributes: {
|
attributes: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
storage: {
|
||||||
|
type: "numeric",
|
||||||
|
icon: "images/resources/disk.svg",
|
||||||
|
element: "input",
|
||||||
|
unitText: "B",
|
||||||
|
attributes: {
|
||||||
|
type: "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
pci: {
|
pci: {
|
||||||
|
type: "list",
|
||||||
element: "interactive-list",
|
element: "interactive-list",
|
||||||
align: "start"
|
align: "start"
|
||||||
}
|
}
|
||||||
@ -91,10 +108,15 @@ class InteractiveList extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get value () {
|
get value () {
|
||||||
|
const ret = [];
|
||||||
|
for (const elem of this.container.childNodes) {
|
||||||
|
ret.push(elem.value);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
set value (value) {
|
set value (value) {
|
||||||
|
this.container.innerHTML = "";
|
||||||
for (const item of value) {
|
for (const item of value) {
|
||||||
this.#addItem(item);
|
this.#addItem(item);
|
||||||
}
|
}
|
||||||
@ -151,29 +173,57 @@ class InteractiveListMatchItem extends HTMLElement {
|
|||||||
<link rel="stylesheet" href="modules/w3.css">
|
<link rel="stylesheet" href="modules/w3.css">
|
||||||
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/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/style.css">
|
||||||
|
<link rel="stylesheet" href="css/form.css">
|
||||||
<style>
|
<style>
|
||||||
#container {
|
#container {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
display: grid;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
svg {
|
svg {
|
||||||
margin-top: calc(-0.5em + 0.5lh);
|
margin-top: calc(-0.5em + 0.5lh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (width >= 993px) {
|
||||||
|
#container {
|
||||||
|
grid-template-columns: 15% 1fr 15% auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (width <= 993px) and (width >= 601px) {
|
||||||
|
#container {
|
||||||
|
grid-template-columns: 1fr 15% auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (width <= 601px) {
|
||||||
|
#container {
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="container" class="w3-row">
|
<div id="container">
|
||||||
<p class="w3-col l2 w3-hide-medium w3-hide-small"><span id="name"></span></p>
|
<p class="w3-hide-medium w3-hide-small" id="name"></p>
|
||||||
<p class="w3-col l7 m9 s11">match="<span id="match"></span>"</p>
|
<p id="match"></p>
|
||||||
<p class="w3-col l2 m2 w3-hide-small">max=<span id="max"></span></p>
|
<p class="w3-hide-small" id="max"></p>
|
||||||
<svg id="delete-btn" class="w3-col l1 m1 s1 clickable" tabindex="0" role="button"><use></use></svg>
|
<div>
|
||||||
|
<svg id="config-btn" class="clickable" tabindex="0" role="button"><use></use></svg>
|
||||||
|
<svg id="delete-btn" class="clickable" tabindex="0" role="button"><use></use></svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
this.#nameElem = this.shadowRoot.querySelector("#name");
|
this.#nameElem = this.shadowRoot.querySelector("#name");
|
||||||
this.#matchElem = this.shadowRoot.querySelector("#match");
|
this.#matchElem = this.shadowRoot.querySelector("#match");
|
||||||
this.#maxElem = this.shadowRoot.querySelector("#max");
|
this.#maxElem = this.shadowRoot.querySelector("#max");
|
||||||
|
|
||||||
|
this.configBtn = this.shadowRoot.querySelector("#config-btn");
|
||||||
|
this.configBtn.onclick = this.#handleConfig.bind(this);
|
||||||
|
setSVGSrc(this.configBtn, "images/common/config.svg");
|
||||||
|
setSVGAlt(this.configBtn, "Config Item");
|
||||||
|
|
||||||
this.deleteBtn = this.shadowRoot.querySelector("#delete-btn");
|
this.deleteBtn = this.shadowRoot.querySelector("#delete-btn");
|
||||||
this.deleteBtn.onclick = this.#handleDelete.bind(this);
|
this.deleteBtn.onclick = this.#handleDelete.bind(this);
|
||||||
setSVGSrc(this.deleteBtn, "images/actions/delete-active.svg");
|
setSVGSrc(this.deleteBtn, "images/actions/delete-active.svg");
|
||||||
@ -182,8 +232,8 @@ class InteractiveListMatchItem extends HTMLElement {
|
|||||||
|
|
||||||
#update () {
|
#update () {
|
||||||
this.#nameElem.innerText = this.#name;
|
this.#nameElem.innerText = this.#name;
|
||||||
this.#matchElem.innerText = this.#match;
|
this.#matchElem.innerText = `match="${this.#match}"`;
|
||||||
this.#maxElem.innerText = this.#max;
|
this.#maxElem.innerText = `max=${this.#max}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name () {
|
get name () {
|
||||||
@ -213,6 +263,51 @@ class InteractiveListMatchItem extends HTMLElement {
|
|||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get value () {
|
||||||
|
return {
|
||||||
|
name: this.#name,
|
||||||
|
match: this.#match,
|
||||||
|
max: this.#max
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
set value (value) {
|
||||||
|
this.#name = value.name;
|
||||||
|
this.#match = value.match;
|
||||||
|
this.#max = value.max;
|
||||||
|
this.#update();
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleConfig () {
|
||||||
|
const header = `Edit ${this.#name} Rule`;
|
||||||
|
|
||||||
|
const body = `
|
||||||
|
<form method="dialog" class="input-grid" style="grid-template-columns: auto 1fr;" id="form">
|
||||||
|
<label for="name">Rule Name</label>
|
||||||
|
<input class="w3-input w3-border" name="name" id="name" type="text" required>
|
||||||
|
<label for="match">Matching Pattern</label>
|
||||||
|
<input class="w3-input w3-border" name="match" id="match" type="text" required>
|
||||||
|
<label for="max">Max Resource</label>
|
||||||
|
<input class="w3-input w3-border" name="max" id="max" type="number" required>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const d = dialog(header, body, async (result, form) => {
|
||||||
|
if (result === "confirm") {
|
||||||
|
const newItem = {
|
||||||
|
name: form.get("name"),
|
||||||
|
match: form.get("match"),
|
||||||
|
max: form.get("max")
|
||||||
|
};
|
||||||
|
this.value = newItem;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
d.querySelector("#name").value = this.#name;
|
||||||
|
d.querySelector("#match").value = this.#match;
|
||||||
|
d.querySelector("#max").value = this.#max;
|
||||||
|
}
|
||||||
|
|
||||||
#handleDelete () {
|
#handleDelete () {
|
||||||
const header = `Delete ${this.name}`;
|
const header = `Delete ${this.name}`;
|
||||||
const body = `<p>Are you sure you want to <strong>delete</strong> ${this.name}</p>`;
|
const body = `<p>Are you sure you want to <strong>delete</strong> ${this.name}</p>`;
|
||||||
@ -269,7 +364,7 @@ async function populateGroups () {
|
|||||||
for (const groupName of Object.keys(allGroups)) {
|
for (const groupName of Object.keys(allGroups)) {
|
||||||
const group = allGroups[groupName];
|
const group = allGroups[groupName];
|
||||||
const item = document.createElement("draggable-item");
|
const item = document.createElement("draggable-item");
|
||||||
item.data = group;
|
item.value = group;
|
||||||
item.innerHTML = `
|
item.innerHTML = `
|
||||||
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
||||||
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
||||||
@ -291,30 +386,48 @@ async function populateResources () {
|
|||||||
const field = document.querySelector("#resources");
|
const field = document.querySelector("#resources");
|
||||||
for (const resourceName of Object.keys(userData.resources)) {
|
for (const resourceName of Object.keys(userData.resources)) {
|
||||||
const resource = userData.resources[resourceName];
|
const resource = userData.resources[resourceName];
|
||||||
if (resourcesConfigPage[resourceName]) {
|
let resourceLine;
|
||||||
const resourceConfig = resourcesConfigPage[resourceName];
|
let resourceConfig;
|
||||||
let resourceLine;
|
|
||||||
|
|
||||||
if (resourceName === "cpu" || resourceName === "pci") {
|
if (resourcesConfigPage[resourceName]) {
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, resourceName, { value: resource.global }, "(Global)");
|
resourceConfig = resourcesConfigPage[resourceName];
|
||||||
|
resourceConfig.id = `${resourceName}-global`;
|
||||||
|
|
||||||
|
if (resourceConfig.type === "list") {
|
||||||
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.global }, "(Global)");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, resourceName, { value: resource.global.max }, "(Global)");
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.global.max }, "(Global)");
|
||||||
}
|
}
|
||||||
|
|
||||||
postPopulateResourceLine(field, resourceName, "global", resourceConfig, resourceLine);
|
postPopulateResourceLine(field, resourceName, "global", resourceConfig, resourceLine);
|
||||||
|
|
||||||
for (const nodeSpecificName of Object.keys(resource.nodes)) { // for each node specific, add a line with the node name as a prefix
|
for (const nodeSpecificName of Object.keys(resource.nodes)) { // for each node specific, add a line with the node name as a prefix
|
||||||
if (resourceName === "cpu" || resourceName === "pci") {
|
resourceConfig.id = `${resourceName}-${nodeSpecificName}`;
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, resourceName, { value: resource.nodes[nodeSpecificName] }, `(${nodeSpecificName})`);
|
if (resourceConfig.type === "list") {
|
||||||
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.nodes[nodeSpecificName] }, `(${nodeSpecificName})`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, resourceName, { value: resource.nodes[nodeSpecificName].max }, `(${nodeSpecificName})`);
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.nodes[nodeSpecificName].max }, `(${nodeSpecificName})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
postPopulateResourceLine(field, resourceName, nodeSpecificName, resourceConfig, resourceLine);
|
postPopulateResourceLine(field, resourceName, nodeSpecificName, resourceConfig, resourceLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
resourceConfig = resourcesConfigPage.storage;
|
||||||
|
resourceConfig.id = `${resourceName}-global`;
|
||||||
|
resourceConfig.name = resourceName;
|
||||||
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.global.max }, "(Global)");
|
||||||
|
|
||||||
|
postPopulateResourceLine(field, resourceName, "global", resourceConfig, resourceLine);
|
||||||
|
|
||||||
|
for (const nodeSpecificName of Object.keys(resource.nodes)) { // for each node specific, add a line with the node name as a prefix
|
||||||
|
resourceConfig.id = `${resourceName}-${nodeSpecificName}`;
|
||||||
|
resourceLine = addResourceLine(resourceConfig, field, { value: resource.nodes[nodeSpecificName].max }, `(${nodeSpecificName})`);
|
||||||
|
postPopulateResourceLine(field, resourceName, nodeSpecificName, resourceConfig, resourceLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
document.querySelector("#resource-add").addEventListener("click", handleResourceAdd);
|
document.querySelector("#resource-add").addEventListener("click", handleResourceAdd);
|
||||||
}
|
}
|
||||||
@ -338,6 +451,9 @@ function postPopulateResourceLine (field, resourceName, resourceScope, resourceC
|
|||||||
|
|
||||||
resourceLine.resourceName = resourceName;
|
resourceLine.resourceName = resourceName;
|
||||||
resourceLine.resourceScope = resourceScope;
|
resourceLine.resourceScope = resourceScope;
|
||||||
|
resourceLine.resourceType = resourceConfig.type;
|
||||||
|
|
||||||
|
resourceRulesLines[resourceLine.element.id] = resourceLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleResourceAdd () {
|
async function handleResourceAdd () {
|
||||||
@ -351,7 +467,7 @@ async function handleResourceAdd () {
|
|||||||
<option value="global">Global</option>
|
<option value="global">Global</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const d = dialog(header, body, async (result, form) => {
|
const d = dialog(header, body, async (result, form) => {
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
@ -359,8 +475,6 @@ async function handleResourceAdd () {
|
|||||||
const type = clusterResourceConfig[name].type;
|
const type = clusterResourceConfig[name].type;
|
||||||
const scope = form.get("scope");
|
const scope = form.get("scope");
|
||||||
|
|
||||||
console.log(name, type, scope);
|
|
||||||
|
|
||||||
// check if the resource name is not in the cluster config resources
|
// check if the resource name is not in the cluster config resources
|
||||||
if (!clusterResourceConfig[name]) {
|
if (!clusterResourceConfig[name]) {
|
||||||
alert(`${name} is not an allowed resource name`);
|
alert(`${name} is not an allowed resource name`);
|
||||||
@ -384,23 +498,24 @@ async function handleResourceAdd () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const field = document.querySelector("#resources");
|
const field = document.querySelector("#resources");
|
||||||
|
const resourceConfig = resourcesConfigPage[name];
|
||||||
let resourceLine;
|
let resourceLine;
|
||||||
|
|
||||||
if (scope === "global" && type === "numeric") {
|
if (scope === "global" && type === "numeric") {
|
||||||
userData.resources[name].global = { max: 0 };
|
userData.resources[name].global = { max: 0 };
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, name, { value: userData.resources[name].global.max }, "(Global)");
|
resourceLine = addResourceLine(resourceConfig, field, { value: userData.resources[name].global.max }, "(Global)");
|
||||||
}
|
}
|
||||||
else if (scope === "global" && type === "list") {
|
else if (scope === "global" && type === "list") {
|
||||||
userData.resources[name].global = [];
|
userData.resources[name].global = [];
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, name, { value: userData.resources[name].global }, "(Global)");
|
resourceLine = addResourceLine(resourceConfig, field, { value: userData.resources[name].global }, "(Global)");
|
||||||
}
|
}
|
||||||
else if (scope !== "global" && type === "numeric") {
|
else if (scope !== "global" && type === "numeric") {
|
||||||
userData.resources[name].nodes[scope] = { max: 0 };
|
userData.resources[name].nodes[scope] = { max: 0 };
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, name, { value: userData.resources[name].nodes[scope].max }, `(${scope})`);
|
resourceLine = addResourceLine(resourceConfig, field, { value: userData.resources[name].nodes[scope].max }, `(${scope})`);
|
||||||
}
|
}
|
||||||
else if (scope !== "global" && type === "list") {
|
else if (scope !== "global" && type === "list") {
|
||||||
userData.resources[name].nodes[scope] = [];
|
userData.resources[name].nodes[scope] = [];
|
||||||
resourceLine = addResourceLine(resourcesConfigPage, field, name, { value: userData.resources[name].nodes[scope] }, `(${scope})`);
|
resourceLine = addResourceLine(resourceConfig, field, { value: userData.resources[name].nodes[scope] }, `(${scope})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
postPopulateResourceLine(field, name, scope, resourcesConfigPage[name], resourceLine);
|
postPopulateResourceLine(field, name, scope, resourcesConfigPage[name], resourceLine);
|
||||||
@ -437,6 +552,8 @@ async function handleResourceDelete () {
|
|||||||
else {
|
else {
|
||||||
userData.resources[this.resourceName].nodes[this.resourceScope] = false;
|
userData.resources[this.resourceName].nodes[this.resourceScope] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete resourceRulesLines[this.element.id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -449,7 +566,7 @@ async function populateCluster () {
|
|||||||
|
|
||||||
for (const node of allNodes) { // for each node of all cluster nodes
|
for (const node of allNodes) { // for each node of all cluster nodes
|
||||||
const item = document.createElement("draggable-item");
|
const item = document.createElement("draggable-item");
|
||||||
item.data = node;
|
item.value = node;
|
||||||
item.innerHTML = `
|
item.innerHTML = `
|
||||||
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
||||||
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
||||||
@ -466,7 +583,7 @@ async function populateCluster () {
|
|||||||
|
|
||||||
for (const pool of allPools) { // for each pool of all cluster pools
|
for (const pool of allPools) { // for each pool of all cluster pools
|
||||||
const item = document.createElement("draggable-item");
|
const item = document.createElement("draggable-item");
|
||||||
item.data = pool;
|
item.value = pool;
|
||||||
item.innerHTML = `
|
item.innerHTML = `
|
||||||
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
<div style="display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center;">
|
||||||
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
<svg id="drag" role="application" aria-label="drag icon"><title>drag icon</title><use href="images/actions/drag.svg#symb"></use></svg>
|
||||||
@ -492,5 +609,73 @@ async function populateCluster () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleFormExit () {
|
async function handleFormExit () {
|
||||||
// TODO
|
const body = {
|
||||||
|
attributes: {
|
||||||
|
memberOf: []
|
||||||
|
},
|
||||||
|
resources: {},
|
||||||
|
cluster: {
|
||||||
|
admin: document.querySelector("#admin").checked,
|
||||||
|
nodes: {},
|
||||||
|
pools: {},
|
||||||
|
vmid: {
|
||||||
|
min: document.querySelector("#vmid-min").value,
|
||||||
|
max: document.querySelector("#vmid-max").value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const group of document.querySelector("#groups-enabled").value) {
|
||||||
|
body.attributes.memberOf.push(group.dn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate resources
|
||||||
|
for (const key of Object.keys(resourceRulesLines)) {
|
||||||
|
const resourceLine = resourceRulesLines[key];
|
||||||
|
// if type is numeric
|
||||||
|
if (resourceLine.resourceType === "numeric") {
|
||||||
|
if (body.resources[resourceLine.resourceName] === undefined) {
|
||||||
|
body.resources[resourceLine.resourceName] = {
|
||||||
|
global: {
|
||||||
|
max: 0
|
||||||
|
},
|
||||||
|
nodes: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (resourceLine.resourceScope === "global") {
|
||||||
|
body.resources[resourceLine.resourceName].global.max = resourceLine.element.value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
body.resources[resourceLine.resourceName].nodes[resourceLine.resourceScope].max = resourceLine.element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (body.resources[resourceLine.resourceName] === undefined) {
|
||||||
|
body.resources[resourceLine.resourceName] = {
|
||||||
|
global: [],
|
||||||
|
nodes: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (resourceLine.resourceScope === "global") {
|
||||||
|
body.resources[resourceLine.resourceName].global = resourceLine.element.value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
body.resources[resourceLine.resourceName].nodes[resourceLine.resourceScope] = resourceLine.element.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate nodes
|
||||||
|
for (const node of document.querySelector("#nodes-enabled").value) {
|
||||||
|
body.cluster.nodes[node] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate pools
|
||||||
|
for (const pool of document.querySelector("#pools-enabled").value) {
|
||||||
|
body.cluster.pools[pool] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO post to api
|
||||||
|
|
||||||
|
console.log(body);
|
||||||
}
|
}
|
||||||
|
@ -427,8 +427,7 @@ export function isEmpty (obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addResourceLine (config, field, resourceType, attributesOverride, labelPrefix = null) {
|
export function addResourceLine (resourceConfig, field, attributesOverride, labelPrefix = null) {
|
||||||
const resourceConfig = config[resourceType];
|
|
||||||
const iconHref = resourceConfig.icon;
|
const iconHref = resourceConfig.icon;
|
||||||
const elementType = resourceConfig.element;
|
const elementType = resourceConfig.element;
|
||||||
const labelText = labelPrefix ? `${labelPrefix} ${resourceConfig.name}` : resourceConfig.name;
|
const labelText = labelPrefix ? `${labelPrefix} ${resourceConfig.name}` : resourceConfig.name;
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
<legend>Cluster</legend>
|
<legend>Cluster</legend>
|
||||||
<div class="input-grid" style="grid-template-columns: auto auto 1fr;">
|
<div class="input-grid" style="grid-template-columns: auto auto 1fr;">
|
||||||
<label for="admin">Admin</label>
|
<label for="admin">Admin</label>
|
||||||
<input class="w3-check w3-border" type="checkbox" id="admin" name="admin">
|
<input class="w3-check w3-border" type="checkbox" id="admin" name="admin" style="margin-left: 0;">
|
||||||
<div></div>
|
<div></div>
|
||||||
<label style="align-self: start;">Nodes</label>
|
<label style="align-self: start;">Nodes</label>
|
||||||
<div class="grid two-columns" style="grid-column: 2 / span 2">
|
<div class="grid two-columns" style="grid-column: 2 / span 2">
|
||||||
|
Loading…
Reference in New Issue
Block a user