Merge branch 'main' into feature
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Has been cancelled
CI / build (20.x, 3.12) (push) Has been cancelled
CI / build (20.x, 3.13) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled

This commit is contained in:
Jeremy Stretch
2025-09-16 12:00:48 -04:00
110 changed files with 299711 additions and 37418 deletions

View File

@@ -4,6 +4,7 @@ import django_tables2 as tables
from core.models import *
from netbox.tables import NetBoxTable, columns
from .columns import BackendTypeColumn
from .template_code import DATA_SOURCE_SYNC_BUTTON
__all__ = (
'DataFileTable',
@@ -37,6 +38,9 @@ class DataSourceTable(NetBoxTable):
tags = columns.TagColumn(
url_name='core:datasource_list',
)
actions = columns.ActionsColumn(
extra_buttons=DATA_SOURCE_SYNC_BUTTON,
)
class Meta(NetBoxTable.Meta):
model = DataSource

View File

@@ -1,10 +1,8 @@
import django_tables2 as tables
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from netbox.tables import BaseTable, columns
from .template_code import PLUGIN_IS_INSTALLED
from .template_code import PLUGIN_IS_INSTALLED, PLUGIN_NAME_TEMPLATE
__all__ = (
'CatalogPluginTable',
@@ -12,12 +10,6 @@ __all__ = (
)
PLUGIN_NAME_TEMPLATE = """
<img class="plugin-icon" src="{{ record.icon_url }}">
<a href="{% url 'core:plugin' record.config_name %}">{{ record.title_long }}</a>
"""
class PluginVersionTable(BaseTable):
version = tables.Column(
verbose_name=_('Version')
@@ -61,6 +53,7 @@ class CatalogPluginTable(BaseTable):
verbose_name=_('Local')
)
is_installed = columns.TemplateColumn(
accessor=tables.A('is_loaded'),
verbose_name=_('Active'),
template_code=PLUGIN_IS_INSTALLED
)
@@ -93,10 +86,4 @@ class CatalogPluginTable(BaseTable):
)
# List installed plugins first, then certified plugins, then
# everything else (with each tranche ordered alphabetically)
order_by = ('-is_installed', '-is_certified', 'name')
def render_title_long(self, value, record):
if record.static:
return value
url = reverse('core:plugin', args=[record.config_name])
return mark_safe(f"<a href='{url}'>{value}</a>")
order_by = ('-is_installed', '-is_certified', 'title_long')

View File

@@ -26,3 +26,29 @@ PLUGIN_IS_INSTALLED = """
<span class="text-muted">&mdash;</span>
{% endif %}
"""
PLUGIN_NAME_TEMPLATE = """
{% load static %}
{% if record.icon_url %}
<img class="plugin-icon" src="{{ record.icon_url }}">
{% else %}
<img class="plugin-icon" src="{% static 'plugin-default.svg' %}">
{% endif %}
<a href="{% url 'core:plugin' record.config_name %}">{{ record.title_long }}</a>
"""
DATA_SOURCE_SYNC_BUTTON = """
{% load helpers %}
{% load i18n %}
{% if perms.core.sync_datasource %}
{% if record.ready_for_sync %}
<button class="btn btn-primary btn-sm" type="submit" formaction="{% url 'core:datasource_sync' pk=record.pk %}?return_url={{ request.get_full_path|urlencode }}" formmethod="post">
<i class="mdi mdi-sync" aria-hidden="true"></i> {% trans "Sync" %}
</button>
{% else %}
<button class="btn btn-primary btn-sm" disabled>
<i class="mdi mdi-sync" aria-hidden="true"></i> {% trans "Sync" %}
</button>
{% endif %}
{% endif %}
"""

View File

@@ -33,7 +33,13 @@ from utilities.forms import ConfirmationForm
from utilities.htmx import htmx_partial
from utilities.json import ConfigJSONEncoder
from utilities.query import count_related
from utilities.views import ContentTypePermissionRequiredMixin, GetRelatedModelsMixin, ViewTab, register_model_view
from utilities.views import (
ContentTypePermissionRequiredMixin,
GetRelatedModelsMixin,
GetReturnURLMixin,
ViewTab,
register_model_view,
)
from . import filtersets, forms, tables
from .jobs import SyncDataSourceJob
from .models import *
@@ -66,7 +72,7 @@ class DataSourceView(GetRelatedModelsMixin, generic.ObjectView):
@register_model_view(DataSource, 'sync')
class DataSourceSyncView(BaseObjectView):
class DataSourceSyncView(GetReturnURLMixin, BaseObjectView):
queryset = DataSource.objects.all()
def get_required_permission(self):
@@ -85,7 +91,7 @@ class DataSourceSyncView(BaseObjectView):
request,
_("Queued job #{id} to sync {datasource}").format(id=job.pk, datasource=datasource)
)
return redirect(datasource.get_absolute_url())
return redirect(self.get_return_url(request, datasource))
@register_model_view(DataSource, 'add', detail=False)