Closes #15621: User notifications (#16800)

* Initial work on #15621

* Signal receiver should ignore models which don't support notifications

* Flesh out NotificationGroup functionality

* Add NotificationGroup filters for users & groups

* Separate read & dimiss actions

* Enable one-click dismissals from notifications list

* Include total notification count in dropdown

* Drop 'kind' field from Notification model

* Register event types in the registry; add colors & icons

* Enable event rules to target notification groups

* Define dynamic choices for Notification.event_name

* Move event registration to core

* Add more job events

* Misc cleanup

* Misc cleanup

* Correct absolute URLs for notifications & subscriptions

* Optimize subscriber notifications

* Use core event types when queuing events

* Standardize queued event attribute to event_type; change content_type to object_type

* Rename Notification.event_name to event_type

* Restore NotificationGroupBulkEditView

* Add API tests

* Add view & filterset tests

* Add model documentation

* Fix tests

* Update notification bell when notifications have been cleared

* Ensure subscribe button appears only on relevant models

* Notifications/subscriptions cannot be ordered by object

* Misc cleanup

* Add event icon & type to notifications table

* Adjust icon sizing

* Mute color of read notifications

* Misc cleanup
This commit is contained in:
Jeremy Stretch
2024-07-15 14:24:11 -04:00
committed by GitHub
parent 1c2336be60
commit b0e7294bc1
59 changed files with 1913 additions and 90 deletions

View File

@@ -0,0 +1,13 @@
from django.utils.translation import gettext as _
from netbox.tables.columns import ActionsColumn, ActionsItem
__all__ = (
'NotificationActionsColumn',
)
class NotificationActionsColumn(ActionsColumn):
actions = {
'dismiss': ActionsItem(_('Dismiss'), 'trash-can-outline', 'delete', 'danger'),
}

View File

@@ -7,6 +7,7 @@ from django.utils.translation import gettext_lazy as _
from extras.models import *
from netbox.constants import EMPTY_TABLE_TEXT
from netbox.tables import BaseTable, NetBoxTable, columns
from .columns import NotificationActionsColumn
__all__ = (
'BookmarkTable',
@@ -19,21 +20,28 @@ __all__ = (
'ExportTemplateTable',
'ImageAttachmentTable',
'JournalEntryTable',
'NotificationGroupTable',
'NotificationTable',
'SavedFilterTable',
'ReportResultsTable',
'ScriptResultsTable',
'SubscriptionTable',
'TaggedItemTable',
'TagTable',
'WebhookTable',
)
IMAGEATTACHMENT_IMAGE = '''
IMAGEATTACHMENT_IMAGE = """
{% if record.image %}
<a class="image-preview" href="{{ record.image.url }}" target="_blank">{{ record }}</a>
{% else %}
&mdash;
{% endif %}
'''
"""
NOTIFICATION_ICON = """
<span class="text-{{ value.color }} fs-3"><i class="{{ value.icon }}"></i></span>
"""
class CustomFieldTable(NetBoxTable):
@@ -263,6 +271,93 @@ class BookmarkTable(NetBoxTable):
default_columns = ('object', 'object_type', 'created')
class SubscriptionTable(NetBoxTable):
object_type = columns.ContentTypeColumn(
verbose_name=_('Object Type'),
)
object = tables.Column(
verbose_name=_('Object'),
linkify=True,
orderable=False
)
user = tables.Column(
verbose_name=_('User'),
linkify=True
)
actions = columns.ActionsColumn(
actions=('delete',)
)
class Meta(NetBoxTable.Meta):
model = Subscription
fields = ('pk', 'object', 'object_type', 'created', 'user')
default_columns = ('object', 'object_type', 'created')
class NotificationTable(NetBoxTable):
icon = columns.TemplateColumn(
template_code=NOTIFICATION_ICON,
accessor=tables.A('event'),
attrs={
'td': {'class': 'w-1'},
'th': {'class': 'w-1'},
},
verbose_name=''
)
object_type = columns.ContentTypeColumn(
verbose_name=_('Object Type'),
)
object = tables.Column(
verbose_name=_('Object'),
linkify={
'viewname': 'extras:notification_read',
'args': [tables.A('pk')],
},
orderable=False
)
created = columns.DateTimeColumn(
timespec='minutes',
verbose_name=_('Created'),
)
read = columns.DateTimeColumn(
timespec='minutes',
verbose_name=_('Read'),
)
user = tables.Column(
verbose_name=_('User'),
linkify=True
)
actions = NotificationActionsColumn(
actions=('dismiss',)
)
class Meta(NetBoxTable.Meta):
model = Notification
fields = ('pk', 'icon', 'object', 'object_type', 'event_type', 'created', 'read', 'user')
default_columns = ('icon', 'object', 'object_type', 'event_type', 'created')
row_attrs = {
'data-read': lambda record: bool(record.read),
}
class NotificationGroupTable(NetBoxTable):
name = tables.Column(
linkify=True,
verbose_name=_('Name')
)
users = columns.ManyToManyColumn(
linkify_item=True
)
groups = columns.ManyToManyColumn(
linkify_item=True
)
class Meta(NetBoxTable.Meta):
model = NotificationGroup
fields = ('pk', 'name', 'description', 'groups', 'users')
default_columns = ('name', 'description', 'groups', 'users')
class WebhookTable(NetBoxTable):
name = tables.Column(
verbose_name=_('Name'),