mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-09 00:58:16 -06:00
More
This commit is contained in:
parent
46719fb356
commit
6098977ee3
@ -1,3 +1,4 @@
|
||||
import json
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
@ -19,7 +20,7 @@ from extras.dashboard.utils import get_widget_class
|
||||
from netbox.constants import DEFAULT_ACTION_PERMISSIONS
|
||||
from netbox.views import generic
|
||||
from netbox.views.generic.mixins import TableMixin
|
||||
from utilities.data import deep_compare_dict
|
||||
from utilities.data import deep_compare_dict, make_diff
|
||||
from utilities.forms import ConfirmationForm, get_field_value
|
||||
from utilities.htmx import htmx_partial
|
||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||
@ -730,27 +731,19 @@ class ObjectChangeView(generic.ObjectView):
|
||||
|
||||
if prechange_data and instance.postchange_data:
|
||||
diff_added, diff_removed = deep_compare_dict(prechange_data, instance.postchange_data, exclude=('last_updated'))
|
||||
custom_fields_added = diff_added['custom_fields'] if 'custom_fields' in diff_added else None
|
||||
custom_fields_removed = diff_removed['custom_fields'] if 'custom_fields' in diff_removed else None
|
||||
cfr_list = []
|
||||
if custom_fields_added:
|
||||
for cf, cf_value in prechange_data['custom_fields'].items():
|
||||
cfr_list.append((cf, cf_value, cf in custom_fields_added))
|
||||
cfa_list = []
|
||||
if custom_fields_removed:
|
||||
for cf, cf_value in instance.postchange_data['custom_fields'].items():
|
||||
cfa_list.append((cf, cf_value, cf in custom_fields_removed))
|
||||
text_before, text_after = make_diff(json.dumps(prechange_data, indent=2, sort_keys=True), json.dumps(instance.postchange_data, indent=2, sort_keys=True))
|
||||
|
||||
else:
|
||||
diff_added = None
|
||||
diff_removed = None
|
||||
cfa_list = None
|
||||
cfr_list = None
|
||||
text_before = None
|
||||
text_after = None
|
||||
|
||||
return {
|
||||
'diff_added': diff_added,
|
||||
'diff_removed': diff_removed,
|
||||
"cfa_list": cfa_list,
|
||||
"cfr_list": cfr_list,
|
||||
'text_before': text_before,
|
||||
'text_after': text_after,
|
||||
'next_change': next_change,
|
||||
'prev_change': prev_change,
|
||||
'related_changes_table': related_changes_table,
|
||||
|
@ -112,13 +112,8 @@
|
||||
<div class="card-body">
|
||||
{% if object.prechange_data %}
|
||||
{% spaceless %}
|
||||
<pre class="change-data">{% for k, v in object.prechange_data.items %}{% spaceless %}
|
||||
{% if k != 'custom_fields' or not cfr_list %}
|
||||
<span{% if k in diff_removed %} class="removed"{% endif %}>{{ k }}: {{ v|json }}</span>
|
||||
{% else %}
|
||||
<span>{{ k }}: {</span>{% for cfr_data in cfr_list %}<span{% if cfr_data.2 %} class="removed"{% endif %}> {{ cfr_data.0|json }}: {{ cfr_data.1|json|fixindent }}</span>
|
||||
{% endfor %}<span>}</span>
|
||||
{% endif %}
|
||||
<pre class="change-data">{% for text, changed in text_before %}{% spaceless %}
|
||||
<span{% if changed %} class="removed"{% endif %}>{{ text }}</span>
|
||||
{% endspaceless %}{% endfor %}
|
||||
</pre>
|
||||
{% endspaceless %}
|
||||
@ -136,13 +131,8 @@
|
||||
<div class="card-body">
|
||||
{% if object.postchange_data %}
|
||||
{% spaceless %}
|
||||
<pre class="change-data">{% for k, v in object.postchange_data.items %}{% spaceless %}
|
||||
{% if k != 'custom_fields' or not cfa_list %}
|
||||
<span{% if k in diff_added %} class="added"{% endif %}>{{ k }}: {{ v|json }}</span>
|
||||
{% else %}
|
||||
<span>{{ k }}: {</span>{% for cfa_data in cfa_list %}<span{% if cfa_data.2 %} class="added"{% endif %}> {{ cfa_data.0|json }}: {{ cfa_data.1|json|fixindent }}</span>
|
||||
{% endfor %}<span>}</span>
|
||||
{% endif %}
|
||||
<pre class="change-data">{% for text,changed in text_after %}{% spaceless %}
|
||||
<span{% if changed %} class="added"{% endif %}>{{ text }}</span>
|
||||
{% endspaceless %}{% endfor %}
|
||||
</pre>
|
||||
{% endspaceless %}
|
||||
|
@ -8,6 +8,7 @@ __all__ = (
|
||||
'drange',
|
||||
'flatten_dict',
|
||||
'deep_compare_dict',
|
||||
'make_diff',
|
||||
)
|
||||
|
||||
|
||||
@ -127,3 +128,177 @@ def drange(start, end, step=decimal.Decimal(1)):
|
||||
while start > end:
|
||||
yield start
|
||||
start += step
|
||||
|
||||
#
|
||||
# String utilities
|
||||
#
|
||||
def regular_line_ending(s: str):
|
||||
if s.endswith(","):
|
||||
return True
|
||||
return not (s.endswith("{") or s.endswith("["))
|
||||
|
||||
|
||||
def begin_of_complex(s: str):
|
||||
return s.endswith("[") or s.endswith("{")
|
||||
|
||||
|
||||
def has_indent(s: str, indent: str):
|
||||
return not s.removeprefix(indent).startswith(" ")
|
||||
|
||||
|
||||
def extract_key(s: str):
|
||||
if '": ' not in s:
|
||||
return None
|
||||
idx = s.find(': ')
|
||||
substr = s[:idx].replace('"', '').strip()
|
||||
return substr
|
||||
|
||||
def make_diff(old: str, new: str):
|
||||
old_lines = old.splitlines(False)
|
||||
new_lines = new.splitlines(False)
|
||||
old_list: list[tuple[str, bool]] = []
|
||||
new_list: list[tuple[str, bool]] = []
|
||||
old_idx = 0
|
||||
new_idx = 0
|
||||
while True:
|
||||
if old_idx == len(old_lines) and new_idx == len(new_lines):
|
||||
break
|
||||
if old_idx == len(old_lines):
|
||||
while new_idx != len(new_lines):
|
||||
new_list.append((new_lines[new_idx], True))
|
||||
old_list.append(("", False))
|
||||
new_idx += 1
|
||||
break
|
||||
if new_idx == len(new_lines):
|
||||
while old_idx != len(old_lines):
|
||||
old_list.append((old_lines[old_idx], True))
|
||||
new_list.append(("", False))
|
||||
old_idx += 1
|
||||
break
|
||||
old_s = old_lines[old_idx]
|
||||
old_idx += 1
|
||||
old_k = extract_key(old_s)
|
||||
new_s = new_lines[new_idx]
|
||||
new_k = extract_key(new_s)
|
||||
new_idx += 1
|
||||
# Handle additions of keys
|
||||
if old_k is not None and new_k is not None and old_k != new_k:
|
||||
print("Found mismatch:", old_k, new_k)
|
||||
found_it = False
|
||||
for old_idx2 in range(old_idx, len(old_lines)):
|
||||
old_s2 = old_lines[old_idx2]
|
||||
old_k2 = extract_key(old_s2)
|
||||
print(">>", old_k2, new_k)
|
||||
if old_k2 == new_k:
|
||||
print("Found it", old_k2, old_idx2, new_k)
|
||||
old_list.append((old_s, False))
|
||||
new_list.append((" <O>", False))
|
||||
old_s = "" if old_idx >= len(old_lines) else old_lines[old_idx]
|
||||
for _ in range(old_idx + 1, old_idx2 + 1):
|
||||
old_s = "" if old_idx >= len(old_lines) else old_lines[old_idx]
|
||||
new_list.append((" <<OLDFILLER>", False))
|
||||
old_list.append((old_s, True))
|
||||
old_idx += 1
|
||||
old_list.append((old_s, False))
|
||||
new_list.append((new_s, False))
|
||||
old_idx += 1
|
||||
found_it = True
|
||||
break
|
||||
if found_it:
|
||||
continue
|
||||
for new_idx2 in range(new_idx, len(new_lines)):
|
||||
new_s2 = new_lines[new_idx2]
|
||||
new_k2 = extract_key(new_s2)
|
||||
print(">>22", old_k, new_k2)
|
||||
if new_k2 == old_k:
|
||||
print("NEW Found it", new_k2, new_idx2, old_k)
|
||||
old_list.append((" <N>", False))
|
||||
new_list.append((new_s, False))
|
||||
new_s = "" if new_idx >= len(new_lines) else new_lines[new_idx]
|
||||
for _ in range(new_idx + 1, new_idx2 + 1):
|
||||
new_s = "" if new_idx >= len(new_lines) else new_lines[new_idx]
|
||||
old_list.append((" <<NEWFILLER>", False))
|
||||
new_idx += 1
|
||||
new_list.append((new_s, True))
|
||||
old_list.append((old_s, False))
|
||||
new_list.append((new_s, False))
|
||||
new_idx += 1
|
||||
found_it = True
|
||||
break
|
||||
continue
|
||||
if "{" == old_s.strip() and "{" == new_s.strip():
|
||||
old_list.append(("{", False))
|
||||
new_list.append(("{", False))
|
||||
continue
|
||||
if "}" == old_s.strip() and "}" == new_s.strip():
|
||||
old_list.append(("}", False))
|
||||
new_list.append(("}", False))
|
||||
continue
|
||||
# Handle:
|
||||
# "foo": null "foo": [
|
||||
# "bar",
|
||||
# "baz",
|
||||
# "]"
|
||||
if regular_line_ending(old_s) and begin_of_complex(new_s):
|
||||
indent_of_new = new_s.replace(new_s.strip(), "")
|
||||
new_list.append((new_s, True))
|
||||
old_list.append((old_s, True))
|
||||
while not has_indent(new_lines[new_idx], indent_of_new):
|
||||
old_list.append(("", True))
|
||||
new_list.append((new_lines[new_idx], True))
|
||||
new_idx += 1
|
||||
old_list.append(("", True))
|
||||
new_list.append((new_lines[new_idx], True))
|
||||
new_idx += 1
|
||||
continue
|
||||
# Handle:
|
||||
# "foo": { "foo": null
|
||||
# "foo": "bar"
|
||||
# }
|
||||
if begin_of_complex(old_s) and regular_line_ending(new_s):
|
||||
indent_of_old = old_s.replace(old_s.strip(), "")
|
||||
old_list.append((old_s, True))
|
||||
new_list.append((new_s, True))
|
||||
while not has_indent(old_lines[old_idx], indent_of_old):
|
||||
new_list.append(("", True))
|
||||
old_list.append((old_lines[old_idx], True))
|
||||
old_idx += 1
|
||||
new_list.append(("", True))
|
||||
old_list.append((old_lines[old_idx], True))
|
||||
old_idx += 1
|
||||
continue
|
||||
if begin_of_complex(old_s) and begin_of_complex(new_s):
|
||||
indent_of_old = old_s.replace(old_s.strip(), "")
|
||||
indent_of_new = new_s.replace(new_s.strip(), "")
|
||||
old_list.append((old_s, False))
|
||||
new_list.append((new_s, False))
|
||||
old_tmp = []
|
||||
new_tmp = []
|
||||
while not has_indent(old_lines[old_idx], indent_of_old):
|
||||
old_tmp.append(old_lines[old_idx])
|
||||
old_idx += 1
|
||||
while not has_indent(new_lines[new_idx], indent_of_new):
|
||||
new_tmp.append(new_lines[new_idx])
|
||||
new_idx += 1
|
||||
a, b = make_diff("\n".join(old_tmp), "\n".join(new_tmp))
|
||||
assert len(a) == len(b)
|
||||
old_list += a
|
||||
new_list += b
|
||||
old_list.append((old_lines[old_idx], False))
|
||||
old_idx += 1
|
||||
new_list.append((new_lines[new_idx], False))
|
||||
new_idx += 1
|
||||
continue
|
||||
if old_s == new_s:
|
||||
old_list.append((old_s, False))
|
||||
new_list.append((new_s, False))
|
||||
continue
|
||||
# Handle:
|
||||
# "foo": 1(,) "foo": 2(,)
|
||||
if regular_line_ending(old_s) and regular_line_ending(new_s):
|
||||
old_list.append((old_s, True))
|
||||
new_list.append((new_s, True))
|
||||
continue
|
||||
print(len(old_list), len(new_list))
|
||||
assert len(old_list) == len(new_list)
|
||||
return old_list, new_list
|
Loading…
Reference in New Issue
Block a user