From 720ada24862bc0f28c724ad0080cf717e61fb0f4 Mon Sep 17 00:00:00 2001 From: Mary Salvi Date: Tue, 23 Jun 2026 15:29:40 -0400 Subject: [PATCH 1/4] Add component models-list wireframe --- .../net_maestro/partials/models_list.html | 40 ++++++++++++++++++ .../templates/net_maestro/shared/sidebar.html | 15 +++++++ net_maestro/core/views.py | 41 +++++++++++++++++++ net_maestro/urls.py | 5 +++ 4 files changed, 101 insertions(+) create mode 100644 net_maestro/core/templates/net_maestro/partials/models_list.html diff --git a/net_maestro/core/templates/net_maestro/partials/models_list.html b/net_maestro/core/templates/net_maestro/partials/models_list.html new file mode 100644 index 0000000..029898f --- /dev/null +++ b/net_maestro/core/templates/net_maestro/partials/models_list.html @@ -0,0 +1,40 @@ +
+
+
+
+

Available Component Models

+
+
+ +
+ {% for model in models %} +
+
+
+
+ +

{{ model.name }}

+
+
+
{{ model.type }}
+
+
+

{{model.description}}

+
+ {% for param in model.parameters %} +
{{ param }}
+ {% endfor %} +
+
+
+ {% empty %} +
+
+ +

No models available

+
+
+ {% endfor %} +
+
+
diff --git a/net_maestro/core/templates/net_maestro/shared/sidebar.html b/net_maestro/core/templates/net_maestro/shared/sidebar.html index 12f59b9..6543e62 100644 --- a/net_maestro/core/templates/net_maestro/shared/sidebar.html +++ b/net_maestro/core/templates/net_maestro/shared/sidebar.html @@ -1,6 +1,21 @@
diff --git a/net_maestro/core/views.py b/net_maestro/core/views.py index 28729c4..a3a33f9 100644 --- a/net_maestro/core/views.py +++ b/net_maestro/core/views.py @@ -378,6 +378,48 @@ def models_list(request: HttpRequest) -> HttpResponse: return render(request, "net_maestro/index.html", context) +def _new_model_form_context() -> dict[str, object]: + """Return read-only demo context for the new custom component form. + + TODO: Replace this static host example with a real Django form bound to model-backed + base component choices and custom component defaults. + TODO: Keep field metadata in the view so the template can render form sections without + knowing which fields belong to hosts, routers, or switches. + """ + return { + "form_sections": [ + { + "title": "Model", + "fields": [ + {"label": "Name", "value": "New Model"}, + {"label": "Component Type", "value": "Router"}, + {"label": "Engine", "value": "PDES (CODES)"}, + {"label": "Description", "value": "Simple point-to-point router."}, + { + "label": "Parameters", + "value": "routing, latency, bandwidth, chunk_size, vc_size", + }, + ], + }, + ], + } + + +def model_create(request: HttpRequest) -> HttpResponse: + """Render the demonstration form for creating a new model component. + + TODO: Render and process a real form for creating a new model. + TODO: Validate component fields by type, especially host-only traffic fields. + TODO: Return either a full-page redirect or an HTMX partial update after successful create. + """ + context = _new_model_form_context() + partial_template = "net_maestro/partials/model_form.html" + if request.headers.get("HX-Request"): + return render(request, partial_template, context) + context.update({"active_page": "modelsList", "partial_template": partial_template}) + return render(request, "net_maestro/index.html", context) + + def page_view( request: HttpRequest, partial: str, diff --git a/net_maestro/urls.py b/net_maestro/urls.py index 06b6321..cddf41e 100644 --- a/net_maestro/urls.py +++ b/net_maestro/urls.py @@ -83,6 +83,11 @@ views.models_list, name="models-list-partial", ), + path( + "models/new-model", + views.model_create, + name="model-create", + ), ] if settings.DEBUG: From 392f930b55fee326bf5261b38f37ed354985e679 Mon Sep 17 00:00:00 2001 From: Mary Salvi Date: Thu, 30 Jul 2026 14:49:14 -0400 Subject: [PATCH 3/4] Add component_model Django models --- net_maestro/core/admin/__init__.py | 2 + net_maestro/core/admin/component_model.py | 14 +++++++ .../migrations/0010_add_component_model.py | 37 +++++++++++++++++++ net_maestro/core/models/__init__.py | 2 + net_maestro/core/models/component_model.py | 25 +++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 net_maestro/core/admin/component_model.py create mode 100644 net_maestro/core/migrations/0010_add_component_model.py create mode 100644 net_maestro/core/models/component_model.py diff --git a/net_maestro/core/admin/__init__.py b/net_maestro/core/admin/__init__.py index 65c5eb3..601d9c7 100644 --- a/net_maestro/core/admin/__init__.py +++ b/net_maestro/core/admin/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +from .component_model import ComponentModelAdmin from .event_file import EventFileAdmin from .event_record import EventRecordAdmin from .model_file import ModelFileAdmin @@ -12,6 +13,7 @@ from .simulation_pe_record import SimulationPeRecordAdmin __all__ = [ + "ComponentModelAdmin", "EventFileAdmin", "EventRecordAdmin", "ModelFileAdmin", diff --git a/net_maestro/core/admin/component_model.py b/net_maestro/core/admin/component_model.py new file mode 100644 index 0000000..2ddefd7 --- /dev/null +++ b/net_maestro/core/admin/component_model.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from django.contrib import admin + +from net_maestro.core.models import ComponentModel + + +@admin.register(ComponentModel) +class ComponentModelAdmin(admin.ModelAdmin): + list_display = ["id", "name", "component_type", "description", "engine", "parameters"] + list_filter = [ + "component_type", + "engine", + ] diff --git a/net_maestro/core/migrations/0010_add_component_model.py b/net_maestro/core/migrations/0010_add_component_model.py new file mode 100644 index 0000000..6201712 --- /dev/null +++ b/net_maestro/core/migrations/0010_add_component_model.py @@ -0,0 +1,37 @@ +# Generated by Django 6.0.6 on 2026-08-05 21:34 +from __future__ import annotations + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0009_pholdsimulationlprecord"), + ] + + operations = [ + migrations.CreateModel( + name="ComponentModel", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("name", models.CharField(max_length=255)), + ( + "component_type", + models.CharField( + choices=[("host", "Host"), ("router", "Router"), ("switch", "Switch")], + max_length=100, + ), + ), + ("description", models.TextField(blank=True, null=True)), + ("engine", models.CharField(max_length=100)), + ("parameters", models.JSONField(blank=True, null=True)), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ], + ), + ] diff --git a/net_maestro/core/models/__init__.py b/net_maestro/core/models/__init__.py index c58d1a7..5ac82b4 100644 --- a/net_maestro/core/models/__init__.py +++ b/net_maestro/core/models/__init__.py @@ -1,5 +1,6 @@ from __future__ import annotations +from .component_model import ComponentModel from .event_file import EventFile from .event_record import EventRecord from .model_file import ModelFile @@ -12,6 +13,7 @@ from .simulation_pe_record import SimulationPeRecord __all__ = [ + "ComponentModel", "EventFile", "EventRecord", "ModelFile", diff --git a/net_maestro/core/models/component_model.py b/net_maestro/core/models/component_model.py new file mode 100644 index 0000000..f13dbbe --- /dev/null +++ b/net_maestro/core/models/component_model.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from django.db import models + + +class ComponentType(models.TextChoices): + HOST = "host", "Host" + ROUTER = "router", "Router" + SWITCH = "switch", "Switch" + + +class ComponentModel(models.Model): + # TODO: Verify that these fields are correct. + # Would we want to extend for specific types? ie. Host/ Router + # TODO: Revisit when we have a User model: created_by, updated_by + name = models.CharField(max_length=255) + component_type = models.CharField(max_length=100, choices=ComponentType.choices) + description = models.TextField(blank=True) + engine = models.CharField(max_length=100) + parameters = models.JSONField(blank=True, null=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self) -> str: + return f"ComponentModel {self.name}" From fb6a21bdcf66fc8548e6777e5d6726b871df047f Mon Sep 17 00:00:00 2001 From: Mary Salvi Date: Wed, 5 Aug 2026 18:17:34 -0400 Subject: [PATCH 4/4] Update base models view for components page --- net_maestro/core/views.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net_maestro/core/views.py b/net_maestro/core/views.py index a3a33f9..7d8ff99 100644 --- a/net_maestro/core/views.py +++ b/net_maestro/core/views.py @@ -61,15 +61,15 @@ def _custom_component_context() -> dict[str, object]: "icon_class": "ri-organization-chart", }, { - "name": "ESNet Host", + "name": "nw-lp", "type": "Host", - "engine": "PDES (ROSS)", + "engine": "PDES (CODES)", "icon_class": "ri-server-line", }, { - "name": "ESNet Router", + "name": "simplep2p", "type": "Router", - "engine": "PDES (ROSS)", + "engine": "PDES (CODES)", "icon_class": "ri-router-fill", }, ], @@ -78,7 +78,7 @@ def _custom_component_context() -> dict[str, object]: "id": 1, "name": "High Traffic Host", "type": "Host", - "base_model": "ESNet Host", + "base_model": "nw-lp", "icon_class": "ri-server-line", "color_class": "text-primary", "badge_class": "badge-primary", @@ -94,7 +94,7 @@ def _custom_component_context() -> dict[str, object]: "id": 2, "name": "Regional Backbone Router", "type": "Router", - "base_model": "ESNet Router", + "base_model": "simplep2p", "icon_class": "ri-router-fill", "color_class": "text-secondary", "badge_class": "badge-secondary", @@ -103,7 +103,7 @@ def _custom_component_context() -> dict[str, object]: {"label": "Egress Bandwidth", "value": "400 Gbps"}, {"label": "Ingress Latency", "value": "1.25 ms"}, {"label": "Egress Latency", "value": "1.25 ms"}, - {"label": "Engine", "value": "PDES (ROSS)"}, + {"label": "Engine", "value": "PDES (CODES)"}, {"label": "Role", "value": "Backbone Transit"}, ], },