IP Manager überarbeitet
This commit is contained in:
@@ -122,3 +122,44 @@ color:#555;
|
|||||||
margin-left:30px;
|
margin-left:30px;
|
||||||
color:#555;
|
color:#555;
|
||||||
}
|
}
|
||||||
|
.clickable{
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clickable:hover{
|
||||||
|
color:#1e3a8a;
|
||||||
|
text-decoration:underline;
|
||||||
|
}
|
||||||
|
#lastUpdate{
|
||||||
|
font-size:13px;
|
||||||
|
margin-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ipList div{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ipList .ip{
|
||||||
|
flex:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ipList button{
|
||||||
|
margin-left:6px;
|
||||||
|
font-size:11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ipForm.edit-mode{
|
||||||
|
border:2px solid #3b82f6;
|
||||||
|
padding:10px;
|
||||||
|
border-radius:6px;
|
||||||
|
background:#eef4ff;
|
||||||
|
}
|
||||||
|
.ip.public{
|
||||||
|
background:#22c55e;
|
||||||
|
color:white;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
<h1>Ressourcen Verwaltung</h1>
|
<h1>Ressourcen Verwaltung</h1>
|
||||||
|
|
||||||
|
<div id="lastUpdate" style="margin-bottom:10px;color:#555;">
|
||||||
|
Letztes Update: -
|
||||||
|
</div>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
||||||
<h2>Kosten Dashboard</h2>
|
<h2>Kosten Dashboard</h2>
|
||||||
@@ -220,10 +224,9 @@ Domains jährlich: <span id="costDomain">0</span> €<br>
|
|||||||
<div id="ipList"></div>
|
<div id="ipList"></div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<input id="new_ip" placeholder="IP">
|
<input id="new_ip" placeholder="IP">
|
||||||
<input id="new_type" placeholder="type">
|
<input id="new_type" placeholder="public / private">
|
||||||
<input id="new_comment" placeholder="comment">
|
<input id="new_comment" placeholder="Beschreibung">
|
||||||
|
|
||||||
<button onclick="saveIP()">Add</button>
|
<button onclick="saveIP()">Add</button>
|
||||||
|
|
||||||
@@ -233,6 +236,20 @@ Domains jährlich: <span id="costDomain">0</span> €<br>
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="ipForm">
|
||||||
|
<input id="new_ip" placeholder="IP">
|
||||||
|
<input id="new_type" placeholder="public / private">
|
||||||
|
<input id="new_comment" placeholder="Beschreibung">
|
||||||
|
|
||||||
|
|
||||||
|
<button id="ipSaveBtn" onclick="saveIP()">Add</button>
|
||||||
|
<button id="ipCancelBtn" onclick="cancelIPEdit()" style="display:none">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="domainModal" class="modal">
|
<div id="domainModal" class="modal">
|
||||||
|
|
||||||
<h3 id="domainModalTitle">Domain</h3>
|
<h3 id="domainModalTitle">Domain</h3>
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ window.loadInfrastructure = async function(){
|
|||||||
|
|
||||||
resources.forEach(r => {
|
resources.forEach(r => {
|
||||||
|
|
||||||
let html = `<div class="infra-server"><b>${r.name}</b></div>`
|
let html = `
|
||||||
|
<div class="infra-server clickable"
|
||||||
|
onclick='openServerDetail(${JSON.stringify(r)})'>
|
||||||
|
<b>${r.name}</b>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
if(Array.isArray(r.ips)){
|
if(Array.isArray(r.ips)){
|
||||||
|
|
||||||
@@ -23,8 +28,12 @@ window.loadInfrastructure = async function(){
|
|||||||
|
|
||||||
domains.forEach(d => {
|
domains.forEach(d => {
|
||||||
|
|
||||||
html += `<div class="infra-domain"> └ 🌐 ${d.domain_name}</div>`
|
html += `
|
||||||
|
<div class="infra-domain clickable"
|
||||||
|
onclick='openDomainEdit(${JSON.stringify(d)})'>
|
||||||
|
🌐 ${d.domain_name}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
const sublist = subs.filter(s =>
|
const sublist = subs.filter(s =>
|
||||||
s.domain_id == d.domain_id || s.domain_name == d.domain_name
|
s.domain_id == d.domain_id || s.domain_name == d.domain_name
|
||||||
)
|
)
|
||||||
@@ -33,7 +42,12 @@ window.loadInfrastructure = async function(){
|
|||||||
|
|
||||||
if(s.ip_address == ip.ip){
|
if(s.ip_address == ip.ip){
|
||||||
|
|
||||||
html += `<div class="infra-sub"> └ ${s.subdomain}.${s.domain_name}</div>`
|
html += `
|
||||||
|
<div class="infra-sub clickable"
|
||||||
|
onclick='openSubEdit(${JSON.stringify(s)})'>
|
||||||
|
↳ ${s.subdomain}.${s.domain_name}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let refreshing = false
|
let refreshing = false
|
||||||
|
|
||||||
async function refreshAll(){
|
async function refreshAll(){
|
||||||
@@ -16,6 +15,7 @@ async function refreshAll(){
|
|||||||
if(refreshing) return
|
if(refreshing) return
|
||||||
refreshing = true
|
refreshing = true
|
||||||
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
await loadResources()
|
await loadResources()
|
||||||
@@ -26,16 +26,35 @@ async function refreshAll(){
|
|||||||
loadInfrastructure()
|
loadInfrastructure()
|
||||||
loadCosts()
|
loadCosts()
|
||||||
|
|
||||||
|
// Zeit setzen
|
||||||
|
updateLastUpdate()
|
||||||
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
|
||||||
console.error("Refresh error", e)
|
console.error("Refresh error", e)
|
||||||
|
|
||||||
|
document.getElementById("lastUpdate").innerText = "🔴 Fehler beim Update"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshing = false
|
refreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function clearDNSCache(){
|
function clearDNSCache(){
|
||||||
for(const key in dnsCache){
|
for(const key in dnsCache){
|
||||||
delete dnsCache[key]
|
delete dnsCache[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLastUpdate(){
|
||||||
|
|
||||||
|
const now = new Date()
|
||||||
|
|
||||||
|
const time = now.toLocaleTimeString()
|
||||||
|
|
||||||
|
// Lade-Indikator
|
||||||
|
document.getElementById("lastUpdate").innerText =
|
||||||
|
"🟢 Letztes Update: " + time
|
||||||
|
}
|
||||||
|
|||||||
@@ -233,9 +233,11 @@ document.getElementById("subdomainModal").style.display="block"
|
|||||||
|
|
||||||
window.openIPManager = function(resourceId){
|
window.openIPManager = function(resourceId){
|
||||||
|
|
||||||
document.getElementById("ip_resource_id").value=resourceId
|
document.getElementById("ip_resource_id").value = resourceId
|
||||||
|
|
||||||
document.getElementById("ipModal").style.display="block"
|
document.getElementById("ipModal").style.display="block"
|
||||||
|
|
||||||
|
loadIPs(resourceId) // 🔥 wichtig!
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,17 @@ window.loadResources = async function(){
|
|||||||
let ips = ""
|
let ips = ""
|
||||||
|
|
||||||
if(Array.isArray(r.ips)){
|
if(Array.isArray(r.ips)){
|
||||||
ips = r.ips.map(ip =>
|
ips = r.ips.map(ip => {
|
||||||
"<span class='ip'>" + (ip.type || "") + " " + ip.ip + "</span>"
|
const cls = (ip.type || "").toLowerCase().includes("public")
|
||||||
).join("")
|
? "ip public"
|
||||||
|
: "ip"
|
||||||
|
|
||||||
|
return "<span class='" + cls + "'>" +
|
||||||
|
(ip.type || "") + " " + ip.ip +
|
||||||
|
"</span>"
|
||||||
|
|
||||||
|
}).join("")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let domains = mappings
|
let domains = mappings
|
||||||
@@ -163,3 +171,141 @@ window.loadCancelled = async function(){
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.saveIP = async function(){
|
||||||
|
|
||||||
|
const resourceId = document.getElementById("ip_resource_id").value
|
||||||
|
|
||||||
|
const ipField = document.getElementById("new_ip")
|
||||||
|
const id = ipField.dataset.editId
|
||||||
|
|
||||||
|
const ip = ipField.value
|
||||||
|
const type = document.getElementById("new_type").value
|
||||||
|
const comment = document.getElementById("new_comment").value
|
||||||
|
|
||||||
|
if(id){
|
||||||
|
// 🔥 UPDATE
|
||||||
|
await api(API + "/ips/" + id, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {'Content-Type':'application/json'},
|
||||||
|
body: JSON.stringify({ip, type, comment})
|
||||||
|
})
|
||||||
|
|
||||||
|
delete ipField.dataset.editId
|
||||||
|
|
||||||
|
}else{
|
||||||
|
// 🔥 CREATE
|
||||||
|
|
||||||
|
try{
|
||||||
|
const result = await api(API + "/ipcheck/" + ip)
|
||||||
|
|
||||||
|
if(result.length){
|
||||||
|
if(!confirm("IP existiert bereits. Trotzdem speichern?")){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(e){}
|
||||||
|
|
||||||
|
await api(API + "/resources/" + resourceId + "/ips", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {'Content-Type':'application/json'},
|
||||||
|
body: JSON.stringify({ip, type, comment})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Felder reset
|
||||||
|
ipField.value = ""
|
||||||
|
document.getElementById("new_type").value = ""
|
||||||
|
document.getElementById("new_comment").value = ""
|
||||||
|
|
||||||
|
loadIPs(resourceId)
|
||||||
|
loadResources()
|
||||||
|
cancelIPEdit()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.deleteIP = async function(id, resourceId){
|
||||||
|
|
||||||
|
if(!confirm("IP löschen?")) return
|
||||||
|
|
||||||
|
await api(API + "/ips/" + id, {
|
||||||
|
method: "DELETE"
|
||||||
|
})
|
||||||
|
|
||||||
|
loadIPs(resourceId) // Modal neu laden
|
||||||
|
loadResources() // Tabelle aktualisieren
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
window.loadIPs = async function(resourceId){
|
||||||
|
|
||||||
|
const ips = await api(API + "/resources/" + resourceId + "/ips")
|
||||||
|
|
||||||
|
const container = document.getElementById("ipList")
|
||||||
|
container.innerHTML = ""
|
||||||
|
|
||||||
|
ips.forEach(ip => {
|
||||||
|
|
||||||
|
// ✅ HIER rein!
|
||||||
|
const cls = (ip.type || "").toLowerCase().includes("public")
|
||||||
|
? "ip public"
|
||||||
|
: "ip"
|
||||||
|
|
||||||
|
const div = document.createElement("div")
|
||||||
|
|
||||||
|
div.innerHTML = `
|
||||||
|
<span class="${cls}">
|
||||||
|
${ip.ip} (${ip.type || ""}) ${ip.comment || ""}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<button onclick="editIP(${ip.id}, '${ip.ip}', '${ip.type || ""}', '${ip.comment || ""}')">
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button onclick="deleteIP(${ip.id}, ${resourceId})">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
|
||||||
|
container.appendChild(div)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.editIP = function(id, ip, type, comment){
|
||||||
|
|
||||||
|
document.getElementById("new_ip").value = ip
|
||||||
|
document.getElementById("new_type").value = type
|
||||||
|
document.getElementById("new_comment").value = comment
|
||||||
|
|
||||||
|
document.getElementById("new_ip").dataset.editId = id
|
||||||
|
|
||||||
|
// 👇 UX Highlight + Fokus
|
||||||
|
document.getElementById("ipForm").classList.add("edit-mode")
|
||||||
|
document.getElementById("ipSaveBtn").innerText = "Update"
|
||||||
|
document.getElementById("ipCancelBtn").style.display = "inline-block"
|
||||||
|
|
||||||
|
document.getElementById("new_ip").focus() // 👈 HIER
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
window.cancelIPEdit = function(){
|
||||||
|
|
||||||
|
const ipField = document.getElementById("new_ip")
|
||||||
|
|
||||||
|
delete ipField.dataset.editId
|
||||||
|
|
||||||
|
ipField.value = ""
|
||||||
|
document.getElementById("new_type").value = ""
|
||||||
|
document.getElementById("new_comment").value = ""
|
||||||
|
|
||||||
|
document.getElementById("ipForm").classList.remove("edit-mode")
|
||||||
|
document.getElementById("ipSaveBtn").innerText = "Add"
|
||||||
|
document.getElementById("ipCancelBtn").style.display = "none"
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,4 +11,27 @@ router.post("/resources/:id/ips", controller.create);
|
|||||||
/* delete IP */
|
/* delete IP */
|
||||||
router.delete("/ips/:id", controller.remove);
|
router.delete("/ips/:id", controller.remove);
|
||||||
|
|
||||||
|
router.put("/ips/:id", async (req, res) => {
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
const {ip, type, comment} = req.body
|
||||||
|
|
||||||
|
await db.query(
|
||||||
|
"UPDATE resource_ips SET ip=?, type=?, comment=? WHERE id=?",
|
||||||
|
[ip, type, comment, req.params.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
res.json({success:true})
|
||||||
|
|
||||||
|
}catch(e){
|
||||||
|
|
||||||
|
console.error("UPDATE IP error:", e)
|
||||||
|
res.status(500).json({error:"DB error"})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user