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}" diff --git a/net_maestro/core/templates/net_maestro/partials/model_form.html b/net_maestro/core/templates/net_maestro/partials/model_form.html new file mode 100644 index 0000000..bde61ed --- /dev/null +++ b/net_maestro/core/templates/net_maestro/partials/model_form.html @@ -0,0 +1,95 @@ +
+
+ {% comment %} + This page is a demonstration-only create form for `/models-list/new-model`. + The fields are read-only and are populated by model_create() via + _model_form_context(). Depending on further specs the fields and details here might change. + Save and Cancel intentionally navigate back to the + custom component list without persisting anything. + + TODO: Replace the read-only display with a real Django form when models + are backed properly by django models. + TODO: Convert the save action to POST and persist the new model before returning + to `/models/`. + {% endcomment %} +
+
+
+ + Models + + + New Model +
+

+ Model +

+
+ +
+ +
+
+
+
+
+ +
+

New Model

+
+
+
+ + {% for section in form_sections %} +
+

{{ section.title }}

+
+ {% for field in section.fields %} + + {% endfor %} +
+
+ {% endfor %} +
+
+
+
+
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..1a2b9d2 --- /dev/null +++ b/net_maestro/core/templates/net_maestro/partials/models_list.html @@ -0,0 +1,51 @@ +
+
+
+
+

Available Component Models

+
+ + + New Component Model + +
+ +
+ {% 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 @@