2026-03-10 15:27:21 +01:00

536 lines
10 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

async function loadResources(){
const resources = await api(API + "/resources/active");
const mappings = await api(API + "/domainmap");
const table = document.getElementById("resources");
table.innerHTML = "";
resources.forEach(r => {
let ips = "";
if(Array.isArray(r.ips)){
ips = r.ips.map(ip =>
"<span class='ip'>" + (ip.type || "") + " " + ip.ip + "</span>"
).join("");
}
let domains = mappings
.filter(m => m.resource_id == r.id)
.map(m => "<span class='ip'>🌐 " + m.domain_name + "</span>")
.join("");
const tr = document.createElement("tr");
tr.innerHTML = `
<td>${r.name}</td>
<td>${r.produkt || ""}</td>
<td><span class="provider">${r.provider || ""}</span></td>
<td id="status-${r.id}">...</td>
<td>
<div class="system">
${r.cpu ? r.cpu + " CPU" : ""}
${r.ram ? " • " + r.ram + " RAM" : ""}
${r.disk ? " • " + r.disk : ""}
${r.os ? " • " + r.os : ""}
</div>
</td>
<td>${domains}</td>
<td>
${ips}
<br>
<button onclick="openIPManager(${r.id})">IPs</button>
</td>
<td>
<button onclick='openEdit(${JSON.stringify(r)})'>
Edit
</button>
<button onclick="deleteResource(${r.id})">
Delete
</button>
</td>
</td>
<td>
<button onclick="deleteResource(${r.id})">Delete</button>
</td>
`;
table.appendChild(tr);
});
}
async function loadDomains(){
const domains = await api(API + "/domains")
const table = document.getElementById("domains")
table.innerHTML = ""
for(const d of domains){
const tr = document.createElement("tr")
tr.innerHTML = `
<td>${d.domain_name}</td> <td> <span class="provider">${d.provider || ""}</span> </td> <td>${d.ip_address || ""}</td> <td id="server-${d.id}"> ${d.resource_name ? d.resource_name : "<span style='color:red'>⚠ no server</span>"} </td> <td id="dns-${d.id}">...</td> <td>${d.yearly_cost || ""}</td> <td> <button onclick='openDomainEdit(${JSON.stringify(d)})'>Edit</button> <button onclick="deleteDomain(${d.id})">Delete</button> </td> `
table.appendChild(tr)
try{
const dnsRes = await fetch(API + "/dns/" + d.domain_name)
const result = await dnsRes.json()
let status = "❌"
if(result.ips && result.ips.length){
const ipList = result.ips.join("<br>")
if(d.ip_address && result.ips.includes(d.ip_address)){
status = "✅ " + ipList
}else{
status = "⚠ " + ipList
}
}
document.getElementById("dns-"+d.id).innerHTML = status
}catch(e){
document.getElementById("dns-"+d.id).innerHTML = "❌"
}
}
}
async function deleteDomain(id){
if(!confirm("Domain löschen?")) return;
await api(API + "/domains/" + id, {
method: "DELETE"
});
loadDomains();
}
async function loadMapping(){
const data = await api(API + "/domainmap");
const table = document.getElementById("mapping");
table.innerHTML = "";
data.forEach(m => {
const tr = document.createElement("tr");
tr.innerHTML = `
<td>${m.domain_name}</td>
<td>${m.ip_address}</td>
<td>${m.server_name || ""}</td>
`;
table.appendChild(tr);
});
}
function openIPManager(resourceId){
document.getElementById("ip_resource_id").value = resourceId
document.getElementById("ipModal").style.display = "block"
loadIPs(resourceId)
}
function closeIPModal(){
document.getElementById("ipModal").style.display = "none"
}
async function loadIPs(resourceId){
const ips = await api(API + "/resources/" + resourceId + "/ips")
const container = document.getElementById("ipList")
container.innerHTML = ""
ips.forEach(ip=>{
const div = document.createElement("div")
div.innerHTML = `
${ip.ip} (${ip.type||""}) ${ip.comment||""}
<button onclick="deleteIP(${ip.id},${resourceId})">Delete</button>
`
container.appendChild(div)
})
}
async function saveIP(){
const resourceId = document.getElementById("ip_resource_id").value
const ip = document.getElementById("new_ip").value
const type = document.getElementById("new_type").value
const comment = document.getElementById("new_comment").value
await api("/resman/api/resources/"+resourceId+"/ips",{
method:"POST",
headers:{'Content-Type':'application/json'},
body:JSON.stringify({ip,type,comment})
})
loadIPs(resourceId)
loadResources()
}
function openCreate(){
document.getElementById("modalTitle").innerText = "Create Resource"
document.getElementById("resource_id").value = ""
document.querySelectorAll("#resourceModal input, #resourceModal textarea")
.forEach(e=>e.value="")
document.getElementById("status").value = "aktiv"
document.getElementById("resourceModal").style.display = "block"
}
function openEdit(resource){
document.getElementById("modalTitle").innerText = "Edit Resource"
document.getElementById("resource_id").value = resource.id
Object.keys(resource).forEach(k=>{
const el = document.getElementById(k)
if(el) el.value = resource[k] || ""
})
document.getElementById("resourceModal").style.display = "block"
}
function closeModal(){
document.getElementById("resourceModal").style.display="none"
}
async function saveResource(){
const id = document.getElementById("resource_id").value
let kostenMonat=document.getElementById("kosten_monat").value
let kostenJahr=document.getElementById("kosten_jahr").value
if(kostenMonat) kostenMonat=kostenMonat.replace(",",".")
if(kostenJahr) kostenJahr=kostenJahr.replace(",",".")
const data={
name:document.getElementById("name").value,
produkt:document.getElementById("produkt").value,
provider:document.getElementById("provider").value,
art:document.getElementById("art").value,
cpu:document.getElementById("cpu").value,
ram:document.getElementById("ram").value,
disk:document.getElementById("disk").value,
os:document.getElementById("os").value,
kosten_monat:kostenMonat || null,
kosten_jahr:kostenJahr || null,
providername:document.getElementById("providername").value,
ipv6_net:document.getElementById("ipv6_net").value,
bestelldatum:document.getElementById("bestelldatum").value || null,
kuendbar_ab:document.getElementById("kuendbar_ab").value || null,
kuendigungsdatum:document.getElementById("kuendigungsdatum").value || null,
status:document.getElementById("status").value,
bemerkung:document.getElementById("bemerkung").value
}
if(id){
await api(API+"/resources/"+id,{
method:"PUT",
headers:{'Content-Type':'application/json'},
body:JSON.stringify(data)
})
}else{
await api(API+"/resources",{
method:"POST",
headers:{'Content-Type':'application/json'},
body:JSON.stringify(data)
})
}
closeModal()
loadResources()
loadCancelled()
loadCosts()
loadInfrastructure()
}
function openDomainCreate(){
document.getElementById("domainModalTitle").innerText="Create Domain"
document.getElementById("domain_id").value=""
document.getElementById("domain_name").value=""
document.getElementById("domain_provider").value=""
document.getElementById("domain_ip").value=""
document.getElementById("domain_cost").value=""
document.getElementById("domain_notes").value=""
document.getElementById("domainModal").style.display="block"
}
function openDomainEdit(d){
document.getElementById("domainModalTitle").innerText="Edit Domain"
document.getElementById("domain_id").value=d.id
document.getElementById("domain_name").value=d.domain_name||""
document.getElementById("domain_provider").value=d.provider||""
document.getElementById("domain_ip").value=d.ip_address||""
document.getElementById("domain_cost").value=d.yearly_cost||""
document.getElementById("domain_notes").value=d.notes||""
document.getElementById("domainModal").style.display="block"
}
function closeDomainModal(){
document.getElementById("domainModal").style.display="none"
}
async function saveDomain(){
const id=document.getElementById("domain_id").value
let cost=document.getElementById("domain_cost").value
if(cost){
cost=cost.replace(",",".")
}
const data={
domain_name:domain_name.value,
provider:domain_provider.value,
ip_address:domain_ip.value,
yearly_cost:cost || null,
notes:domain_notes.value
}
if(id){
await api(API+"/domains/"+id,{
method:"PUT",
headers:{'Content-Type':'application/json'},
body:JSON.stringify(data)
})
}else{
await api(API+"/domains",{
method:"POST",
headers:{'Content-Type':'application/json'},
body:JSON.stringify(data)
})
}
closeDomainModal()
loadDomains()
loadMapping()
loadCosts()
}
async function loadCancelled(){
const res = await api(API+"/resources/cancelled")
const table = document.getElementById("cancelled")
table.innerHTML=""
res.forEach(r=>{
const tr=document.createElement("tr")
tr.innerHTML=`
<td>${r.name}</td>
<td>${r.produkt||""}</td>
<td><span class="provider">${r.provider || ""}</span></td>
<td>${r.cpu||""}</td>
<td>${r.ram||""}</td>
<td>${r.disk||""}</td>
<td>gekündigt</td>
`
table.appendChild(tr)
})
}
async function loadCosts(){
const resources = await api(API+"/resources/active")
const domains = await api(API+"/domains")
let month = 0
let year = 0
let domainYear = 0
resources.forEach(r=>{
let m = Number(r.kosten_monat || 0)
let y = Number(r.kosten_jahr || 0)
if(m){
month += m
}else if(y){
month += y / 12
}
if(y){
year += y
}else if(m){
year += m * 12
}
})
domains.forEach(d=>{
domainYear += Number(d.yearly_cost || 0)
})
document.getElementById("costMonth").innerText = month.toFixed(2)
document.getElementById("costYear").innerText = year.toFixed(2)
document.getElementById("costDomain").innerText = domainYear.toFixed(2)
document.getElementById("costTotal").innerText = (year + domainYear).toFixed(2)
}
async function loadInfrastructure(){
const resources = await api(API + "/resources/active")
const mappings = await api(API + "/domainmap")
let html = ""
resources.forEach(r => {
html += `
<div style="margin-bottom:20px;border:1px solid #ddd;padding:10px;border-radius:6px">
<b>${r.name}</b><br>
Produkt: ${r.produkt || ""}<br>
CPU: ${r.cpu || ""} | RAM: ${r.ram || ""} | Disk: ${r.disk || ""}<br>
OS: ${r.os || ""}
<br><br>
`
if(Array.isArray(r.ips)){
r.ips.forEach(ip => {
html += `
<div style="margin-left:20px">
<b>IP:</b> ${ip.ip} (${ip.type || ""})
`
const domains = mappings.filter(m => m.ip_address == ip.ip)
domains.forEach(d => {
html += `
<div style="margin-left:20px;color:#444">
🌐 ${d.domain_name}
</div>
`
})
html += "</div>"
})
}
html += "</div>"
})
document.getElementById("infraView").innerHTML = html
}
loadResources();
loadDomains();
loadMapping();
loadCosts()
loadInfrastructure()