Răsfoiți Sursa

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

Jeremy Stretch 3 luni în urmă
părinte
comite
3d143d635b

+ 10 - 0
docs/configuration/miscellaneous.md

@@ -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`

+ 11 - 7
docs/development/user-preferences.md

@@ -6,10 +6,14 @@ For end‑user 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   |
+| Name                       | Description                                                   |
+|----------------------------|---------------------------------------------------------------|
+| `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                   |

+ 2 - 2
netbox/core/forms/model_forms.py

@@ -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'))
     )

+ 9 - 0
netbox/netbox/config/parameters.py

@@ -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'),

+ 6 - 1
netbox/netbox/context_processors.py

@@ -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',
     }
 
 

+ 9 - 0
netbox/netbox/preferences.py

@@ -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(),

+ 7 - 0
netbox/netbox/settings.py

@@ -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
 #

+ 3 - 0
netbox/templates/base/base.html

@@ -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 #}

+ 4 - 0
netbox/templates/core/inc/config_data.html

@@ -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>

+ 8 - 4
netbox/users/forms/model_forms.py

@@ -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