Render SoftwareProduct manufacturer consistently (#59)
Closes #58 Signed-off-by: wkoot <3715211+wkoot@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
### Changed
|
||||
|
||||
* Support NetBox v4.2.3 (#51)
|
||||
* Render objects consistently (#58)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ class SoftwareProductSerializer(NetBoxModelSerializer):
|
||||
"display",
|
||||
"url",
|
||||
"name",
|
||||
"description",
|
||||
"manufacturer",
|
||||
"description",
|
||||
"tags",
|
||||
@@ -60,8 +61,7 @@ class SoftwareProductSerializer(NetBoxModelSerializer):
|
||||
brief_fields = ("id", "display", "url", "name", "description")
|
||||
|
||||
def get_display(self, obj):
|
||||
# TODO - does not match form and filter views, display manufacturer separately?
|
||||
return f"{obj.manufacturer} - {obj}"
|
||||
return f"{obj}"
|
||||
|
||||
|
||||
class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
|
||||
@@ -87,7 +87,7 @@ class SoftwareProductInstallationSerializer(NetBoxModelSerializer):
|
||||
"created",
|
||||
"last_updated",
|
||||
)
|
||||
brief_fields = ("id", "display", "url", "name")
|
||||
brief_fields = ("id", "display", "url")
|
||||
|
||||
def get_display(self, obj):
|
||||
return f"{obj}"
|
||||
@@ -104,6 +104,7 @@ class SoftwareProductVersionSerializer(NetBoxModelSerializer):
|
||||
"display",
|
||||
"url",
|
||||
"name",
|
||||
"description",
|
||||
"release_date",
|
||||
"documentation_url",
|
||||
"end_of_support",
|
||||
@@ -118,7 +119,7 @@ class SoftwareProductVersionSerializer(NetBoxModelSerializer):
|
||||
"created",
|
||||
"last_updated",
|
||||
)
|
||||
brief_fields = ("id", "display", "url", "name")
|
||||
brief_fields = ("id", "display", "url", "name", "description")
|
||||
|
||||
def get_display(self, obj):
|
||||
return f"{obj}"
|
||||
|
||||
@@ -42,6 +42,7 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
|
||||
"""Filter capabilities for SoftwareProductVersion instances."""
|
||||
|
||||
name = CharFilter(lookup_expr="icontains")
|
||||
description = CharFilter(lookup_expr="icontains")
|
||||
filename = CharFilter(lookup_expr="icontains")
|
||||
|
||||
release_type = MultipleChoiceFilter(choices=SoftwareReleaseTypes.choices)
|
||||
@@ -66,6 +67,7 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
|
||||
return queryset
|
||||
qs_filter = (
|
||||
Q(name__icontains=value)
|
||||
| Q(description__icontains=value)
|
||||
| Q(software_product__name__icontains=value)
|
||||
| Q(software_product__manufacturer__name__icontains=value)
|
||||
| Q(comments__icontains=value)
|
||||
@@ -130,6 +132,7 @@ class SoftwareLicenseFilterSet(NetBoxModelFilterSet):
|
||||
return queryset
|
||||
qs_filter = (
|
||||
Q(name__icontains=value)
|
||||
| Q(description__icontains=value)
|
||||
| Q(software_product__name__icontains=value)
|
||||
| Q(version__name__icontains=value)
|
||||
| Q(installation__device__name__icontains=value)
|
||||
|
||||
@@ -74,7 +74,14 @@ class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
|
||||
fieldsets = (
|
||||
FieldSet("q", "filter_id", "tag"),
|
||||
FieldSet(
|
||||
"name", "description", "type", "stored_location", "support", "software_product", "version", "installation"
|
||||
"name",
|
||||
"description",
|
||||
"type",
|
||||
"stored_location",
|
||||
"support",
|
||||
"software_product_id",
|
||||
"version_id",
|
||||
"installation_id",
|
||||
),
|
||||
)
|
||||
selector_fields = ("q", "filter_id", "name")
|
||||
@@ -87,18 +94,20 @@ class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
|
||||
stored_location = CharField(required=False)
|
||||
support = ChoiceField(required=False, choices=BOOLEAN_WITH_BLANK_CHOICES)
|
||||
|
||||
software_product = DynamicModelMultipleChoiceField(
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
)
|
||||
version = DynamicModelMultipleChoiceField(
|
||||
version_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
required=False,
|
||||
label="Version",
|
||||
)
|
||||
installation = DynamicModelMultipleChoiceField(
|
||||
installation_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductInstallation.objects.all(),
|
||||
required=False,
|
||||
label="Installation",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
|
||||
model = SoftwareProduct
|
||||
fieldsets = (
|
||||
FieldSet("q", "filter_id", "tag"),
|
||||
FieldSet("name", "description", "manufacturer"),
|
||||
FieldSet("name", "description", "manufacturer_id"),
|
||||
)
|
||||
selector_fields = ("q", "filter_id", "name")
|
||||
|
||||
@@ -45,9 +45,10 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
|
||||
|
||||
name = CharField(required=False)
|
||||
description = CharField(required=False)
|
||||
manufacturer = DynamicModelMultipleChoiceField(
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label="Manufacturer",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -69,33 +69,36 @@ class SoftwareProductInstallationFilterForm(NetBoxModelFilterSetForm):
|
||||
model = SoftwareProductInstallation
|
||||
fieldsets = (
|
||||
FieldSet("q", "filter_id", "tag"),
|
||||
FieldSet("device", "virtualmachine", "cluster", "software_product", "version"),
|
||||
FieldSet("device_id", "virtualmachine_id", "cluster_id", "software_product_id", "version_id"),
|
||||
)
|
||||
selector_fields = ("filter_id", "q")
|
||||
|
||||
tag = TagFilterField(model)
|
||||
|
||||
device = DynamicModelMultipleChoiceField(
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
required=False,
|
||||
label="Device",
|
||||
)
|
||||
virtualmachine = DynamicModelMultipleChoiceField(
|
||||
virtualmachine_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
required=False,
|
||||
label="Virtual Machine",
|
||||
)
|
||||
cluster = DynamicModelMultipleChoiceField(
|
||||
cluster_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False,
|
||||
label="Cluster",
|
||||
)
|
||||
software_product = DynamicModelMultipleChoiceField(
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
)
|
||||
version = DynamicModelMultipleChoiceField(
|
||||
version_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProductVersion.objects.all(),
|
||||
required=False,
|
||||
label="Version",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ class SoftwareProductVersionForm(NetBoxModelForm):
|
||||
model = SoftwareProductVersion
|
||||
fields = (
|
||||
"name",
|
||||
"description",
|
||||
"software_product",
|
||||
"release_date",
|
||||
"documentation_url",
|
||||
@@ -50,22 +51,24 @@ class SoftwareProductVersionFilterForm(NetBoxModelFilterSetForm):
|
||||
model = SoftwareProductVersion
|
||||
fieldsets = (
|
||||
FieldSet("q", "filter_id", "tag"),
|
||||
FieldSet("name", "filename", "release_type", "manufacturer", "software_product"),
|
||||
FieldSet("name", "description", "filename", "release_type", "manufacturer_id", "software_product_id"),
|
||||
)
|
||||
selector_fields = ("q", "filter_id", "name")
|
||||
|
||||
tag = TagFilterField(model)
|
||||
|
||||
name = CharField(required=False)
|
||||
description = CharField(required=False)
|
||||
filename = CharField(required=False)
|
||||
|
||||
release_type = MultipleChoiceField(required=False, choices=SoftwareReleaseTypes.choices)
|
||||
|
||||
manufacturer = DynamicModelMultipleChoiceField(
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label="Manufacturer",
|
||||
)
|
||||
software_product = DynamicModelMultipleChoiceField(
|
||||
software_product_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SoftwareProduct.objects.all(),
|
||||
required=False,
|
||||
label="Software Product",
|
||||
@@ -77,6 +80,7 @@ class SoftwareProductVersionBulkImportForm(NetBoxModelImportForm):
|
||||
model = SoftwareProductVersion
|
||||
fields = (
|
||||
"name",
|
||||
"description",
|
||||
"software_product",
|
||||
"release_date",
|
||||
"end_of_support",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.5 on 2025-02-17 21:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("netbox_slm", "0008_software_release_types_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="softwareproductversion",
|
||||
name="description",
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -33,7 +33,7 @@ class SoftwareProduct(NetBoxModel):
|
||||
|
||||
def get_installation_count(self):
|
||||
count = SoftwareProductInstallation.objects.filter(software_product_id=self.pk).count()
|
||||
query_string = urlencode(dict(software_product=self.pk))
|
||||
query_string = urlencode(dict(software_product_id=self.pk))
|
||||
search_target = reverse("plugins:netbox_slm:softwareproductinstallation_list")
|
||||
# Can be composed directly with reverse(query=) in Django 5.2, see https://code.djangoproject.com/ticket/25582
|
||||
return format_html(f"<a href='{search_target}?{query_string}'>{count}</a>") if count else "0"
|
||||
@@ -50,6 +50,7 @@ class SoftwareProductVersion(NetBoxModel):
|
||||
name = models.CharField(max_length=64)
|
||||
comments = models.TextField(blank=True)
|
||||
|
||||
description = models.CharField(max_length=255, null=True, blank=True)
|
||||
release_date = models.DateField(null=True, blank=True)
|
||||
documentation_url = LaxURLField(max_length=1024, null=True, blank=True)
|
||||
end_of_support = models.DateField(null=True, blank=True)
|
||||
@@ -78,7 +79,7 @@ class SoftwareProductVersion(NetBoxModel):
|
||||
|
||||
def get_installation_count(self):
|
||||
count = SoftwareProductInstallation.objects.filter(version_id=self.pk).count()
|
||||
query_string = urlencode(dict(version=self.pk))
|
||||
query_string = urlencode(dict(version_id=self.pk))
|
||||
search_target = reverse("plugins:netbox_slm:softwareproductinstallation_list")
|
||||
# Can be composed directly with reverse(query=) in Django 5.2, see https://code.djangoproject.com/ticket/25582
|
||||
return format_html(f"<a href='{search_target}?{query_string}'>{count}</a>") if count else "0"
|
||||
|
||||
+10
-30
@@ -20,8 +20,8 @@ class SoftwareProductTable(NetBoxTable):
|
||||
fields = (
|
||||
"pk",
|
||||
"name",
|
||||
"manufacturer",
|
||||
"description",
|
||||
"manufacturer",
|
||||
"installations",
|
||||
"tags",
|
||||
)
|
||||
@@ -29,16 +29,9 @@ class SoftwareProductTable(NetBoxTable):
|
||||
"pk",
|
||||
"name",
|
||||
"manufacturer",
|
||||
"description",
|
||||
"installations",
|
||||
"tags",
|
||||
)
|
||||
sequence = (
|
||||
"manufacturer",
|
||||
"name",
|
||||
"description",
|
||||
"installations",
|
||||
)
|
||||
|
||||
def order_installations(self, queryset, is_descending):
|
||||
queryset = queryset.annotate(count=Count("softwareproductinstallation__id")).order_by(
|
||||
@@ -63,6 +56,7 @@ class SoftwareProductVersionTable(NetBoxTable):
|
||||
fields = (
|
||||
"pk",
|
||||
"name",
|
||||
"description",
|
||||
"software_product",
|
||||
"manufacturer",
|
||||
"release_date",
|
||||
@@ -74,18 +68,12 @@ class SoftwareProductVersionTable(NetBoxTable):
|
||||
default_columns = (
|
||||
"pk",
|
||||
"name",
|
||||
"software_product",
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"release_date",
|
||||
"installations",
|
||||
"tags",
|
||||
)
|
||||
sequence = (
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"name",
|
||||
"installations",
|
||||
)
|
||||
|
||||
def order_installations(self, queryset, is_descending):
|
||||
queryset = queryset.annotate(count=Count("softwareproductinstallation__id")).order_by(
|
||||
@@ -98,13 +86,9 @@ class SoftwareProductInstallationTable(NetBoxTable):
|
||||
"""Table for displaying SoftwareProductInstallation objects."""
|
||||
|
||||
pk = ToggleColumn()
|
||||
name = tables.LinkColumn()
|
||||
|
||||
device = tables.Column(accessor="device", linkify=True)
|
||||
virtualmachine = tables.Column(accessor="virtualmachine", linkify=True)
|
||||
cluster = tables.Column(accessor="cluster", linkify=True)
|
||||
platform = tables.Column(accessor="platform", linkify=True)
|
||||
type = tables.Column(accessor="render_type")
|
||||
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", linkify=True)
|
||||
version = tables.Column(accessor="version", linkify=True)
|
||||
|
||||
@@ -114,9 +98,9 @@ class SoftwareProductInstallationTable(NetBoxTable):
|
||||
model = SoftwareProductInstallation
|
||||
fields = (
|
||||
"pk",
|
||||
"name",
|
||||
"platform",
|
||||
"type",
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"version",
|
||||
"tags",
|
||||
@@ -125,6 +109,7 @@ class SoftwareProductInstallationTable(NetBoxTable):
|
||||
"pk",
|
||||
"platform",
|
||||
"type",
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"version",
|
||||
"tags",
|
||||
@@ -144,10 +129,6 @@ class SoftwareProductInstallationTable(NetBoxTable):
|
||||
queryset_union = device_annotate.union(vm_annotate).union(cluster_annotate)
|
||||
return queryset_union.order_by(f"{'-' if is_descending else ''}render_type"), True
|
||||
|
||||
def render_software_product(self, value, **kwargs):
|
||||
# TODO - does not match form and filter views, display manufacturer separately?
|
||||
return f"{kwargs['record'].software_product.manufacturer.name} - {value}"
|
||||
|
||||
|
||||
class SoftwareLicenseTable(NetBoxTable):
|
||||
"""Table for displaying SoftwareLicense objects."""
|
||||
@@ -158,6 +139,7 @@ class SoftwareLicenseTable(NetBoxTable):
|
||||
type = tables.Column()
|
||||
stored_location = tables.Column(accessor="stored_location_txt", linkify=lambda record: record.stored_location_url)
|
||||
|
||||
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
|
||||
software_product = tables.Column(accessor="software_product", linkify=True)
|
||||
version = tables.Column(accessor="version", linkify=True)
|
||||
installation = tables.Column(accessor="installation", linkify=True)
|
||||
@@ -174,6 +156,7 @@ class SoftwareLicenseTable(NetBoxTable):
|
||||
"stored_location",
|
||||
"start_date",
|
||||
"expiration_date",
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"version",
|
||||
"installation",
|
||||
@@ -184,15 +167,12 @@ class SoftwareLicenseTable(NetBoxTable):
|
||||
default_columns = (
|
||||
"pk",
|
||||
"name",
|
||||
"expiration_date",
|
||||
"manufacturer",
|
||||
"software_product",
|
||||
"installation",
|
||||
"expiration_date",
|
||||
"tags",
|
||||
)
|
||||
|
||||
def render_software_product(self, value, **kwargs):
|
||||
# TODO - does not match form and filter views, display manufacturer separately?
|
||||
return f"{kwargs['record'].software_product.manufacturer.name} - {value}"
|
||||
|
||||
def render_installation(self, **kwargs):
|
||||
return f"{kwargs['record'].installation.platform}"
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
<th scope="row">Name</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Description</th>
|
||||
<td>{{ object.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer</th>
|
||||
<td>{{ object.software_product.manufacturer|linkify }}</td>
|
||||
|
||||
@@ -50,11 +50,11 @@ class ModelTestCase(TestCase):
|
||||
|
||||
def test_get_installation_count(self):
|
||||
self.assertEqual(
|
||||
f"<a href='/plugins/slm/installations/?software_product={self.software_product.pk}'>1</a>",
|
||||
f"<a href='/plugins/slm/installations/?software_product_id={self.software_product.pk}'>1</a>",
|
||||
self.software_product.get_installation_count(),
|
||||
)
|
||||
self.assertEqual(
|
||||
f"<a href='/plugins/slm/installations/?version={self.software_product_version.pk}'>1</a>",
|
||||
f"<a href='/plugins/slm/installations/?version_id={self.software_product_version.pk}'>1</a>",
|
||||
self.software_product_version.get_installation_count(),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user