Skip to content

Commit 3d143d6

Browse files
Closes #20675: Enable NetBox Copilot integration (#20682)
1 parent 77307b3 commit 3d143d6

File tree

10 files changed

+69
-14
lines changed

10 files changed

+69
-14
lines changed

docs/configuration/miscellaneous.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ Sets content for the top banner in the user interface.
5353

5454
---
5555

56+
## COPILOT_ENABLED
57+
58+
!!! tip "Dynamic Configuration Parameter"
59+
60+
Default: `True`
61+
62+
Enables or disables the [NetBox Copilot](https://netboxlabs.com/docs/copilot/) agent globally. When enabled, users can opt to toggle the agent individually.
63+
64+
---
65+
5666
## CENSUS_REPORTING_ENABLED
5767

5868
Default: `True`

docs/development/user-preferences.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ For end‑user guidance on resetting saved table layouts, see [Features > User P
66

77
## Available Preferences
88

9-
| Name | Description |
10-
|--------------------------|---------------------------------------------------------------|
11-
| data_format | Preferred format when rendering raw data (JSON or YAML) |
12-
| pagination.per_page | The number of items to display per page of a paginated table |
13-
| pagination.placement | Where to display the paginator controls relative to the table |
14-
| tables.${table}.columns | The ordered list of columns to display when viewing the table |
15-
| tables.${table}.ordering | A list of column names by which the table should be ordered |
9+
| Name | Description |
10+
|----------------------------|---------------------------------------------------------------|
11+
| `csv_delimiter` | The delimiting character used when exporting CSV data |
12+
| `data_format` | Preferred format when rendering raw data (JSON or YAML) |
13+
| `locale.language` | The language selected for UI translation |
14+
| `pagination.per_page` | The number of items to display per page of a paginated table |
15+
| `pagination.placement` | Where to display the paginator controls relative to the table |
16+
| `tables.${table}.columns` | The ordered list of columns to display when viewing the table |
17+
| `tables.${table}.ordering` | A list of column names by which the table should be ordered |
18+
| `ui.copilot_enabled` | Toggles the NetBox Copilot AI agent |
19+
| `ui.tables.striping` | Toggles visual striping of tables in the UI |

netbox/core/forms/model_forms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ class ConfigRevisionForm(forms.ModelForm, metaclass=ConfigFormMetaclass):
166166
FieldSet('CUSTOM_VALIDATORS', 'PROTECTION_RULES', name=_('Validation')),
167167
FieldSet('DEFAULT_USER_PREFERENCES', name=_('User Preferences')),
168168
FieldSet(
169-
'MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL',
170-
name=_('Miscellaneous')
169+
'MAINTENANCE_MODE', 'COPILOT_ENABLED', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION',
170+
'MAPS_URL', name=_('Miscellaneous'),
171171
),
172172
FieldSet('comment', name=_('Config Revision'))
173173
)

netbox/netbox/config/parameters.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ def __init__(self, name, label, default, description='', field=None, field_kwarg
183183
description=_("Enable maintenance mode"),
184184
field=forms.BooleanField
185185
),
186+
ConfigParam(
187+
name='COPILOT_ENABLED',
188+
label=_('NetBox Copilot enabled'),
189+
default=True,
190+
description=_(
191+
"Enable the NetBox Copilot AI agent globally. If enabled, users can toggle the agent individually."
192+
),
193+
field=forms.BooleanField
194+
),
186195
ConfigParam(
187196
name='GRAPHQL_ENABLED',
188197
label=_('GraphQL enabled'),

netbox/netbox/context_processors.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ def preferences(request):
2525
Adds preferences for the current user (if authenticated) to the template context.
2626
Example: {{ preferences|get_key:"pagination.placement" }}
2727
"""
28+
config = get_config()
2829
user_preferences = request.user.config if request.user.is_authenticated else {}
2930
return {
3031
'preferences': user_preferences,
31-
'htmx_navigation': user_preferences.get('ui.htmx_navigation', False) == 'true'
32+
'copilot_enabled': (
33+
config.COPILOT_ENABLED and not django_settings.ISOLATED_DEPLOYMENT and
34+
user_preferences.get('ui.copilot_enabled', False) == 'true'
35+
),
36+
'htmx_navigation': user_preferences.get('ui.htmx_navigation', False) == 'true',
3237
}
3338

3439

netbox/netbox/preferences.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ def get_csv_delimiters():
4949
else ''
5050
)
5151
),
52+
'ui.copilot_enabled': UserPreference(
53+
label=_('NetBox Copilot'),
54+
choices=(
55+
('', _('Disabled')),
56+
('true', _('Enabled')),
57+
),
58+
description=_('Enable the NetBox Copilot AI agent'),
59+
default=False,
60+
),
5261
'pagination.per_page': UserPreference(
5362
label=_('Page length'),
5463
choices=get_page_lengths(),

netbox/netbox/settings.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,13 @@ def _setting(name, default=None):
653653
CENSUS_URL = 'https://census.netbox.oss.netboxlabs.com/api/v1/'
654654

655655

656+
#
657+
# NetBox Copilot
658+
#
659+
660+
NETBOX_COPILOT_URL = 'https://static.copilot.netboxlabs.ai/load.js'
661+
662+
656663
#
657664
# Django social auth
658665
#

netbox/templates/base/base.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
{% block layout %}{% endblock %}
7070

7171
{# Additional Javascript #}
72+
{% if copilot_enabled and request.user.is_authenticated %}
73+
<script src="{{ settings.NETBOX_COPILOT_URL }}" defer></script>
74+
{% endif %}
7275
{% block javascript %}{% endblock %}
7376

7477
{# User messages #}

netbox/templates/core/inc/config_data.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@
129129
<th scope="row" class="ps-3">{% trans "Maintenance mode" %}</th>
130130
<td>{% checkmark config.MAINTENANCE_MODE %}</td>
131131
</tr>
132+
<tr>
133+
<th scope="row" class="ps-3">{% trans "NetBox Copilot enabled" %}</th>
134+
<td>{% checkmark config.COPILOT_ENABLED %}</td>
135+
</tr>
132136
<tr>
133137
<th scope="row" class="ps-3">{% trans "GraphQL enabled" %}</th>
134138
<td>{% checkmark config.GRAPHQL_ENABLED %}</td>

netbox/users/forms/model_forms.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from core.models import ObjectType
1212
from ipam.formfields import IPNetworkFormField
1313
from ipam.validators import prefix_validator
14+
from netbox.config import get_config
1415
from netbox.preferences import PREFERENCES
1516
from users.constants import *
1617
from users.models import *
@@ -64,8 +65,8 @@ def __new__(mcs, name, bases, attrs):
6465
class UserConfigForm(forms.ModelForm, metaclass=UserConfigFormMetaclass):
6566
fieldsets = (
6667
FieldSet(
67-
'locale.language', 'pagination.per_page', 'pagination.placement', 'ui.htmx_navigation',
68-
'ui.tables.striping',
68+
'locale.language', 'ui.copilot_enabled', 'pagination.per_page', 'pagination.placement',
69+
'ui.htmx_navigation', 'ui.tables.striping',
6970
name=_('User Interface')
7071
),
7172
FieldSet('data_format', 'csv_delimiter', name=_('Miscellaneous')),
@@ -83,8 +84,7 @@ class Meta:
8384
def __init__(self, *args, instance=None, **kwargs):
8485

8586
# Get initial data from UserConfig instance
86-
initial_data = flatten_dict(instance.data)
87-
kwargs['initial'] = initial_data
87+
kwargs['initial'] = flatten_dict(instance.data)
8888

8989
super().__init__(*args, instance=instance, **kwargs)
9090

@@ -93,6 +93,10 @@ def __init__(self, *args, instance=None, **kwargs):
9393
(f'tables.{table_name}', '') for table_name in instance.data.get('tables', [])
9494
)
9595

96+
# Disable Copilot preference if it has been disabled globally
97+
if not get_config().COPILOT_ENABLED:
98+
self.fields['ui.copilot_enabled'].disabled = True
99+
96100
def save(self, *args, **kwargs):
97101

98102
# Set UserConfig data

0 commit comments

Comments
 (0)