Closes #20675: Enable NetBox Copilot integration (#20682)

This commit is contained in:
Jeremy Stretch
2025-10-27 09:54:38 -04:00
committed by GitHub
parent 77307b3c91
commit 3d143d635b
10 changed files with 69 additions and 14 deletions

View File

@@ -166,8 +166,8 @@ class ConfigRevisionForm(forms.ModelForm, metaclass=ConfigFormMetaclass):
FieldSet('CUSTOM_VALIDATORS', 'PROTECTION_RULES', name=_('Validation')),
FieldSet('DEFAULT_USER_PREFERENCES', name=_('User Preferences')),
FieldSet(
'MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL',
name=_('Miscellaneous')
'MAINTENANCE_MODE', 'COPILOT_ENABLED', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION',
'MAPS_URL', name=_('Miscellaneous'),
),
FieldSet('comment', name=_('Config Revision'))
)

View File

@@ -183,6 +183,15 @@ PARAMS = (
description=_("Enable maintenance mode"),
field=forms.BooleanField
),
ConfigParam(
name='COPILOT_ENABLED',
label=_('NetBox Copilot enabled'),
default=True,
description=_(
"Enable the NetBox Copilot AI agent globally. If enabled, users can toggle the agent individually."
),
field=forms.BooleanField
),
ConfigParam(
name='GRAPHQL_ENABLED',
label=_('GraphQL enabled'),

View File

@@ -25,10 +25,15 @@ def preferences(request):
Adds preferences for the current user (if authenticated) to the template context.
Example: {{ preferences|get_key:"pagination.placement" }}
"""
config = get_config()
user_preferences = request.user.config if request.user.is_authenticated else {}
return {
'preferences': user_preferences,
'htmx_navigation': user_preferences.get('ui.htmx_navigation', False) == 'true'
'copilot_enabled': (
config.COPILOT_ENABLED and not django_settings.ISOLATED_DEPLOYMENT and
user_preferences.get('ui.copilot_enabled', False) == 'true'
),
'htmx_navigation': user_preferences.get('ui.htmx_navigation', False) == 'true',
}

View File

@@ -49,6 +49,15 @@ PREFERENCES = {
else ''
)
),
'ui.copilot_enabled': UserPreference(
label=_('NetBox Copilot'),
choices=(
('', _('Disabled')),
('true', _('Enabled')),
),
description=_('Enable the NetBox Copilot AI agent'),
default=False,
),
'pagination.per_page': UserPreference(
label=_('Page length'),
choices=get_page_lengths(),

View File

@@ -653,6 +653,13 @@ DEPLOYMENT_ID = hashlib.sha256(SECRET_KEY.encode('utf-8')).hexdigest()[:16]
CENSUS_URL = 'https://census.netbox.oss.netboxlabs.com/api/v1/'
#
# NetBox Copilot
#
NETBOX_COPILOT_URL = 'https://static.copilot.netboxlabs.ai/load.js'
#
# Django social auth
#

View File

@@ -69,6 +69,9 @@
{% block layout %}{% endblock %}
{# Additional Javascript #}
{% if copilot_enabled and request.user.is_authenticated %}
<script src="{{ settings.NETBOX_COPILOT_URL }}" defer></script>
{% endif %}
{% block javascript %}{% endblock %}
{# User messages #}

View File

@@ -129,6 +129,10 @@
<th scope="row" class="ps-3">{% trans "Maintenance mode" %}</th>
<td>{% checkmark config.MAINTENANCE_MODE %}</td>
</tr>
<tr>
<th scope="row" class="ps-3">{% trans "NetBox Copilot enabled" %}</th>
<td>{% checkmark config.COPILOT_ENABLED %}</td>
</tr>
<tr>
<th scope="row" class="ps-3">{% trans "GraphQL enabled" %}</th>
<td>{% checkmark config.GRAPHQL_ENABLED %}</td>

View File

@@ -11,6 +11,7 @@ from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from ipam.formfields import IPNetworkFormField
from ipam.validators import prefix_validator
from netbox.config import get_config
from netbox.preferences import PREFERENCES
from users.constants import *
from users.models import *
@@ -64,8 +65,8 @@ class UserConfigFormMetaclass(forms.models.ModelFormMetaclass):
class UserConfigForm(forms.ModelForm, metaclass=UserConfigFormMetaclass):
fieldsets = (
FieldSet(
'locale.language', 'pagination.per_page', 'pagination.placement', 'ui.htmx_navigation',
'ui.tables.striping',
'locale.language', 'ui.copilot_enabled', 'pagination.per_page', 'pagination.placement',
'ui.htmx_navigation', 'ui.tables.striping',
name=_('User Interface')
),
FieldSet('data_format', 'csv_delimiter', name=_('Miscellaneous')),
@@ -83,8 +84,7 @@ class UserConfigForm(forms.ModelForm, metaclass=UserConfigFormMetaclass):
def __init__(self, *args, instance=None, **kwargs):
# Get initial data from UserConfig instance
initial_data = flatten_dict(instance.data)
kwargs['initial'] = initial_data
kwargs['initial'] = flatten_dict(instance.data)
super().__init__(*args, instance=instance, **kwargs)
@@ -93,6 +93,10 @@ class UserConfigForm(forms.ModelForm, metaclass=UserConfigFormMetaclass):
(f'tables.{table_name}', '') for table_name in instance.data.get('tables', [])
)
# Disable Copilot preference if it has been disabled globally
if not get_config().COPILOT_ENABLED:
self.fields['ui.copilot_enabled'].disabled = True
def save(self, *args, **kwargs):
# Set UserConfig data