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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 69 additions and 14 deletions

View File

@ -53,6 +53,16 @@ Sets content for the top banner in the user interface.
---
## COPILOT_ENABLED
!!! tip "Dynamic Configuration Parameter"
Default: `True`
Enables or disables the [NetBox Copilot](https://netboxlabs.com/docs/copilot/) agent globally. When enabled, users can opt to toggle the agent individually.
---
## CENSUS_REPORTING_ENABLED
Default: `True`

View File

@ -7,9 +7,13 @@ For enduser guidance on resetting saved table layouts, see [Features > User P
## Available Preferences
| Name | Description |
|--------------------------|---------------------------------------------------------------|
| data_format | Preferred format when rendering raw data (JSON or YAML) |
| pagination.per_page | The number of items to display per page of a paginated table |
| pagination.placement | Where to display the paginator controls relative to the table |
| tables.${table}.columns | The ordered list of columns to display when viewing the table |
| tables.${table}.ordering | A list of column names by which the table should be ordered |
|----------------------------|---------------------------------------------------------------|
| `csv_delimiter` | The delimiting character used when exporting CSV data |
| `data_format` | Preferred format when rendering raw data (JSON or YAML) |
| `locale.language` | The language selected for UI translation |
| `pagination.per_page` | The number of items to display per page of a paginated table |
| `pagination.placement` | Where to display the paginator controls relative to the table |
| `tables.${table}.columns` | The ordered list of columns to display when viewing the table |
| `tables.${table}.ordering` | A list of column names by which the table should be ordered |
| `ui.copilot_enabled` | Toggles the NetBox Copilot AI agent |
| `ui.tables.striping` | Toggles visual striping of tables in the UI |

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