feat: add devices by tag page

This commit is contained in:
2025-12-05 01:37:45 +00:00
parent 8242e9d758
commit 9c0e6d035c
3 changed files with 99 additions and 1 deletions
+34
View File
@@ -2071,6 +2071,39 @@ def register_routes(app):
site_devices[site].append({'id': device_id, 'name': name, 'description': description})
return render_with_user('devices_by_type.html', device_type=device_type, icon_class=icon_class, site_devices=site_devices)
@app.route('/devices/tag/<int:tag_id>')
@permission_required('view_devices')
def devices_by_tag(tag_id):
from flask import current_app
with get_db_connection(current_app) as conn:
cursor = conn.cursor()
cursor.execute('SELECT id, name, color FROM Tag WHERE id = %s', (tag_id,))
row = cursor.fetchone()
if not row:
return f"Tag not found", 404
tag_id_db, tag_name, tag_color = row
cursor.execute('''
SELECT DISTINCT Device.id, Device.name, Device.description, Subnet.site
FROM Device
JOIN DeviceTag ON Device.id = DeviceTag.device_id
LEFT JOIN DeviceIPAddress ON Device.id = DeviceIPAddress.device_id
LEFT JOIN IPAddress ON DeviceIPAddress.ip_id = IPAddress.id
LEFT JOIN Subnet ON IPAddress.subnet_id = Subnet.id
WHERE DeviceTag.tag_id = %s
''', (tag_id,))
devices = cursor.fetchall()
seen_ids = set()
site_devices = {}
for device_id, name, description, site in devices:
if device_id in seen_ids:
continue
seen_ids.add(device_id)
site = site or 'Unassigned'
if site not in site_devices:
site_devices[site] = []
site_devices[site].append({'id': device_id, 'name': name, 'description': description})
return render_with_user('devices_by_tag.html', tag_name=tag_name, tag_color=tag_color, site_devices=site_devices)
@app.route('/racks')
@permission_required('view_racks')
def racks():
@@ -3865,6 +3898,7 @@ def register_routes(app):
app.add_url_rule('/device_type_stats', 'device_type_stats', device_type_stats)
app.add_url_rule('/device_types', 'device_types', device_types, methods=['GET', 'POST'])
app.add_url_rule('/devices/type/<device_type>', 'devices_by_type', devices_by_type)
app.add_url_rule('/devices/tag/<int:tag_id>', 'devices_by_tag', devices_by_tag)
app.add_url_rule('/racks', 'racks', racks)
app.add_url_rule('/rack/add', 'add_rack', add_rack, methods=['GET', 'POST'])
app.add_url_rule('/rack/<int:rack_id>', 'rack', rack)
+64
View File
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ tag_name }} - Tagged Devices</title>
<link rel="icon" type="image/png" href="{{ LOGO_PNG }}">
<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-300 text-gray-900 dark:bg-zinc-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">
<div class="flex items-center mb-6 relative">
<a href="/tags" class="absolute left-0 bg-gray-200 hover:bg-gray-400 dark:bg-zinc-700 dark:hover:bg-zinc-600 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">
<div class="flex items-center justify-center space-x-2">
<div class="w-5 h-5 rounded-full border border-gray-600" style="background-color: {{ tag_color }}"></div>
<span>{{ tag_name }} - Tagged Devices</span>
</div>
</h1>
</div>
{% if site_devices %}
{% for site, devices in site_devices.items() %}
<div class="mb-8">
<h2 class="text-xl font-bold mb-4 dark:text-white">{{ site }}</h2>
<div class="bg-gray-200 dark:bg-zinc-800 rounded-lg shadow-md p-4">
<table class="w-full table-auto mb-2">
<thead>
<tr class="bg-gray-200 dark:bg-zinc-700">
<th class="px-4 py-2 text-left">Device Name</th>
<th class="px-4 py-2 text-left">Description</th>
</tr>
</thead>
<tbody>
{% 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 dark:text-white hover:cursor-pointer">{{ device.name }}</a>
</td>
<td class="px-4 py-3">{{ device.description or '' }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr class="bg-gray-200 dark:bg-zinc-900 font-bold">
<td class="px-4 py-2 text-right" colspan="2">Total: {{ devices|length }}</td>
</tr>
</tfoot>
</table>
</div>
</div>
{% endfor %}
{% else %}
<div class="bg-gray-200 dark:bg-zinc-800 rounded-lg shadow-md p-8 text-center">
<p class="text-gray-500">No devices found with this tag.</p>
</div>
{% endif %}
</div>
</div>
</body>
</html>
+1 -1
View File
@@ -58,7 +58,7 @@
</td>
<td class="p-3 text-center">
{% if tag.device_count > 0 %}
<a href="/api/v1/devices/by-tag/{{ tag.name }}" class="text-blue-400 hover:text-blue-600">
<a href="/devices/tag/{{ tag.id }}" class="text-blue-400 hover:text-blue-600 hover:cursor-pointer">
{{ tag.device_count }}
</a>
{% else %}