Skip to content

Commit

Permalink
Closes #47: Move plugin to separete menu item in navbar (#52)
Browse files Browse the repository at this point in the history
* Move plugin into separate menu item

* Add tab for devices with their config compliance
  • Loading branch information
miaow2 authored Jan 28, 2024
1 parent f83d730 commit 63dd590
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 121 deletions.
2 changes: 1 addition & 1 deletion docs/colliecting-diffs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Usage

Under `Plugins` navbar menu you can find plugin
In navbar serach for `Config Diff Plugin` menu

![Screenshot of navbar](media/screenshots/navbar.png)

Expand Down
Binary file modified docs/media/screenshots/navbar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
("dcim", "0181_rename_device_role_device_role"),
("netbox_config_diff", "0007_configurationrequest"),
]

operations = [
migrations.AlterField(
model_name="configcompliance",
name="device",
field=models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="config_compliance",
to="dcim.device",
),
),
]
2 changes: 1 addition & 1 deletion netbox_config_diff/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ConfigCompliance(AbsoluteURLMixin, ChangeLoggingMixin, models.Model):
device = models.OneToOneField(
to="dcim.Device",
on_delete=models.CASCADE,
related_name="config_compliamce",
related_name="config_compliance",
)
status = models.CharField(
max_length=50,
Expand Down
51 changes: 26 additions & 25 deletions netbox_config_diff/navigation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from extras.plugins import PluginMenuButton, PluginMenuItem
from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem
from utilities.choices import ButtonColorChoices


Expand All @@ -12,35 +12,36 @@ def get_add_button(model: str) -> PluginMenuButton:
)


menu_items = (
PluginMenuItem(
link="plugins:netbox_config_diff:platformsetting_list",
link_text="Platform Settings",
buttons=[get_add_button("platformsetting")],
permissions=["netbox_config_diff.view_platformsetting"],
),
PluginMenuItem(
link="plugins:netbox_config_diff:configcompliance_list",
link_text="Config Compliances",
buttons=[],
permissions=["netbox_config_diff.view_configcompliance"],
),
PluginMenuItem(
link="plugins:netbox_config_diff:configurationrequest_list",
link_text="Configuration Requests",
buttons=[get_add_button("configurationrequest")],
permissions=["netbox_config_diff.view_configurationrequest"],
),
def get_menu_item(model: str, verbose_name: str, add_button: bool = True) -> PluginMenuItem:
return PluginMenuItem(
link=f"plugins:netbox_config_diff:{model}_list",
link_text=verbose_name,
buttons=[get_add_button(model)] if add_button else [],
permissions=[f"netbox_config_diff.view_{model}"],
)


compliance_items = (
get_menu_item("platformsetting", "Platform Settings"),
get_menu_item("configcompliance", "Config Compliances", add_button=False),
)

config_items = (
get_menu_item("configurationrequest", "Configuration Requests"),
get_menu_item("substitute", "Substitutes"),
PluginMenuItem(
link="plugins:netbox_config_diff:configurationrequest_job_list",
link_text="Jobs",
buttons=[],
permissions=["core.view_job"],
),
PluginMenuItem(
link="plugins:netbox_config_diff:substitute_list",
link_text="Substitutes",
buttons=[get_add_button("substitute")],
permissions=["netbox_config_diff.view_substitute"],
)

menu = PluginMenu(
label="Config Diff Plugin",
groups=(
("Compliance", compliance_items),
("Config Management", config_items),
),
icon_class="mdi mdi-vector-difference",
)
Original file line number Diff line number Diff line change
@@ -1,81 +1,13 @@
{% extends "netbox_config_diff/configcompliance/base.html" %}
{% load static %}
{% extends "generic/object.html" %}
{% load buttons %}
{% load perms %}

{% block content %}
<div class="row mb-3">
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">{{ object|meta:"verbose_name"|bettertitle }}</h5>
<div class="card-body">
<table class="table table-hover attr-table">
<tr>
<th scope="row">Device</th>
<td>{{ object.device|linkify }}</td>
</tr>
<tr>
<th scope="row">Status</th>
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
</tr>
</table>
</div>
</div>
{% block controls %}
<div class="controls">
<div class="control-group">
{% if request.user|can_delete:object %}
{% delete_button object %}
{% endif %}
</div>
{% if object.error %}
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">Error</h5>
<div class="card-body">
<pre class="block">{{ object.error }}</pre>
</div>
</div>
</div>
{% endif %}
</div>
{% if object.diff %}
<div class="row mb-3">
<div class="col col-md-12">
<div class="card">
<h5 class="card-header">Diff</h5>
<div class="card-body" id="diffElement"></div>
</div>
</div>
</div>
{% endif %}
{% endblock content %}

{% block javascript %}
<script type="text/javascript" src="{% static 'netbox_config_diff/diff2html-ui.min.js' %}"></script>
<script type="text/javascript">
var link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
const colorMode = localStorage.getItem("netbox-color-mode");
if (colorMode === 'dark') {
link.href = `{% static 'netbox_config_diff/diff2html.dark.min.css' %}`
} else {
link.href = `{% static 'netbox_config_diff/diff2html.min.css' %}`
};
document.head.appendChild(link);
document.addEventListener('DOMContentLoaded', () => {
var configuration = {
drawFileList: false,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
stickyFileHeaders: false,
drawFileList: false,
};
const jsonDiff = `{{ object.diff|safe }}`;
var targetElement = document.getElementById('diffElement');
var diff2htmlUi = new Diff2HtmlUI(targetElement, jsonDiff, configuration);
diff2htmlUi.draw();
document.querySelector(".d2h-file-header").remove();
diff2htmlUi.highlightCode();
});
</script>
{% endblock javascript %}
{% endblock controls %}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% extends "netbox_config_diff/configcompliance/base.html" %}
{% extends "netbox_config_diff/configcompliance.html" %}

{% block title %}{{ object }} - {{ header }}{% endblock %}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{% extends base_template %}
{% load static %}

{% block content %}
<div class="row mb-3">
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">{{ instance|meta:"verbose_name"|bettertitle }}</h5>
<div class="card-body">
<table class="table table-hover attr-table">
<tr>
<th scope="row">Device</th>
<td>{{ instance.device|linkify }}</td>
</tr>
<tr>
<th scope="row">Status</th>
<td>{% badge instance.get_status_display bg_color=instance.get_status_color %}</td>
</tr>
</table>
</div>
</div>
</div>
{% if instance.error %}
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">Error</h5>
<div class="card-body">
<pre class="block">{{ instance.error }}</pre>
</div>
</div>
</div>
{% endif %}
</div>
{% if instance.diff %}
<div class="row mb-3">
<div class="col col-md-12">
<div class="card">
<h5 class="card-header">Diff</h5>
<div class="card-body" id="diffElement"></div>
</div>
</div>
</div>
{% endif %}
{% endblock content %}

{% block javascript %}
<script type="text/javascript" src="{% static 'netbox_config_diff/diff2html-ui.min.js' %}"></script>
<script type="text/javascript">
var link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
const colorMode = localStorage.getItem("netbox-color-mode");
if (colorMode === 'dark') {
link.href = `{% static 'netbox_config_diff/diff2html.dark.min.css' %}`
} else {
link.href = `{% static 'netbox_config_diff/diff2html.min.css' %}`
};
document.head.appendChild(link);
document.addEventListener('DOMContentLoaded', () => {
var configuration = {
drawFileList: false,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
stickyFileHeaders: false,
drawFileList: false,
};
const jsonDiff = `{{ instance.diff|safe }}`;
var targetElement = document.getElementById('diffElement');
var diff2htmlUi = new Diff2HtmlUI(targetElement, jsonDiff, configuration);
diff2htmlUi.draw();
document.querySelector(".d2h-file-header").remove();
diff2htmlUi.highlightCode();
});
</script>
{% endblock javascript %}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% extends "netbox_config_diff/configcompliance/base.html" %}
{% extends "netbox_config_diff/configcompliance.html" %}

{% block title %}{{ object }} - Missing/Extra{% endblock %}

Expand Down
42 changes: 41 additions & 1 deletion netbox_config_diff/views/compliance.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from dcim.models import Device
from django.http import HttpResponse
from django.shortcuts import render
from django.shortcuts import redirect, render
from django.utils.translation import gettext as _
from netbox.views import generic
from utilities.views import ViewTab, register_model_view
Expand Down Expand Up @@ -51,6 +52,14 @@ def get_extra_context(self, request, instance):
@register_model_view(ConfigCompliance)
class ConfigComplianceView(generic.ObjectView):
queryset = ConfigCompliance.objects.all()
base_template = "netbox_config_diff/configcompliance.html"
template_name = "netbox_config_diff/configcompliance/data.html"

def get_extra_context(self, request, instance):
return {
"instance": instance,
"base_template": self.base_template,
}


@register_model_view(ConfigCompliance, "rendered-config")
Expand Down Expand Up @@ -113,6 +122,37 @@ def get(self, request, **kwargs):
)


@register_model_view(Device, "config_compliance", "config-compliance")
class ConfigComplianceDeviceView(generic.ObjectView):
queryset = Device.objects.all()
base_template = "dcim/device/base.html"
template_name = "netbox_config_diff/configcompliance/data.html"
tab = ViewTab(
label=_("Config Compliance"),
weight=2110,
badge=lambda obj: 1 if hasattr(obj, "config_compliance") else 0,
hide_if_empty=True,
)

def get(self, request, **kwargs):
instance = self.get_object(**kwargs)

if not hasattr(instance, "config_compliance"):
return redirect("dcim:device", pk=instance.pk)

return render(
request,
self.get_template_name(),
{
"object": instance,
"instance": instance.config_compliance,
"tab": self.tab,
"base_template": self.base_template,
**self.get_extra_context(request, instance),
},
)


class ConfigComplianceListView(generic.ObjectListView):
queryset = ConfigCompliance.objects.prefetch_related("device")
filterset = ConfigComplianceFilterSet
Expand Down

0 comments on commit 63dd590

Please sign in to comment.