diff --git a/app/__init__.py b/app/__init__.py index 07e98e0..196dcb1 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,6 +2,10 @@ from flask import Flask, g, redirect, url_for, render_template, session import datetime import os import secrets +from app.core.extensions import db, migrate, login_manager, bcrypt, limiter +from app.core.csrf_utils import init_csrf +from app.core.auth import User, load_user +from app.core.context_processors import inject_breadcrumbs def create_app(config_name="development"): @@ -20,9 +24,6 @@ def create_app(config_name="development"): app.config['SECRET_KEY'] = secrets.token_hex(32) # Initialize extensions - from app.core.extensions import db, migrate, login_manager, bcrypt, limiter - from app.core.csrf_utils import init_csrf - db.init_app(app) migrate.init_app(app, db) login_manager.init_app(app) @@ -31,8 +32,6 @@ def create_app(config_name="development"): limiter.init_app(app) # Initialize login manager - from app.core.auth import User - @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) @@ -119,4 +118,7 @@ def create_app(config_name="development"): print(f"CSRF header name: {app.config.get('WTF_CSRF_HEADERS')}") return response + # Register context processors + app.context_processor(inject_breadcrumbs) + return app diff --git a/app/core/context_processors.py b/app/core/context_processors.py new file mode 100644 index 0000000..8f7c003 --- /dev/null +++ b/app/core/context_processors.py @@ -0,0 +1,126 @@ +from flask import request, url_for +from app.core.models import Server, App, Subnet + +def inject_breadcrumbs(): + """Add breadcrumbs to template context based on current route""" + breadcrumbs = [] + path_parts = request.path.strip('/').split('/') + + # Skip breadcrumbs for the dashboard home + if request.endpoint == 'dashboard.dashboard_home': + return {'breadcrumbs': []} + + # Handle IPAM routes + if 'ipam' in path_parts: + # Base IPAM breadcrumb + breadcrumbs.append({ + 'title': 'IPAM', + 'url': url_for('ipam.ipam_home') + }) + + # Handle subnet routes within IPAM + if 'subnet' in path_parts: + try: + if 'new' in path_parts: + breadcrumbs.append({ + 'title': 'New Subnet', + 'url': '#' + }) + else: + subnet_id = int(path_parts[path_parts.index('subnet') + 1]) + subnet = Subnet.query.get(subnet_id) + if subnet: + breadcrumbs.append({ + 'title': subnet.cidr, + 'url': url_for('ipam.subnet_view', subnet_id=subnet.id) + }) + + if 'edit' in path_parts: + breadcrumbs.append({ + 'title': 'Edit', + 'url': '#' + }) + except (ValueError, IndexError): + pass + + # Handle server routes + elif 'server' in path_parts: + try: + # Add Servers base breadcrumb + breadcrumbs.append({ + 'title': 'Servers', + 'url': url_for('dashboard.server_list') + }) + + if 'new' in path_parts: + breadcrumbs.append({ + 'title': 'New Server', + 'url': '#' + }) + else: + server_id = int(path_parts[path_parts.index('server') + 1]) + server = Server.query.get(server_id) + if server: + # If we're viewing a specific server + breadcrumbs.append({ + 'title': server.hostname, + 'url': url_for('dashboard.server_view', server_id=server.id) + }) + + if 'edit' in path_parts: + breadcrumbs.append({ + 'title': 'Edit', + 'url': '#' + }) + except (ValueError, IndexError): + pass + + # Handle app routes + elif 'app' in path_parts: + try: + # Add Applications base breadcrumb + breadcrumbs.append({ + 'title': 'Applications', + 'url': url_for('dashboard.app_list') + }) + + # For new app + if 'new' in path_parts: + breadcrumbs.append({ + 'title': 'New Application', + 'url': '#' + }) + else: + app_id = int(path_parts[path_parts.index('app') + 1]) + app = App.query.get(app_id) + if app: + server = Server.query.get(app.server_id) + + if server: + breadcrumbs.append({ + 'title': server.hostname, + 'url': url_for('dashboard.server_view', server_id=server.id) + }) + + # If we're viewing a specific app + breadcrumbs.append({ + 'title': app.name, + 'url': url_for('dashboard.app_view', app_id=app.id) + }) + + if 'edit' in path_parts: + breadcrumbs.append({ + 'title': 'Edit', + 'url': '#' + }) + except (ValueError, IndexError): + pass + + # Handle overview route + elif 'overview' in path_parts: + breadcrumbs.append({ + 'title': 'Infrastructure Overview', + 'url': url_for('dashboard.overview') + }) + + return {'breadcrumbs': breadcrumbs} diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py index 26351d7..517ee5a 100644 --- a/app/routes/dashboard.py +++ b/app/routes/dashboard.py @@ -529,3 +529,75 @@ def settings(): return redirect(url_for("dashboard.settings")) return render_template("dashboard/settings.html", title="User Settings") + + +@bp.route("/overview") +@login_required +def overview(): + """Hierarchical overview of subnets, servers, and applications""" + # Get all subnets with their servers + subnets = Subnet.query.all() + + # Get servers without subnets + standalone_servers = Server.query.filter(Server.subnet_id.is_(None)).all() + + # Create a hierarchical structure + hierarchy = { + 'subnets': [], + 'standalone_servers': [] + } + + # Organize subnets and their servers + for subnet in subnets: + subnet_data = { + 'id': subnet.id, + 'cidr': subnet.cidr, + 'description': subnet.description, + 'location': subnet.location, + 'servers': [] + } + + for server in subnet.servers: + server_data = { + 'id': server.id, + 'hostname': server.hostname, + 'ip_address': server.ip_address, + 'apps': [] + } + + for app in server.apps: + app_data = { + 'id': app.id, + 'name': app.name, + 'ports': app.ports + } + server_data['apps'].append(app_data) + + subnet_data['servers'].append(server_data) + + hierarchy['subnets'].append(subnet_data) + + # Organize standalone servers + for server in standalone_servers: + server_data = { + 'id': server.id, + 'hostname': server.hostname, + 'ip_address': server.ip_address, + 'apps': [] + } + + for app in server.apps: + app_data = { + 'id': app.id, + 'name': app.name, + 'ports': app.ports + } + server_data['apps'].append(app_data) + + hierarchy['standalone_servers'].append(server_data) + + return render_template( + "dashboard/overview.html", + title="Infrastructure Overview", + hierarchy=hierarchy + ) diff --git a/app/templates/components/breadcrumbs.html b/app/templates/components/breadcrumbs.html new file mode 100644 index 0000000..f071aab --- /dev/null +++ b/app/templates/components/breadcrumbs.html @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/app/templates/dashboard/app_form.html b/app/templates/dashboard/app_form.html index d2f53b5..62ae64a 100644 --- a/app/templates/dashboard/app_form.html +++ b/app/templates/dashboard/app_form.html @@ -72,9 +72,10 @@ {% if edit_mode and app.ports %} {% for port in app.ports %} - + +
+