feat: Added light mode up to admin

This commit is contained in:
2025-06-10 00:38:20 +00:00
parent a99bb24339
commit 38c840251f
18 changed files with 129 additions and 129 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ document.addEventListener('DOMContentLoaded', function() {
const scrollToTopButton = document.createElement('button');
scrollToTopButton.innerHTML = '<i class="fas fa-arrow-up"></i>';
scrollToTopButton.style.fontSize = '26px';
scrollToTopButton.className = 'fixed bottom-5 right-5 bg-gray-800 text-white p-3 rounded-full shadow-lg hidden';
scrollToTopButton.className = 'fixed bottom-5 right-5 bg-gray-200 dark:bg-gray-800 text-black dark:text-white p-3 rounded-full shadow-lg hidden';
scrollToTopButton.style.width = '60px';
scrollToTopButton.style.height = '60px';
scrollToTopButton.style.borderRadius = '50%';
+2 -2
View File
@@ -8,7 +8,7 @@ document.addEventListener('DOMContentLoaded', () => {
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.placeholder = 'Search by IP or Hostname';
searchInput.className = 'p-2 w-full rounded-lg bg-gray-800 text-gray-100 border border-gray-600 focus:outline-none focus:border-blue-400 mb-4 text-center';
searchInput.className = 'p-2 w-full rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600 focus:outline-none focus:border-blue-400 mb-4 text-center';
form.insertAdjacentElement('beforebegin', searchInput);
searchInput.addEventListener('keypress', (event) => {
@@ -40,7 +40,7 @@ document.addEventListener('DOMContentLoaded', () => {
const scrollToTopButton = document.createElement('button');
scrollToTopButton.innerHTML = '<i class="fas fa-arrow-up"></i>';
scrollToTopButton.style.fontSize = '26px';
scrollToTopButton.className = 'fixed bottom-5 right-5 bg-gray-800 text-white p-3 rounded-full shadow-lg hidden';
scrollToTopButton.className = 'fixed bottom-5 right-5 bg-gray-200 dark:bg-gray-800 text-black dark:text-white p-3 rounded-full shadow-lg hidden';
scrollToTopButton.style.width = '60px';
scrollToTopButton.style.height = '60px';
scrollToTopButton.style.borderRadius = '50%';
+5 -5
View File
@@ -8,23 +8,23 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<div class="flex items-center mb-6 relative">
<a href="javascript:window.history.back()" class="absolute left-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white flex items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<a href="javascript:window.history.back()" class="absolute left-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 flex items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center w-full">Add Device</h1>
</div>
<form action="/add_device" method="POST" class="flex flex-col space-y-4">
<input type="text" name="device_name" placeholder="Device Name" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<input type="text" name="device_name" placeholder="Device Name" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600" required>
<label for="device_type" class="block mb-2">Device Type</label>
<select id="device_type" name="device_type" class="border p-2 rounded w-full mb-4 bg-gray-800 text-gray-100 border-gray-600" required>
<select id="device_type" name="device_type" class="p-2 rounded w-full mb-4 bg-gray-200 dark:bg-gray-800 border border-gray-600" required>
{% for dtype in device_types %}
<option value="{{ dtype[0] }}">{{ dtype[1] }}</option>
{% endfor %}
</select>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">Add Device</button>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add Device</button>
</form>
</div>
</div>
+6 -6
View File
@@ -8,25 +8,25 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<h1 class="text-3xl font-bold mb-8 text-center">Add Rack</h1>
<form action="/rack/add" method="POST" class="space-y-6 bg-gray-800 rounded-lg shadow-md p-6">
<form action="/rack/add" method="POST" class="space-y-6 bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md p-6">
<div>
<label for="name" class="block font-medium mb-1">Rack Name</label>
<input type="text" id="name" name="name" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-full" required>
<input type="text" id="name" name="name" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600 w-full" required>
</div>
<div>
<label for="site" class="block font-medium mb-1">Site</label>
<input type="text" id="site" name="site" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-full" required>
<input type="text" id="site" name="site" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600 w-full" required>
</div>
<div>
<label for="height_u" class="block font-medium mb-1">Height (U)</label>
<input type="number" id="height_u" name="height_u" min="1" max="60" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-full" required>
<input type="number" id="height_u" name="height_u" min="1" max="60" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600 w-full" required>
</div>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg w-full">Add Rack</button>
<button type="submit" class="bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg w-full">Add Rack</button>
</form>
</div>
</div>
+4 -4
View File
@@ -8,14 +8,14 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<h1 class="text-3xl font-bold mb-6 text-center">Admin</h1>
<div class="flex justify-center gap-4 mb-6">
<a href="/audit" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg shadow text-center w-40">Audit Log</a>
<a href="/users" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg shadow text-center w-40">Users</a>
<a href="/audit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg shadow text-center w-40">Audit Log</a>
<a href="/users" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg shadow text-center w-40">Users</a>
</div>
<hr class="border-t-2 border-gray-600 rounded-lg mb-4">
<h1 class="text-2xl font-bold mb-6 text-center">Add Subnet</h1>
@@ -27,7 +27,7 @@
<input type="text" name="name" placeholder="Subnet Name" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<input type="text" name="cidr" id="cidr-input" placeholder="CIDR (e.g., 192.168.1.0/24)" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<input type="text" name="site" placeholder="Site/Location" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg">Add Subnet</button>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add Subnet</button>
<span id="cidr-error" class="text-red-500 text-sm hidden"></span>
</div>
</form>
+2 -2
View File
@@ -8,7 +8,7 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-6xl pt-20">
@@ -38,7 +38,7 @@
<option value="{{ device[0] }}" {% if request.args.get('device_name') == device[0] %}selected{% endif %}>{{ device[0] }}</option>
{% endfor %}
</select>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">Filter</button>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Filter</button>
</form>
<table class="w-full table-auto bg-gray-800 rounded-lg overflow-hidden">
<thead>
+11 -11
View File
@@ -8,16 +8,16 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 w-auto min-w-[20rem] max-w-2xl pt-20">
<div class="flex items-center mb-8 relative justify-between gap-4">
<a href="javascript:window.history.back()" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white flex items-center justify-center rounded-full w-11 h-11 shrink-0"><i class="fas fa-arrow-left"></i></a>
<a href="javascript:window.history.back()" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 flex items-center justify-center rounded-full w-11 h-11 shrink-0"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center flex-1 min-w-0 truncate">{{ device.name }}</h1>
<form action="/update_device_type" method="POST" class="hidden md:inline ml-2">
<input type="hidden" name="device_id" value="{{ device.id }}">
<select name="device_type_id" class="border p-2 rounded bg-gray-800 text-gray-100 border-gray-600" onchange="this.form.submit()">
<select name="device_type_id" class="border p-2 rounded bg-gray-200 dark:bg-gray-800 border-gray-600" onchange="this.form.submit()">
{% for dtype in device_types %}
<option value="{{ dtype[0] }}" {% if device.device_type_id == dtype[0] %}selected{% endif %}>{{ dtype[1] }}</option>
{% endfor %}
@@ -26,7 +26,7 @@
<div class="flex items-center shrink-0">
<form action="/rename_device" method="POST" class="inline">
<input type="hidden" name="device_id" value="{{ device.id }}">
<input type="text" name="new_name" value="{{ device.name }}" class="hidden border p-1 rounded bg-gray-800 text-gray-100 border-gray-600 w-32 mr-2" style="vertical-align: middle;" required>
<input type="text" name="new_name" value="{{ device.name }}" class="hidden border p-1 rounded bg-gray-200 dark:bg-gray-800 border-gray-600 w-32 mr-2" style="vertical-align: middle;" required>
<button type="button" class="text-blue-400 hover:text-blue-600 ml-2 rename-btn" title="Rename Device"><i class="fas fa-pencil-alt"></i></button>
<button type="submit" class="text-green-400 hover:text-green-600 ml-2 save-btn hidden" title="Save Name"><i class="fas fa-check"></i></button>
<button type="button" class="text-gray-400 hover:text-gray-600 ml-2 cancel-btn hidden" title="Cancel"><i class="fas fa-times"></i></button>
@@ -41,30 +41,30 @@
</div>
<form action="/device/{{ device.id }}/add_ip" method="POST" class="mb-6">
<div class="flex flex-col space-y-4">
<select name="site" id="site-select" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600 w-full" required>
<select name="site" id="site-select" class="border p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border-gray-600 w-full" required>
<option value="" disabled selected>Select Site...</option>
{% set sites = subnets | map(attribute='site') | unique | list %}
{% for site in sites %}
<option value="{{ site }}">{{ site }}</option>
{% endfor %}
</select>
<select name="subnet_id" id="subnet-select" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600 w-full" required>
<select name="subnet_id" id="subnet-select" class="border p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border-gray-600 w-full" required>
<option value="" disabled selected>Select Subnet...</option>
{% for subnet in subnets %}
<option value="{{ subnet.id }}" data-site="{{ subnet.site }}">{{ subnet.name }} ({{ subnet.cidr }})</option>
{% endfor %}
</select>
<select name="ip_id" id="ip-select" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600 w-full" required>
<select name="ip_id" id="ip-select" class="border p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border-gray-600 w-full" required>
<option value="" disabled selected>Select IP...</option>
</select>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg w-full">Add IP</button>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg w-full">Add IP</button>
</div>
</form>
<div class="allocated-ips">
<h3 class="text-lg font-bold mb-2">Allocated IPs:</h3>
<ul class="space-y-2">
{% for ip in device_ips %}
<li class="flex justify-between items-center bg-gray-700 p-2 rounded-lg">
<li class="flex justify-between items-center bg-gray-200 dark:bg-gray-700 p-2 rounded-lg">
<span class="allocated-ip">{{ ip.ip }}</span>
<form action="/device/{{ device.id }}/delete_ip" method="POST" class="inline">
<input type="hidden" name="device_ip_id" value="{{ ip.device_ip_id }}">
@@ -77,8 +77,8 @@
<form action="/update_device_description" method="POST" class="mb-6 mt-4">
<input type="hidden" name="device_id" value="{{ device.id }}">
<label for="description" class="block mb-2 text-lg font-bold">Description</label>
<textarea id="description" name="description" rows="3" class="border p-2 rounded-lg bg-gray-800 text-gray-100 border-gray-600 w-full resize-y" placeholder="Enter device description...">{{ device.description or '' }}</textarea>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg w-full mt-2">Save Description</button>
<textarea id="description" name="description" rows="3" class="border p-2 rounded-lg bg-gray-200 dark:bg-gray-800 border-gray-600 w-full resize-y" placeholder="Enter device description...">{{ device.description or '' }}</textarea>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg w-full mt-2">Save Description</button>
</form>
</div>
</div>
+5 -5
View File
@@ -8,18 +8,18 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-2xl pt-20">
<div class="flex items-center mb-6 relative">
<a href="/devices" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<a href="/devices" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center w-full">Device Stats</h1>
</div>
<div class="bg-gray-800 rounded-lg shadow-md p-6">
<div class="bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md p-6">
<table class="w-full table-auto">
<thead>
<tr class="bg-gray-700">
<tr class="dark:bg-gray-700">
<th class="px-4 py-2 text-left">Type</th>
<th class="px-4 py-2 text-center">Count</th>
</tr>
@@ -29,7 +29,7 @@
<tr class="border-b border-gray-700">
<td class="px-4 py-3 flex items-center gap-2">
<a href="{{ url_for('devices_by_type', device_type=name) }}" class="hover:underline flex items-center gap-2">
<i class="fas {{ icon_class }} text-blue-300"></i> {{ name }}
<i class="fas {{ icon_class }} dark:text-blue-300"></i> {{ name }}
</a>
</td>
<td class="px-4 py-3 text-center font-bold">{{ count }}</td>
+8 -8
View File
@@ -9,23 +9,23 @@
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<link href="/static/css/devices.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-4xl pt-20">
<h1 class="text-3xl font-bold mb-6 text-center">Device Manager</h1>
<div class="flex flex-row justify-center gap-4 mb-6">
<a href="/add_device" class="text-center bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">Add New Device</a>
<a href="/device_type_stats" class="text-center bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">View Device Stats</a>
<a href="/add_device" class="text-center bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add New Device</a>
<a href="/device_type_stats" class="text-center bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">View Device Stats</a>
</div>
<div class="mb-6">
<input type="text" id="search" placeholder="Search devices or IPs..." class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600 w-full">
<input type="text" id="search" placeholder="Search devices or IPs..." class="border p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border-gray-600 w-full">
</div>
<div id="site-list" class="space-y-6">
{% for site, devices in sites_devices.items() %}
<div class="site-group bg-gray-800 rounded-lg shadow-md">
<div class="site-group bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md">
<div class="flex flex-row items-center justify-between p-4 cursor-pointer site-header">
<h2 class="text-xl font-bold mb-0 text-blue-300">{{ site }}</h2>
<h2 class="text-xl font-bold mb-0 dark:text-blue-300">{{ site }}</h2>
<button type="button" class="expand-btn text-gray-400 hover:text-gray-200 ml-2 flex items-center" aria-label="Expand site">
<i class="fas fa-chevron-down"></i>
</button>
@@ -33,13 +33,13 @@
<ul class="device-list hidden px-6 pb-4">
{% for device in devices %}
<li class="my-2">
<a href="/device/{{ device.id }}" class="flex items-center justify-between bg-gray-900 hover:bg-gray-700 text-gray-200 hover:text-white font-semibold rounded-lg px-4 py-2 shadow transition-colors duration-150">
<a href="/device/{{ device.id }}" class="flex items-center justify-between bg-gray-300 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-700 dark:text-gray-200 font-semibold rounded-lg px-4 py-2 shadow transition-colors duration-150">
<span><i class="fas {{ device.icon_class or 'fa-server' }} mr-2"></i>{{ device.name }}</span>
{% set ips = device_ips.get(device.id, []) %}
<span class="flex flex-row flex-wrap justify-end items-center ml-4 text-xs text-blue-300 font-normal align-middle">
{% if ips|length > 0 %}
{% for ip in ips %}
<span class="inline-block bg-gray-800 text-blue-200 rounded px-2 py-1 ml-1 font-mono">{{ ip[1] }}</span>
<span class="inline-block bg-gray-200 dark:bg-gray-800 text-gray-900 dark:text-blue-200 rounded px-2 py-1 ml-1 font-mono">{{ ip[1] }}</span>
{% endfor %}
{% else %}
<span class="text-gray-400">No IPs</span>
+7 -7
View File
@@ -8,20 +8,20 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-3xl pt-20">
<h1 class="text-3xl font-bold mb-8 text-center">
<i class="fas {{ icon_class }} text-blue-300"></i> {{ device_type }} Devices
<i class="fas {{ icon_class }} dark:text-blue-300"></i> {{ device_type }} Devices
</h1>
{% for site, devices in site_devices.items() %}
<div class="mb-8">
<h2 class="text-xl font-bold mb-4 text-blue-200">{{ site }}</h2>
<div class="bg-gray-800 rounded-lg shadow-md p-4">
<h2 class="text-xl font-bold mb-4 dark:text-blue-200">{{ site }}</h2>
<div class="bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md p-4">
<table class="w-full table-auto mb-2">
<thead>
<tr class="bg-gray-700">
<tr class="bg-gray-200 dark:bg-gray-700">
<th class="px-4 py-2 text-left">Device Name</th>
<th class="px-4 py-2 text-left">Description</th>
</tr>
@@ -30,14 +30,14 @@
{% for device in devices %}
<tr class="border-b border-gray-700">
<td class="px-4 py-3">
<a href="/device/{{ device.id }}" class="hover:underline text-blue-300">{{ device.name }}</a>
<a href="/device/{{ device.id }}" class="hover:underline dark:text-blue-300">{{ device.name }}</a>
</td>
<td class="px-4 py-3">{{ device.description or '' }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr class="bg-gray-900 font-bold">
<tr class="bg-gray-200 dark:bg-gray-900 font-bold">
<td class="px-4 py-2 text-right" colspan="2">Total: {{ devices|length }}</td>
</tr>
</tfoot>
+9 -9
View File
@@ -8,33 +8,33 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 w-full sm:max-w-3/4 pt-20">
<div class="flex items-center mb-6 relative">
<a href="/subnet/{{ subnet.id }}" class="absolute left-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white flex items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<a href="/subnet/{{ subnet.id }}" class="absolute left-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 flex items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center w-full">DHCP Pool for {{ subnet.name }}</h1>
</div>
{% if error %}
<div class="text-red-500 text-center mb-4">{{ error }}</div>
{% endif %}
<form action="" method="POST" class="bg-gray-800 p-6 rounded-lg shadow-md flex flex-col gap-4">
<form action="" method="POST" class="bg-gray-200 dark:bg-gray-800 p-6 rounded-lg shadow-md flex flex-col gap-4">
<label for="start_ip" class="font-medium">Start IP Address</label>
<input type="text" id="start_ip" name="start_ip" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.100" required value="{{ dhcp_pool.start_ip if dhcp_pool else '' }}">
<input type="text" id="start_ip" name="start_ip" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.100" required value="{{ dhcp_pool.start_ip if dhcp_pool else '' }}">
<label for="end_ip" class="font-medium">End IP Address</label>
<input type="text" id="end_ip" name="end_ip" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.200" required value="{{ dhcp_pool.end_ip if dhcp_pool else '' }}">
<input type="text" id="end_ip" name="end_ip" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.200" required value="{{ dhcp_pool.end_ip if dhcp_pool else '' }}">
<label for="excluded_ips" class="font-medium">Exclude IPs (comma separated)</label>
<input type="text" id="excluded_ips" name="excluded_ips" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.105,192.168.1.110" value="{{ dhcp_pool.excluded_ips if dhcp_pool and dhcp_pool.excluded_ips else '' }}">
<input type="text" id="excluded_ips" name="excluded_ips" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" placeholder="e.g. 192.168.1.105,192.168.1.110" value="{{ dhcp_pool.excluded_ips if dhcp_pool and dhcp_pool.excluded_ips else '' }}">
<div class="flex gap-4 mt-4">
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg">Save DHCP Pool</button>
<button type="submit" class="bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Save DHCP Pool</button>
{% if dhcp_pool %}
<button type="submit" name="remove" value="1" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg">Remove DHCP Pool</button>
<button type="submit" name="remove" value="1" class="bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Remove DHCP Pool</button>
{% endif %}
</div>
</form>
{% if dhcp_pool %}
<div class="mt-8 bg-gray-700 p-4 rounded-lg">
<div class="mt-8 bg-gray-200 dark:bg-gray-800 p-4 rounded-lg">
<h2 class="text-xl font-bold mb-2">Current DHCP Pool</h2>
<div>Start: <span class="font-mono">{{ dhcp_pool.start_ip }}</span></div>
<div>End: <span class="font-mono">{{ dhcp_pool.end_ip }}</span></div>
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="icon" type="image/png" href="/static/logo.png">
<link href="/static/css/output.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-2xl pt-20">
+8 -8
View File
@@ -8,28 +8,28 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<h1 class="text-3xl font-bold mb-6 text-center">JDB-NET IPAM</h1>
<ul class="space-y-4">
{% for site, subnets in sites_subnets.items() %}
<li class="site-group bg-gray-800 rounded-xl shadow-lg">
<li class="site-group bg-gray-200 dark:bg-gray-800 rounded-xl shadow-lg">
<div class="flex flex-row items-center justify-between p-4 cursor-pointer site-header">
<h2 class="text-xl font-bold mb-0 text-blue-300">{{ site }}</h2>
<button type="button" class="expand-btn text-gray-400 hover:text-gray-200 ml-2 flex items-center" aria-label="Expand site">
<h2 class="text-xl font-bold mb-0 text-gray-900 dark:text-blue-300">{{ site }}</h2>
<button type="button" class="expand-btn text-gray-400 ml-2 flex items-center" aria-label="Expand site">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<ul class="subnet-list hidden space-y-4 px-2 pb-4">
{% for subnet in subnets %}
<li class="p-4 bg-gray-900 rounded-lg shadow-md flex items-center justify-between">
<li class="p-4 bg-gray-300 dark:bg-gray-900 rounded-lg shadow-md flex items-center justify-between">
<div>
<a href="/subnet/{{ subnet.id }}" class="text-blue-400 hover:text-blue-300 text-lg font-medium">{{ subnet.name }}</a>
<p class="text-sm text-gray-400">{{ subnet.cidr }}</p>
<a href="/subnet/{{ subnet.id }}" class="text-gray-900 hover:text-gray-700 dark:text-blue-400 dark:hover:text-blue-300 text-lg font-medium">{{ subnet.name }}</a>
<p class="text-sm text-gray-800 dark:text-gray-400">{{ subnet.cidr }}</p>
</div>
<button type="button" class="export-csv-btn ml-2 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white flex items-center justify-center rounded-full w-9 h-9" title="Export as CSV" data-subnet-id="{{ subnet.id }}">
<button type="button" class="export-csv-btn ml-2 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 flex items-center justify-center rounded-full w-9 h-9" title="Export as CSV" data-subnet-id="{{ subnet.id }}">
<i class="fas fa-file-csv"></i>
</button>
</li>
+4 -4
View File
@@ -7,15 +7,15 @@
<link rel="icon" type="image/png" href="/static/logo.png">
<link href="/static/css/output.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<h1 class="text-3xl font-bold mb-6 text-center">JDB-NET IPAM</h1>
<form action="/login" method="POST" class="flex flex-col space-y-4">
<input type="email" name="email" placeholder="Email Address" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<input type="password" name="password" placeholder="Password" class="border p-3 rounded-lg bg-gray-800 text-gray-100 border-gray-600" required>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">Login</button>
<input type="email" name="email" placeholder="Email Address" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600" required>
<input type="password" name="password" placeholder="Password" class="p-3 rounded-lg bg-gray-200 dark:bg-gray-800 border border-gray-600" required>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Login</button>
</form>
{% if error %}
<p class="text-red-500 text-center mt-4">{{ error }}</p>
+28 -28
View File
@@ -8,20 +8,20 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-2xl pt-20">
<div class="flex flex-col items-center mb-6 relative min-h-[3.5rem]">
<a href="/racks" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<a href="/racks" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center w-full mb-0">{{ rack.name }}</h1>
<span class="text-base text-gray-400 mt-1">({{ rack.height_u }}U, {{ rack.site }})</span>
<span class="text-base mt-1">({{ rack.height_u }}U, {{ rack.site }})</span>
<form action="/rack/{{ rack.id }}/delete" method="POST" onsubmit="return confirm('Delete this rack?');" class="hidden sm:flex absolute right-0 mr-14">
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11 flex" title="Delete Rack">
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11 flex" title="Delete Rack">
<i class="fas fa-times fa-lg"></i>
</button>
</form>
<button type="button" id="export-csv" class="hidden sm:flex absolute right-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11 export-csv-btn" title="Export as CSV" data-rack-id="{{ rack.id }}">
<button type="button" id="export-csv" class="hidden sm:flex absolute right-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11 export-csv-btn" title="Export as CSV" data-rack-id="{{ rack.id }}">
<i class="fas fa-file-csv fa-lg"></i>
</button>
<script>
@@ -37,17 +37,17 @@
</div>
<div class="flex flex-col gap-4 mb-6 items-stretch">
<div class="flex gap-4 w-full justify-center">
<a href="?side=front" id="front-btn" class="rack-side-btn px-4 py-2 rounded-lg text-white font-semibold bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 {% if current_side == 'front' %}ring-2 ring-gray-400{% endif %}">Front</a>
<a href="?side=back" id="back-btn" class="rack-side-btn px-4 py-2 rounded-lg text-white font-semibold bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 {% if current_side == 'back' %}ring-2 ring-gray-400{% endif %}">Back</a>
<a href="?side=front" id="front-btn" class="rack-side-btn px-4 py-2 rounded-lg font-semibold bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 {% if current_side == 'front' %}ring-2 ring-gray-400{% endif %}">Front</a>
<a href="?side=back" id="back-btn" class="rack-side-btn px-4 py-2 rounded-lg font-semibold bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 {% if current_side == 'back' %}ring-2 ring-gray-400{% endif %}">Back</a>
</div>
<div class="flex flex-wrap gap-4 w-full justify-center">
<button id="show-add-device-form" type="button" class="flex-1 min-w-[12rem] max-w-[16rem] bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg flex-shrink-0 whitespace-nowrap"> <i class="fas fa-plus"></i> Add Device</button>
<button id="show-nonnet-form" type="button" class="flex-[1.5_1.5_0%] min-w-[16rem] max-w-[28rem] bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg flex-shrink-0 whitespace-nowrap"> <i class="fas fa-plus"></i> Add Non-Networked Device</button>
<button id="show-add-device-form" type="button" class="flex-1 min-w-[12rem] max-w-[16rem] bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg flex-shrink-0 whitespace-nowrap"> <i class="fas fa-plus"></i> Add Device</button>
<button id="show-nonnet-form" type="button" class="flex-[1.5_1.5_0%] min-w-[16rem] max-w-[28rem] bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg flex-shrink-0 whitespace-nowrap"> <i class="fas fa-plus"></i> Add Non-Networked Device</button>
</div>
</div>
<form id="add-device-form" action="/rack/{{ rack.id }}/add_device" method="POST" class="hidden mb-6 bg-gray-800 rounded-lg p-4">
<form id="add-device-form" action="/rack/{{ rack.id }}/add_device" method="POST" class="hidden mb-6 bg-gray-200 dark:bg-gray-800 rounded-lg p-4">
<div class="flex flex-col md:flex-row gap-2 mb-2">
<select name="device_id" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:flex-1" required>
<select name="device_id" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:flex-1" required>
<option value="" disabled selected>Select Device...</option>
{% for device in site_devices %}
{% if device.device_type_id != 2 and device.device_type_id != 6 %}
@@ -55,28 +55,28 @@
{% endif %}
{% endfor %}
</select>
<input type="number" name="position_u" min="1" max="{{ rack.height_u }}" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:w-24" placeholder="U" required>
<select name="side" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:w-28" required>
<input type="number" name="position_u" min="1" max="{{ rack.height_u }}" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:w-24" placeholder="U" required>
<select name="side" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:w-28" required>
<option value="front">Front</option>
<option value="back">Back</option>
</select>
<button type="submit" class="w-full md:w-auto bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg">Add Device</button>
<button id="hide-add-device-form" type="button" class="w-full md:w-auto bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg md:ml-0.5 mt-2 md:mt-0 flex-shrink-0"><i class="fas fa-times"></i></button>
<button type="submit" class="w-full md:w-auto bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add Device</button>
<button id="hide-add-device-form" type="button" class="w-full md:w-auto bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg md:ml-0.5 mt-2 md:mt-0 flex-shrink-0"><i class="fas fa-times"></i></button>
</div>
<div class="text-xs text-gray-400">To add a multi-U device, repeat for each U position.</div>
<div class="text-xs dark:text-gray-400">To add a multi-U device, repeat for each U position.</div>
</form>
<form id="nonnet-form" action="/rack/{{ rack.id }}/add_nonnet_device" method="POST" class="hidden flex flex-col gap-2 mt-2 mb-6 bg-gray-800 rounded-lg p-4">
<form id="nonnet-form" action="/rack/{{ rack.id }}/add_nonnet_device" method="POST" class="hidden flex flex-col gap-2 mt-2 mb-6 bg-gray-200 dark:bg-gray-800 rounded-lg p-4">
<div class="flex flex-col md:flex-row gap-2">
<input type="text" name="device_name" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:flex-1" placeholder="Device Name" required>
<input type="number" name="position_u" min="1" max="{{ rack.height_u }}" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:w-24" placeholder="U" required>
<select name="side" class="border p-2 rounded bg-gray-900 text-gray-100 border-gray-600 w-full md:w-28" required>
<input type="text" name="device_name" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:flex-1" placeholder="Device Name" required>
<input type="number" name="position_u" min="1" max="{{ rack.height_u }}" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:w-24" placeholder="U" required>
<select name="side" class="border p-2 rounded bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-full md:w-28" required>
<option value="front">Front</option>
<option value="back">Back</option>
</select>
<button type="submit" class="w-full md:w-auto bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg">Add</button>
<button id="hide-nonnet-form" type="button" class="w-full md:w-auto bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg md:ml-0.5 mt-2 md:mt-0 flex-shrink-0"><i class="fas fa-times"></i></button>
<button type="submit" class="w-full md:w-auto bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add</button>
<button id="hide-nonnet-form" type="button" class="w-full md:w-auto bg-gradient-to-r from-gray-300 to-gray-300 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg md:ml-0.5 mt-2 md:mt-0 flex-shrink-0"><i class="fas fa-times"></i></button>
</div>
<div class="text-xs text-gray-400 mt-2">Add a non-networked device.</div>
<div class="text-xs dark:text-gray-400 mt-2">Add a non-networked device.</div>
</form>
<script>
function showBothAddButtons() {
@@ -106,20 +106,20 @@
{% if error %}
<div class="mb-4 p-3 bg-red-700 text-white rounded-lg text-center font-semibold">{{ error }}</div>
{% endif %}
<div id="rack-visual" class="bg-gray-800 rounded-lg shadow-md p-4">
<h2 class="text-xl font-bold mb-2 text-blue-200" id="rack-side-label">{{ current_side|capitalize }}</h2>
<div id="rack-visual" class="bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md p-4">
<h2 class="text-xl font-bold mb-2 dark:text-blue-200" id="rack-side-label">{{ current_side|capitalize }}</h2>
<div id="rack-units">
{% for u in range(rack.height_u, 0, -1) %}
<div class="flex items-center h-10 border-b border-gray-700 hover:bg-gray-700/30 transition group">
<span class="w-16 text-right text-gray-400 text-base font-mono pr-4">U{{ u }}</span>
<span class="w-16 text-right dark:text-gray-400 text-base font-mono pr-4">U{{ u }}</span>
<span class="flex-1 ml-4 flex items-center min-h-8">
{% set found = false %}
{% for rd in rack_devices %}
{% if rd.position_u == u and rd.side == current_side %}
{% if rd.device_id %}
<a href="/device/{{ rd.device_id }}" class="text-blue-400 hover:underline text-base">{{ rd.device_name }}</a>
<a href="/device/{{ rd.device_id }}" class="dark:text-blue-400 hover:underline text-base">{{ rd.device_name }}</a>
{% else %}
<span class="text-blue-200 text-base">{{ rd.nonnet_device_name }}</span>
<span class="dark:text-blue-200 text-base">{{ rd.nonnet_device_name }}</span>
{% endif %}
<form action="/rack/{{ rack.id }}/remove_device" method="POST" style="display:inline" onsubmit="return confirm('Are you sure you want to remove this device from the rack?');">
<input type="hidden" name="rack_device_id" value="{{ rd.id }}">
+7 -7
View File
@@ -8,20 +8,20 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-md pt-20">
<h1 class="text-3xl font-bold mb-8 text-center">Racks</h1>
<div class="flex justify-center mb-6">
<a href="/rack/add" class="bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg inline-block"><i class="fas fa-plus"></i> Add Rack</a>
<a href="/rack/add" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg inline-block"><i class="fas fa-plus"></i> Add Rack</a>
</div>
<div class="space-y-6">
{% for rack in racks %}
<a href="/rack/{{ rack.id }}" class="block bg-gray-800 rounded-lg shadow-md p-4 flex items-start justify-between hover:ring-2 hover:ring-gray-400 transition group">
<a href="/rack/{{ rack.id }}" class="bg-gray-200 dark:bg-gray-800 rounded-lg shadow-md p-4 flex items-start justify-between hover:ring-2 hover:ring-gray-400 transition group">
<div>
<h2 class="text-xl font-bold text-blue-200 mb-1">{{ rack.name }}</h2>
<div class="text-gray-400">Site: {{ rack.site }} | Height: {{ rack.height_u }}U</div>
<h2 class="text-xl font-bold dark:text-blue-200 mb-1">{{ rack.name }}</h2>
<div class="dark:text-gray-400">Site: {{ rack.site }} | Height: {{ rack.height_u }}U</div>
</div>
<div class="ml-6 flex-shrink-0">
<div class="relative flex items-center justify-center w-16 h-16 group">
@@ -30,8 +30,8 @@
<circle cx="50" cy="50" r="42" stroke="#6b7280" stroke-width="12" fill="none" stroke-dasharray="264" stroke-dashoffset="{{ 264 - (264 * rack.percent_full / 100) }}" style="transition: stroke-dashoffset 0.5s;" />
</svg>
<div class="absolute inset-0 flex flex-col items-center justify-center">
<span class="text-sm font-bold text-white">{{ rack.percent_full }}%</span>
<span class="text-xs text-gray-300">Full</span>
<span class="text-sm font-bold">{{ rack.percent_full }}%</span>
<span class="text-xs dark:text-gray-300">Full</span>
</div>
</div>
</div>
+12 -12
View File
@@ -9,37 +9,37 @@
<script src="/static/js/subnet.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 w-full sm:max-w-3/4 pt-20">
<div class="flex items-center mb-6 relative">
<a href="javascript:window.history.back()" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<a href="javascript:window.history.back()" class="hidden sm:flex absolute left-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11"><i class="fas fa-arrow-left"></i></a>
<h1 class="text-3xl font-bold text-center w-full">{{ subnet.name }} ({{ subnet.cidr }})</h1>
<button type="button" id="export-csv" class="hidden sm:flex absolute right-0 bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white items-center justify-center rounded-full w-11 h-11 export-csv-btn" title="Export as CSV" data-subnet-id="{{ subnet.id }}">
<button type="button" id="export-csv" class="hidden sm:flex absolute right-0 bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 items-center justify-center rounded-full w-11 h-11 export-csv-btn" title="Export as CSV" data-subnet-id="{{ subnet.id }}">
<i class="fas fa-file-csv fa-lg"></i>
</button>
</div>
<div class="flex justify-center mb-4">
<a href="/subnet/{{ subnet.id }}/dhcp" class="hidden sm:flex bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white px-4 py-2 rounded-lg shadow items-center gap-2">
<a href="/subnet/{{ subnet.id }}/dhcp" class="hidden sm:flex bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg shadow items-center gap-2">
<i class="fas fa-network-wired"></i> Define DHCP Pool
</a>
</div>
<button id="toggle-desc" class="sm:hidden bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg mb-4 w-full">Show Descriptions</button>
<button id="toggle-desc" class="sm:hidden bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg mb-4 w-full">Show Descriptions</button>
<form action="" method="POST">
<table class="table-auto w-full mb-6">
<thead>
<tr>
<th class="text-center text-gray-400">IP Address</th>
<th class="text-center text-gray-400">Hostname</th>
<th class="text-center text-gray-400 hidden sm:table-cell" id="desc-col-header">Description</th>
<th class="text-center text-gray-700 dark:text-gray-400">IP Address</th>
<th class="text-center text-gray-700 dark:text-gray-400">Hostname</th>
<th class="text-center text-gray-700 dark:text-gray-400 hidden sm:table-cell" id="desc-col-header">Description</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-700">
{% for ip in ip_addresses %}
<tr>
<td class="text-gray-300 font-bold text-center">{{ ip[1] }}</td>
<td class="text-white text-center">
<td class="font-bold text-center">{{ ip[1] }}</td>
<td class="text-center">
{% if ip[2] == 'DHCP' %}
<span class="font-semibold">DHCP</span>
{% elif ip[2] and ip[3] %}
@@ -50,8 +50,8 @@
{{ '' }}
{% endif %}
</td>
<td class="text-white text-left align-top hidden sm:table-cell desc-col">
<textarea readonly rows="1" class="bg-gray-800 text-gray-100 border border-gray-600 rounded w-full resize-y cursor-pointer p-2">{{ ip[4].split('\n')[0] if ip[4] else '' }}</textarea>
<td class="text-left align-top hidden sm:table-cell desc-col">
<textarea readonly rows="1" class="border border-gray-600 rounded w-full resize-y cursor-pointer p-2">{{ ip[4].split('\n')[0] if ip[4] else '' }}</textarea>
</td>
</tr>
{% endfor %}
+9 -9
View File
@@ -8,7 +8,7 @@
<link href="/static/css/output.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col">
<body class="bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen flex flex-col">
{% include 'header.html' %}
<div class="flex-1 flex items-center justify-center mx-4">
<div class="container py-8 max-w-6xl pt-20">
@@ -16,10 +16,10 @@
<form action="/users" method="POST" class="mb-8 bg-gray-800 p-6 rounded-lg shadow-md">
<input type="hidden" name="action" value="add">
<div class="flex flex-col space-y-4">
<input type="text" name="name" placeholder="Name" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" required>
<input type="email" name="email" placeholder="Email Address" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" required>
<input type="password" name="password" placeholder="Password" class="border p-3 rounded-lg bg-gray-900 text-gray-100 border-gray-600" required>
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-4 py-2 rounded-lg">Add User</button>
<input type="text" name="name" placeholder="Name" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" required>
<input type="email" name="email" placeholder="Email Address" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" required>
<input type="password" name="password" placeholder="Password" class="border p-3 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600" required>
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-4 py-2 rounded-lg">Add User</button>
</div>
</form>
<h2 class="text-xl font-bold mb-4">Existing Users</h2>
@@ -29,10 +29,10 @@
<form action="/users" method="POST" class="flex flex-row items-center space-x-2">
<input type="hidden" name="action" value="edit">
<input type="hidden" name="user_id" value="{{ user[0] }}">
<input type="text" name="name" value="{{ user[1] }}" class="border p-2 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-52">
<input type="email" name="email" value="{{ user[2] }}" class="border p-2 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-80">
<input type="password" name="password" placeholder="New Password (leave blank to keep)" class="border p-2 rounded-lg bg-gray-900 text-gray-100 border-gray-600 w-80">
<button type="submit" class="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-500 text-white px-3 py-1 rounded-lg">Save</button>
<input type="text" name="name" value="{{ user[1] }}" class="border p-2 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-52">
<input type="email" name="email" value="{{ user[2] }}" class="border p-2 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-80">
<input type="password" name="password" placeholder="New Password (leave blank to keep)" class="border p-2 rounded-lg bg-gray-300 text-gray-900 dark:bg-gray-900 dark:text-gray-100 border-gray-600 w-80">
<button type="submit" class="bg-gradient-to-r from-gray-200 to-gray-200 dark:from-gray-500 dark:to-gray-700 px-3 py-1 rounded-lg">Save</button>
</form>
<form action="/users" method="POST" onsubmit="return confirm('Are you sure you want to delete this user?');">
<input type="hidden" name="action" value="delete">