ipfabric_netbox 4.3.2b9__py3-none-any.whl → 4.3.2b10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ipfabric_netbox might be problematic. Click here for more details.
- ipfabric_netbox/__init__.py +2 -2
- ipfabric_netbox/api/serializers.py +112 -7
- ipfabric_netbox/api/urls.py +6 -0
- ipfabric_netbox/api/views.py +23 -0
- ipfabric_netbox/choices.py +72 -40
- ipfabric_netbox/data/endpoint.json +47 -0
- ipfabric_netbox/data/filters.json +51 -0
- ipfabric_netbox/data/transform_map.json +188 -174
- ipfabric_netbox/exceptions.py +7 -5
- ipfabric_netbox/filtersets.py +310 -41
- ipfabric_netbox/forms.py +324 -79
- ipfabric_netbox/graphql/__init__.py +6 -0
- ipfabric_netbox/graphql/enums.py +5 -5
- ipfabric_netbox/graphql/filters.py +56 -4
- ipfabric_netbox/graphql/schema.py +28 -0
- ipfabric_netbox/graphql/types.py +61 -1
- ipfabric_netbox/jobs.py +5 -1
- ipfabric_netbox/migrations/0022_prepare_for_filters.py +182 -0
- ipfabric_netbox/migrations/0023_populate_filters_data.py +279 -0
- ipfabric_netbox/migrations/0024_finish_filters.py +29 -0
- ipfabric_netbox/models.py +384 -12
- ipfabric_netbox/navigation.py +98 -24
- ipfabric_netbox/tables.py +194 -9
- ipfabric_netbox/templates/ipfabric_netbox/htmx_list.html +5 -0
- ipfabric_netbox/templates/ipfabric_netbox/inc/combined_expressions.html +59 -0
- ipfabric_netbox/templates/ipfabric_netbox/inc/combined_expressions_content.html +39 -0
- ipfabric_netbox/templates/ipfabric_netbox/inc/endpoint_filters_with_selector.html +54 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricendpoint.html +39 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricfilter.html +51 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricfilterexpression.html +39 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricfilterexpression_edit.html +150 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html +1 -1
- ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html +16 -2
- ipfabric_netbox/templatetags/ipfabric_netbox_helpers.py +65 -0
- ipfabric_netbox/tests/api/test_api.py +333 -13
- ipfabric_netbox/tests/test_filtersets.py +2592 -0
- ipfabric_netbox/tests/test_forms.py +1256 -74
- ipfabric_netbox/tests/test_models.py +242 -34
- ipfabric_netbox/tests/test_views.py +2030 -25
- ipfabric_netbox/urls.py +35 -0
- ipfabric_netbox/utilities/endpoint.py +30 -0
- ipfabric_netbox/utilities/filters.py +88 -0
- ipfabric_netbox/utilities/ipfutils.py +254 -316
- ipfabric_netbox/utilities/logging.py +7 -7
- ipfabric_netbox/utilities/transform_map.py +126 -0
- ipfabric_netbox/views.py +719 -5
- {ipfabric_netbox-4.3.2b9.dist-info → ipfabric_netbox-4.3.2b10.dist-info}/METADATA +3 -2
- {ipfabric_netbox-4.3.2b9.dist-info → ipfabric_netbox-4.3.2b10.dist-info}/RECORD +49 -33
- {ipfabric_netbox-4.3.2b9.dist-info → ipfabric_netbox-4.3.2b10.dist-info}/WHEEL +1 -1
ipfabric_netbox/tables.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import django_tables2 as tables
|
|
2
|
+
from django.db.models import Count
|
|
2
3
|
from django.utils.html import format_html
|
|
3
4
|
from django.utils.translation import gettext_lazy as _
|
|
4
5
|
from django_tables2 import Column
|
|
@@ -7,6 +8,9 @@ from netbox.tables import NetBoxTable
|
|
|
7
8
|
from netbox_branching.models import ChangeDiff
|
|
8
9
|
|
|
9
10
|
from .models import IPFabricData
|
|
11
|
+
from .models import IPFabricEndpoint
|
|
12
|
+
from .models import IPFabricFilter
|
|
13
|
+
from .models import IPFabricFilterExpression
|
|
10
14
|
from .models import IPFabricIngestion
|
|
11
15
|
from .models import IPFabricIngestionIssue
|
|
12
16
|
from .models import IPFabricRelationshipField
|
|
@@ -42,25 +46,126 @@ DATA_BUTTON = """
|
|
|
42
46
|
</a>
|
|
43
47
|
"""
|
|
44
48
|
|
|
49
|
+
COMBINED_EXPRESSIONS_BUTTON = """
|
|
50
|
+
<a href="#"
|
|
51
|
+
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricfilter_combined_expressions' pk=record.pk %}"
|
|
52
|
+
hx-target="#htmx-modal-content"
|
|
53
|
+
data-bs-toggle="modal"
|
|
54
|
+
data-bs-target="#htmx-modal"
|
|
55
|
+
class="btn btn-success btn-sm"
|
|
56
|
+
>
|
|
57
|
+
Combined
|
|
58
|
+
</a>
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
ENDPOINT_FILTERS_BUTTON = """
|
|
62
|
+
{% if record.sync_pk %}
|
|
63
|
+
<a href="#"
|
|
64
|
+
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricendpoint_filters' pk=record.pk %}?sync_pk={{ record.sync_pk }}&from_sync=true"
|
|
65
|
+
hx-target="#htmx-modal-content"
|
|
66
|
+
data-bs-toggle="modal"
|
|
67
|
+
data-bs-target="#htmx-modal"
|
|
68
|
+
class="btn btn-success btn-sm"
|
|
69
|
+
>
|
|
70
|
+
Show Filters
|
|
71
|
+
</a>
|
|
72
|
+
{% else %}
|
|
73
|
+
<a href="#"
|
|
74
|
+
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricendpoint_filters' pk=record.pk %}"
|
|
75
|
+
hx-target="#htmx-modal-content"
|
|
76
|
+
data-bs-toggle="modal"
|
|
77
|
+
data-bs-target="#htmx-modal"
|
|
78
|
+
class="btn btn-success btn-sm"
|
|
79
|
+
>
|
|
80
|
+
Show Filters
|
|
81
|
+
</a>
|
|
82
|
+
{% endif %}
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class IPFabricEndpointTable(NetBoxTable):
|
|
87
|
+
name = tables.Column(linkify=True)
|
|
88
|
+
endpoint = tables.Column(verbose_name=_("Endpoint"))
|
|
89
|
+
filters_count = tables.Column(
|
|
90
|
+
verbose_name=_("Filters"),
|
|
91
|
+
empty_values=(),
|
|
92
|
+
default="",
|
|
93
|
+
linkify=lambda record: f"/plugins/ipfabric/filter/?endpoint_id={record.pk}",
|
|
94
|
+
)
|
|
95
|
+
show_filters = columns.TemplateColumn(
|
|
96
|
+
template_code=ENDPOINT_FILTERS_BUTTON,
|
|
97
|
+
orderable=False,
|
|
98
|
+
verbose_name=_("Combined Filters"),
|
|
99
|
+
empty_values=(),
|
|
100
|
+
default="",
|
|
101
|
+
)
|
|
102
|
+
actions = None
|
|
103
|
+
|
|
104
|
+
def render_filters_count(self, record):
|
|
105
|
+
"""Only render filter count if it's available."""
|
|
106
|
+
if not hasattr(record, "filters_count"):
|
|
107
|
+
return ""
|
|
108
|
+
return record.filters_count
|
|
109
|
+
|
|
110
|
+
class Meta(NetBoxTable.Meta):
|
|
111
|
+
model = IPFabricEndpoint
|
|
112
|
+
fields = ("name", "description", "endpoint", "filters_count", "show_filters")
|
|
113
|
+
default_columns = (
|
|
114
|
+
"name",
|
|
115
|
+
"description",
|
|
116
|
+
"endpoint",
|
|
117
|
+
"filters_count",
|
|
118
|
+
"show_filters",
|
|
119
|
+
)
|
|
120
|
+
|
|
45
121
|
|
|
46
122
|
class IPFabricRelationshipFieldTable(NetBoxTable):
|
|
47
|
-
|
|
123
|
+
id = tables.Column()
|
|
124
|
+
transform_map = tables.Column(linkify=True)
|
|
48
125
|
source_model = columns.ContentTypeColumn(verbose_name=_("Source Model"))
|
|
126
|
+
actions = columns.ActionsColumn(actions=("edit", "delete"))
|
|
49
127
|
|
|
50
128
|
class Meta(NetBoxTable.Meta):
|
|
51
129
|
model = IPFabricRelationshipField
|
|
52
|
-
fields = (
|
|
53
|
-
|
|
130
|
+
fields = (
|
|
131
|
+
"id",
|
|
132
|
+
"transform_map",
|
|
133
|
+
"source_model",
|
|
134
|
+
"target_field",
|
|
135
|
+
"coalesce",
|
|
136
|
+
"actions",
|
|
137
|
+
)
|
|
138
|
+
default_columns = (
|
|
139
|
+
"transform_map",
|
|
140
|
+
"source_model",
|
|
141
|
+
"target_field",
|
|
142
|
+
"coalesce",
|
|
143
|
+
"actions",
|
|
144
|
+
)
|
|
54
145
|
|
|
55
146
|
|
|
56
147
|
class IPFabricTransformFieldTable(NetBoxTable):
|
|
57
148
|
id = tables.Column()
|
|
149
|
+
transform_map = tables.Column(linkify=True)
|
|
58
150
|
actions = columns.ActionsColumn(actions=("edit", "delete"))
|
|
59
151
|
|
|
60
152
|
class Meta(NetBoxTable.Meta):
|
|
61
153
|
model = IPFabricTransformField
|
|
62
|
-
fields = (
|
|
63
|
-
|
|
154
|
+
fields = (
|
|
155
|
+
"id",
|
|
156
|
+
"transform_map",
|
|
157
|
+
"source_field",
|
|
158
|
+
"target_field",
|
|
159
|
+
"coalesce",
|
|
160
|
+
"actions",
|
|
161
|
+
)
|
|
162
|
+
default_columns = (
|
|
163
|
+
"transform_map",
|
|
164
|
+
"source_field",
|
|
165
|
+
"target_field",
|
|
166
|
+
"coalesce",
|
|
167
|
+
"actions",
|
|
168
|
+
)
|
|
64
169
|
|
|
65
170
|
|
|
66
171
|
class IPFabricTransformMapGroupTable(NetBoxTable):
|
|
@@ -79,13 +184,47 @@ class IPFabricTransformMapGroupTable(NetBoxTable):
|
|
|
79
184
|
|
|
80
185
|
class IPFabricTransformMapTable(NetBoxTable):
|
|
81
186
|
name = tables.Column(linkify=True)
|
|
187
|
+
parents = tables.Column(linkify=False, verbose_name=_("Hierarchical Parents"))
|
|
82
188
|
group = tables.Column(linkify=True)
|
|
189
|
+
source_endpoint = tables.Column(linkify=True)
|
|
83
190
|
target_model = columns.ContentTypeColumn(verbose_name=_("Target Model"))
|
|
84
191
|
|
|
192
|
+
def render_parents(self, record):
|
|
193
|
+
"""Render multiple parents as comma-separated list with links."""
|
|
194
|
+
parents = record.parents.all()
|
|
195
|
+
if not parents.exists():
|
|
196
|
+
return "---"
|
|
197
|
+
|
|
198
|
+
parent_links = []
|
|
199
|
+
for parent in parents:
|
|
200
|
+
url = parent.get_absolute_url()
|
|
201
|
+
parent_links.append(format_html('<a href="{}">{}</a>', url, parent.name))
|
|
202
|
+
|
|
203
|
+
# Join the SafeStrings directly
|
|
204
|
+
return format_html(", ".join(str(link) for link in parent_links))
|
|
205
|
+
|
|
206
|
+
def order_parents(self, queryset, is_descending):
|
|
207
|
+
"""Order by count of parents."""
|
|
208
|
+
|
|
209
|
+
queryset = queryset.annotate(parent_count=Count("parents"))
|
|
210
|
+
|
|
211
|
+
if is_descending:
|
|
212
|
+
queryset = queryset.order_by("-parent_count")
|
|
213
|
+
else:
|
|
214
|
+
queryset = queryset.order_by("parent_count")
|
|
215
|
+
|
|
216
|
+
return queryset, True
|
|
217
|
+
|
|
85
218
|
class Meta(NetBoxTable.Meta):
|
|
86
219
|
model = IPFabricTransformMap
|
|
87
|
-
fields = ("name", "group", "
|
|
88
|
-
default_columns = (
|
|
220
|
+
fields = ("name", "parents", "group", "source_endpoint", "target_model")
|
|
221
|
+
default_columns = (
|
|
222
|
+
"name",
|
|
223
|
+
"parents",
|
|
224
|
+
"group",
|
|
225
|
+
"source_endpoint",
|
|
226
|
+
"target_model",
|
|
227
|
+
)
|
|
89
228
|
|
|
90
229
|
|
|
91
230
|
class IPFabricIngestionTable(NetBoxTable):
|
|
@@ -107,8 +246,8 @@ class IPFabricIngestionTable(NetBoxTable):
|
|
|
107
246
|
|
|
108
247
|
class Meta(NetBoxTable.Meta):
|
|
109
248
|
model = IPFabricIngestion
|
|
110
|
-
fields = ("name", "sync", "branch", "
|
|
111
|
-
default_columns = ("name", "sync", "branch", "
|
|
249
|
+
fields = ("name", "sync", "branch", "user", "changes")
|
|
250
|
+
default_columns = ("name", "sync", "branch", "user", "changes")
|
|
112
251
|
|
|
113
252
|
|
|
114
253
|
class IPFabricSnapshotTable(NetBoxTable):
|
|
@@ -257,6 +396,52 @@ class IPFabricIngestionIssuesTable(NetBoxTable):
|
|
|
257
396
|
order_by = "id"
|
|
258
397
|
|
|
259
398
|
|
|
399
|
+
class IPFabricFilterTable(NetBoxTable):
|
|
400
|
+
name = tables.Column(linkify=True)
|
|
401
|
+
endpoints = tables.ManyToManyColumn(linkify_item=True)
|
|
402
|
+
filter_type = columns.ChoiceFieldColumn(verbose_name=_("Filter Type"))
|
|
403
|
+
syncs = tables.ManyToManyColumn(linkify_item=True)
|
|
404
|
+
expressions = columns.ManyToManyColumn(
|
|
405
|
+
linkify_item=True, verbose_name=_("Filter Expressions")
|
|
406
|
+
)
|
|
407
|
+
combined = columns.TemplateColumn(
|
|
408
|
+
template_code=COMBINED_EXPRESSIONS_BUTTON,
|
|
409
|
+
orderable=False,
|
|
410
|
+
verbose_name=_("Combined"),
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
class Meta(NetBoxTable.Meta):
|
|
414
|
+
model = IPFabricFilter
|
|
415
|
+
fields = (
|
|
416
|
+
"name",
|
|
417
|
+
"description",
|
|
418
|
+
"endpoints",
|
|
419
|
+
"filter_type",
|
|
420
|
+
"syncs",
|
|
421
|
+
"expressions",
|
|
422
|
+
"combined",
|
|
423
|
+
)
|
|
424
|
+
default_columns = (
|
|
425
|
+
"name",
|
|
426
|
+
"endpoints",
|
|
427
|
+
"filter_type",
|
|
428
|
+
"syncs",
|
|
429
|
+
"expressions",
|
|
430
|
+
"combined",
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class IPFabricFilterExpressionTable(NetBoxTable):
|
|
435
|
+
name = tables.Column(linkify=True)
|
|
436
|
+
expression = tables.Column(verbose_name=_("Filter Expression"))
|
|
437
|
+
filters = tables.ManyToManyColumn(linkify_item=True)
|
|
438
|
+
|
|
439
|
+
class Meta(NetBoxTable.Meta):
|
|
440
|
+
model = IPFabricFilterExpression
|
|
441
|
+
fields = ("name", "description", "filters", "expression")
|
|
442
|
+
default_columns = ("name", "filters", "expression")
|
|
443
|
+
|
|
444
|
+
|
|
260
445
|
class DeviceIPFTable(tables.Table):
|
|
261
446
|
hostname = Column()
|
|
262
447
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
<div class="modal-content" id="htmx-modal-content">
|
|
3
|
+
<div class="modal-header">
|
|
4
|
+
<h5 class="modal-title">
|
|
5
|
+
{% if context_type == "endpoint" %}
|
|
6
|
+
{% blocktrans %}Combined Filters for Endpoint: {{ object.name }}{% endblocktrans %}
|
|
7
|
+
<br>
|
|
8
|
+
<small class="text-muted">
|
|
9
|
+
{% trans "Endpoint:" %} {{ object.endpoint }} |
|
|
10
|
+
{% trans "Sync:" %} {{ sync.name }} (ID: {{ sync.pk }})
|
|
11
|
+
</small>
|
|
12
|
+
{% elif context_type == "endpoint_all" %}
|
|
13
|
+
{% blocktrans %}All Filters for Endpoint: {{ object.name }}{% endblocktrans %}
|
|
14
|
+
<br>
|
|
15
|
+
<small class="text-muted">
|
|
16
|
+
{% trans "Endpoint:" %} {{ object.endpoint }}
|
|
17
|
+
</small>
|
|
18
|
+
{% else %}
|
|
19
|
+
{% blocktrans %}Combined Expressions - {{ object.name }}{% endblocktrans %}
|
|
20
|
+
<small class="text-muted">(ID: {{ object.pk }})</small>
|
|
21
|
+
{% endif %}
|
|
22
|
+
</h5>
|
|
23
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="modal-body">
|
|
26
|
+
<div class="row mb-3">
|
|
27
|
+
<div class="col-12">
|
|
28
|
+
<div class="card">
|
|
29
|
+
<h5 class="card-header">
|
|
30
|
+
{% if context_type == "endpoint" or context_type == "endpoint_all" %}
|
|
31
|
+
{% trans "Combined Filters" %}: {{ object.endpoint }}
|
|
32
|
+
{% else %}
|
|
33
|
+
{% trans "Merged Filter Expressions for filter type" %}: {{ object.filter_type|upper }}
|
|
34
|
+
{% endif %}
|
|
35
|
+
</h5>
|
|
36
|
+
<div class="card-body">
|
|
37
|
+
{% if is_empty %}
|
|
38
|
+
<div class="alert alert-info" role="alert">
|
|
39
|
+
<i class="mdi mdi-information"></i>
|
|
40
|
+
{% if context_type == "endpoint" %}
|
|
41
|
+
{% trans "No filters are applied to this endpoint in this sync." %}
|
|
42
|
+
{% elif context_type == "endpoint_all" %}
|
|
43
|
+
{% trans "No filters are using this endpoint." %}
|
|
44
|
+
{% else %}
|
|
45
|
+
{% trans "No expressions defined for this filter." %}
|
|
46
|
+
{% endif %}
|
|
47
|
+
</div>
|
|
48
|
+
{% else %}
|
|
49
|
+
<pre>{{ combined_expressions | json }}</pre>
|
|
50
|
+
{% endif %}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<div class="modal-footer">
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
<div class="row mb-3">
|
|
3
|
+
<div class="col-12">
|
|
4
|
+
<div class="card">
|
|
5
|
+
<h5 class="card-header">
|
|
6
|
+
{% if object %}
|
|
7
|
+
{% if context_type == "endpoint" or context_type == "endpoint_all" %}
|
|
8
|
+
{% trans "Combined Filters" %}: {{ object.endpoint }}
|
|
9
|
+
{% if sync %}
|
|
10
|
+
<small class="text-muted"> - {% trans "Sync:" %} {{ sync.name }} (ID: {{ sync.pk }})</small>
|
|
11
|
+
{% else %}
|
|
12
|
+
<small class="text-muted"> - {% trans "All Syncs" %}</small>
|
|
13
|
+
{% endif %}
|
|
14
|
+
{% else %}
|
|
15
|
+
{% trans "Merged Filter Expressions for filter type" %}: {{ object.filter_type|upper }}
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% else %}
|
|
18
|
+
{% trans "Combined Filters" %}
|
|
19
|
+
{% endif %}
|
|
20
|
+
</h5>
|
|
21
|
+
<div class="card-body">
|
|
22
|
+
{% if is_empty %}
|
|
23
|
+
<div class="alert alert-info" role="alert">
|
|
24
|
+
<i class="mdi mdi-information"></i>
|
|
25
|
+
{% if context_type == "endpoint" %}
|
|
26
|
+
{% trans "No filters are applied to this endpoint in this sync." %}
|
|
27
|
+
{% elif context_type == "endpoint_all" %}
|
|
28
|
+
{% trans "No filters are using this endpoint." %}
|
|
29
|
+
{% else %}
|
|
30
|
+
{% trans "No expressions defined for this filter." %}
|
|
31
|
+
{% endif %}
|
|
32
|
+
</div>
|
|
33
|
+
{% else %}
|
|
34
|
+
<pre>{{ combined_expressions | json }}</pre>
|
|
35
|
+
{% endif %}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
<div class="modal-content" id="htmx-modal-content">
|
|
3
|
+
<div class="modal-header">
|
|
4
|
+
<h5 class="modal-title">
|
|
5
|
+
{% if object %}
|
|
6
|
+
{% blocktrans %}Filters for Endpoint: {{ object.name }}{% endblocktrans %}
|
|
7
|
+
<br>
|
|
8
|
+
<small class="text-muted">
|
|
9
|
+
{% trans "Endpoint:" %} {{ object.endpoint }}
|
|
10
|
+
</small>
|
|
11
|
+
{% else %}
|
|
12
|
+
{% trans "Endpoint Filters" %}
|
|
13
|
+
{% endif %}
|
|
14
|
+
</h5>
|
|
15
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="modal-body">
|
|
18
|
+
{% if object %}
|
|
19
|
+
<div class="row mb-3">
|
|
20
|
+
<div class="col-12">
|
|
21
|
+
<div class="form-group">
|
|
22
|
+
<label for="sync-selector">{% trans "Select Sync:" %}</label>
|
|
23
|
+
<select id="sync-selector"
|
|
24
|
+
class="form-select"
|
|
25
|
+
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricendpoint_filters' pk=object.pk %}"
|
|
26
|
+
hx-target="#filters-content"
|
|
27
|
+
hx-include="#sync-selector"
|
|
28
|
+
hx-swap="innerHTML"
|
|
29
|
+
name="sync_pk">
|
|
30
|
+
<option value="">{% trans "All Syncs" %}</option>
|
|
31
|
+
{% for sync in available_syncs %}
|
|
32
|
+
<option value="{{ sync.pk }}" {% if selected_sync_pk == sync.pk %}selected{% endif %}>
|
|
33
|
+
{{ sync.name }} (ID: {{ sync.pk }})
|
|
34
|
+
</option>
|
|
35
|
+
{% endfor %}
|
|
36
|
+
</select>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div id="filters-content">
|
|
42
|
+
{% include "ipfabric_netbox/inc/combined_expressions_content.html" %}
|
|
43
|
+
</div>
|
|
44
|
+
{% else %}
|
|
45
|
+
<div class="alert alert-info" role="alert">
|
|
46
|
+
<i class="mdi mdi-information"></i>
|
|
47
|
+
{% trans "This view requires an HTMX request." %}
|
|
48
|
+
</div>
|
|
49
|
+
{% endif %}
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="modal-footer">
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{% extends 'generic/object.html' %}
|
|
2
|
+
{% load static %}
|
|
3
|
+
{% load helpers %}
|
|
4
|
+
{% load plugins %}
|
|
5
|
+
{% load render_table from django_tables2 %}
|
|
6
|
+
{% load i18n %}
|
|
7
|
+
|
|
8
|
+
{% block content %}
|
|
9
|
+
<div class="row mb-3">
|
|
10
|
+
<div class="col col-md-6">
|
|
11
|
+
<div class="card">
|
|
12
|
+
<h5 class="card-header">{% trans "Endpoint Information" %}</h5>
|
|
13
|
+
<div class="card-body">
|
|
14
|
+
<table class="table table-hover attr-table">
|
|
15
|
+
<tr>
|
|
16
|
+
<th scope="row">{% trans "Name" %}</th>
|
|
17
|
+
<td>{{ object.name }}</td>
|
|
18
|
+
</tr>
|
|
19
|
+
<tr>
|
|
20
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
21
|
+
<td>{{ object.description | placeholder }}</td>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr>
|
|
24
|
+
<th scope="row">{% trans "Endpoint" %}</th>
|
|
25
|
+
<td>{{ object.endpoint | placeholder }}</td>
|
|
26
|
+
</tr>
|
|
27
|
+
</table>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
{% plugin_left_page object %}
|
|
31
|
+
</div>
|
|
32
|
+
<div class="col col-12 col-md-6">
|
|
33
|
+
{% include 'inc/panels/related_objects.html' %}
|
|
34
|
+
{% include 'inc/panels/comments.html' %}
|
|
35
|
+
{% include 'inc/panels/custom_fields.html' %}
|
|
36
|
+
{% plugin_right_page object %}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
{% endblock %}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{% extends 'generic/object.html' %}
|
|
2
|
+
{% load static %}
|
|
3
|
+
{% load helpers %}
|
|
4
|
+
{% load plugins %}
|
|
5
|
+
{% load render_table from django_tables2 %}
|
|
6
|
+
{% load i18n %}
|
|
7
|
+
|
|
8
|
+
{% block extra_controls %}
|
|
9
|
+
<a href="#"
|
|
10
|
+
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricfilter_combined_expressions' pk=object.pk %}"
|
|
11
|
+
hx-target="#htmx-modal-content"
|
|
12
|
+
data-bs-toggle="modal"
|
|
13
|
+
data-bs-target="#htmx-modal"
|
|
14
|
+
class="btn btn-primary"
|
|
15
|
+
>
|
|
16
|
+
<i class="mdi mdi-filter-variant"></i> {% trans "Combined Expressions" %}
|
|
17
|
+
</a>
|
|
18
|
+
{% endblock %}
|
|
19
|
+
|
|
20
|
+
{% block content %}
|
|
21
|
+
<div class="row mb-3">
|
|
22
|
+
<div class="col col-md-6">
|
|
23
|
+
<div class="card">
|
|
24
|
+
<h5 class="card-header">{% trans "Filter Information" %}</h5>
|
|
25
|
+
<div class="card-body">
|
|
26
|
+
<table class="table table-hover attr-table">
|
|
27
|
+
<tr>
|
|
28
|
+
<th scope="row">{% trans "Name" %}</th>
|
|
29
|
+
<td>{{ object.name }}</td>
|
|
30
|
+
</tr>
|
|
31
|
+
<tr>
|
|
32
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
33
|
+
<td>{{ object.description | placeholder }}</td>
|
|
34
|
+
</tr>
|
|
35
|
+
<tr>
|
|
36
|
+
<th scope="row">{% trans "Filter Type" %}</th>
|
|
37
|
+
<td>{{ object.filter_type.upper | placeholder }}</td>
|
|
38
|
+
</tr>
|
|
39
|
+
</table>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
{% plugin_left_page object %}
|
|
43
|
+
</div>
|
|
44
|
+
<div class="col col-12 col-md-6">
|
|
45
|
+
{% include 'inc/panels/related_objects.html' %}
|
|
46
|
+
{% include 'inc/panels/comments.html' %}
|
|
47
|
+
{% include 'inc/panels/custom_fields.html' %}
|
|
48
|
+
{% plugin_right_page object %}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
{% endblock %}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{% extends 'generic/object.html' %}
|
|
2
|
+
{% load static %}
|
|
3
|
+
{% load helpers %}
|
|
4
|
+
{% load plugins %}
|
|
5
|
+
{% load render_table from django_tables2 %}
|
|
6
|
+
{% load i18n %}
|
|
7
|
+
|
|
8
|
+
{% block content %}
|
|
9
|
+
<div class="row mb-3">
|
|
10
|
+
<div class="col col-md-6">
|
|
11
|
+
<div class="card">
|
|
12
|
+
<h5 class="card-header">{% trans "Filter Expression Information" %}</h5>
|
|
13
|
+
<div class="card-body">
|
|
14
|
+
<table class="table table-hover attr-table">
|
|
15
|
+
<tr>
|
|
16
|
+
<th scope="row">{% trans "Name" %}</th>
|
|
17
|
+
<td>{{ object.name }}</td>
|
|
18
|
+
</tr>
|
|
19
|
+
<tr>
|
|
20
|
+
<th scope="row">{% trans "Description" %}</th>
|
|
21
|
+
<td>{{ object.description | placeholder }}</td>
|
|
22
|
+
</tr>
|
|
23
|
+
<tr>
|
|
24
|
+
<th scope="row">{% trans "Expression" %}</th>
|
|
25
|
+
<td>{{ object.expression | placeholder }}</td>
|
|
26
|
+
</tr>
|
|
27
|
+
</table>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
{% plugin_left_page object %}
|
|
31
|
+
</div>
|
|
32
|
+
<div class="col col-12 col-md-6">
|
|
33
|
+
{% include 'inc/panels/related_objects.html' %}
|
|
34
|
+
{% include 'inc/panels/comments.html' %}
|
|
35
|
+
{% include 'inc/panels/custom_fields.html' %}
|
|
36
|
+
{% plugin_right_page object %}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
{% endblock %}
|