2
0
Эх сурвалжийг харах

Fixes #23416: Fix broken and incomplete references in plugin development docs (#23417)

- Correct form field imports in forms.md examples (utilities.forms.fields)
- Remove nonexistent get_form() members from view autodoc directives
- Use a single import path for register_widget() in dashboard-widgets.md
- Document plugin user preferences (UserPreference) and link from PluginConfig
- Add docstrings for NetBoxObjectType and NetBoxModelFilter
Jeremy Stretch 5 цаг өмнө
parent
commit
c3146d4efb

+ 1 - 0
docs/development/user-preferences.md

@@ -13,6 +13,7 @@ For end‑user guidance on resetting saved table layouts, see [Features > User P
 | `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 |
+| `plugins.${plugin}.*`      | Preferences registered by plugins                             |
 | `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                           |

+ 1 - 2
docs/plugins/development/dashboard-widgets.md

@@ -30,8 +30,7 @@ class MyWidget2(DashboardWidget):
 
 ```python
 from django import forms
-from extras.dashboard.utils import register_widget
-from extras.dashboard.widgets import DashboardWidget, WidgetConfigForm
+from extras.dashboard.widgets import DashboardWidget, WidgetConfigForm, register_widget
 
 
 @register_widget

+ 3 - 3
docs/plugins/development/forms.md

@@ -77,7 +77,7 @@ The corresponding model-specific subclasses of `NetBoxModelImportForm` are docum
 from django.utils.translation import gettext_lazy as _
 from dcim.models import Site
 from netbox.forms import NetBoxModelImportForm
-from utilities.forms import CSVModelChoiceField
+from utilities.forms.fields import CSVModelChoiceField
 from .models import MyModel
 
 
@@ -120,7 +120,7 @@ from django import forms
 from django.utils.translation import gettext_lazy as _
 from dcim.models import Site
 from netbox.forms import NetBoxModelBulkEditForm
-from utilities.forms import CommentField, DynamicModelChoiceField
+from utilities.forms.fields import CommentField, DynamicModelChoiceField
 from utilities.forms.rendering import FieldSet
 from .models import MyModel, MyModelStatusChoices
 
@@ -170,7 +170,7 @@ The corresponding model-specific subclasses of `NetBoxModelFilterSetForm` are do
 ```python
 from dcim.models import Site
 from netbox.forms import NetBoxModelFilterSetForm
-from utilities.forms import DynamicModelMultipleChoiceField, MultipleChoiceField
+from utilities.forms.fields import DynamicModelMultipleChoiceField, MultipleChoiceField
 from .models import MyModel, MyModelStatusChoices
 
 class MyModelFilterForm(NetBoxModelFilterSetForm):

+ 1 - 1
docs/plugins/development/index.md

@@ -126,7 +126,7 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
 | `graphql_schema`      | The dotted path to the plugin's GraphQL schema class, if any (default: `graphql.schema`)                                           |
 | `graphql_type_extensions` | The dotted path to the list of GraphQL output-type extension classes, if any (default: `graphql_extensions.type_extensions`)   |
 | `graphql_filter_extensions` | The dotted path to the list of GraphQL filter extension classes, if any (default: `graphql_extensions.filter_extensions`)    |
-| `user_preferences`    | The dotted path to the dictionary mapping of user preferences defined by the plugin (default: `preferences.preferences`)           |
+| `user_preferences`    | The dotted path to the dictionary mapping of user preferences defined by the plugin (default: `preferences.preferences`) |
 
 All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
 

+ 36 - 0
docs/plugins/development/user-interface.md

@@ -12,3 +12,39 @@ window.addEventListener('netbox.colorModeChanged', e => {
   console.log('New color mode:', customEvent.detail.netboxColorMode);
 });
 ```
+
+## User Preferences
+
+Plugins can register their own user preferences, which are displayed in a dedicated "Plugins" section of each user's preferences page. To do so, create a file named `preferences.py` in your plugin and define a dictionary named `preferences` mapping each preference name to a `UserPreference` instance.
+
+```python title="preferences.py"
+from django.utils.translation import gettext_lazy as _
+from users.preferences import UserPreference
+
+preferences = {
+    'default_view': UserPreference(
+        label=_('Default view'),
+        choices=(
+            ('summary', _('Summary')),
+            ('detail', _('Detail')),
+        ),
+        description=_('The default view for plugin objects'),
+    ),
+}
+```
+
+!!! tip
+    The path to the preferences dictionary can be modified by setting `user_preferences` in the PluginConfig instance.
+
+A `UserPreference` accepts the following arguments:
+
+| Argument      | Required | Description                                                                       |
+|---------------|----------|-----------------------------------------------------------------------------------|
+| `label`       | Yes      | The human-friendly name of the preference                                         |
+| `choices`     | Yes      | An iterable of `(value, label)` two-tuples                                        |
+| `default`     | -        | The default value for the preference                                              |
+| `description` | -        | A brief description of the preference                                             |
+| `coerce`      | -        | A callable to convert the submitted value to the appropriate type (e.g. `int`)    |
+| `warning`     | -        | A warning message to display alongside the preference                             |
+
+Each preference is stored under the path `plugins.<plugin_name>.<preference_name>`, where `<plugin_name>` is the last component of the plugin's `PluginConfig.name` (e.g. `netbox_foo` for a plugin named `acme.netbox_foo`). Its value for the current user can be retrieved by calling `get()` on the user's config.

+ 3 - 6
docs/plugins/development/views.md

@@ -172,8 +172,7 @@ Below are the class definitions for NetBox's multi-object views. These views han
 
 ::: netbox.views.generic.BulkDeleteView
     options:
-      members:
-        - get_form
+      members: false
 
 ## Feature Views
 
@@ -184,13 +183,11 @@ These views are provided to enable or enhance certain NetBox model features, suc
 
 ::: netbox.views.generic.ObjectChangeLogView
     options:
-      members:
-        - get_form
+      members: false
 
 ::: netbox.views.generic.ObjectJournalView
     options:
-      members:
-        - get_form
+      members: false
 
 ## Extending Core Views
 

+ 5 - 1
netbox/netbox/graphql/filters.py

@@ -49,7 +49,11 @@ class NetBoxModelFilter(
     ChangeLoggingMixin,
     BaseModelFilter
 ):
-    pass
+    """
+    Base GraphQL filter for models which inherit from NetBoxModel. Adds filters for change logging, custom fields,
+    journal entries, and tags. Subclasses of PrimaryModel, OrganizationalModel, and NestedGroupModel should use the
+    corresponding filter class instead.
+    """
 
 
 @dataclass

+ 6 - 1
netbox/netbox/graphql/types.py

@@ -189,7 +189,12 @@ class NetBoxObjectType(
     TagsMixin,
     BaseObjectType
 ):
-    pass
+    """
+    Base GraphQL object type for models which inherit from NetBoxModel. Adds change logging, custom fields, journal
+    entries, and tags. Subclasses of PrimaryModel, OrganizationalModel, and NestedLtreeGroupModel should use
+    PrimaryObjectType, OrganizationalObjectType, and NestedLtreeGroupObjectType respectively, which add the `owner`
+    field (and `level`, for NestedLtreeGroupObjectType).
+    """
 
 
 #