Skip to content

Closes #47: Move plugin to separete menu item in navbar #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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