or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-integration.mdapi-endpoints.mdconfiguration.mdcore-system.mdindex.mdsignals.mdtemplate-integration.mdutilities.mdweb-interface.md

web-interface.mddocs/

0

# Web Interface

1

2

Pre-built Django views for displaying, managing, and interacting with notifications through web interfaces. Includes list views, mark-as-read functionality, and deletion with proper URL routing and login requirements.

3

4

## Capabilities

5

6

### List Views

7

8

Django class-based views for displaying notifications with pagination and authentication requirements.

9

10

```python { .api }

11

class NotificationViewList(ListView):

12

"""Base list view for notifications with common configuration."""

13

template_name = 'notifications/list.html'

14

context_object_name = 'notifications'

15

paginate_by = settings.PAGINATE_BY # From configuration

16

17

@method_decorator(login_required)

18

def dispatch(self, request, *args, **kwargs): ...

19

20

class AllNotificationsList(NotificationViewList):

21

"""List view showing all user notifications."""

22

23

def get_queryset(self):

24

"""

25

Returns all notifications for authenticated user.

26

Respects SOFT_DELETE setting for filtering.

27

28

Returns:

29

QuerySet: User's notifications (active or all based on settings)

30

"""

31

32

class UnreadNotificationsList(NotificationViewList):

33

"""List view showing only unread notifications."""

34

35

def get_queryset(self):

36

"""

37

Returns only unread notifications for authenticated user.

38

39

Returns:

40

QuerySet: User's unread notifications

41

"""

42

```

43

44

### Mark as Read Functions

45

46

View functions for marking notifications as read with proper authentication and redirect handling.

47

48

```python { .api }

49

@login_required

50

def mark_all_as_read(request):

51

"""

52

Mark all user notifications as read and redirect.

53

54

Args:

55

request: Django HTTP request object

56

57

Query Parameters:

58

next (str, optional): URL to redirect to after marking as read

59

60

Returns:

61

HttpResponseRedirect: Redirect to 'next' URL or notifications:unread

62

"""

63

64

@login_required

65

def mark_as_read(request, slug=None):

66

"""

67

Mark specific notification as read and redirect.

68

69

Args:

70

request: Django HTTP request object

71

slug (str): Notification ID slug

72

73

Query Parameters:

74

next (str, optional): URL to redirect to after marking as read

75

76

Returns:

77

HttpResponseRedirect: Redirect to 'next' URL or notifications:unread

78

79

Raises:

80

Http404: If notification not found or doesn't belong to user

81

"""

82

83

@login_required

84

def mark_as_unread(request, slug=None):

85

"""

86

Mark specific notification as unread and redirect.

87

88

Args:

89

request: Django HTTP request object

90

slug (str): Notification ID slug

91

92

Query Parameters:

93

next (str, optional): URL to redirect to after marking as unread

94

95

Returns:

96

HttpResponseRedirect: Redirect to 'next' URL or notifications:unread

97

98

Raises:

99

Http404: If notification not found or doesn't belong to user

100

"""

101

```

102

103

### Delete Function

104

105

View function for deleting notifications with support for both hard and soft deletion.

106

107

```python { .api }

108

@login_required

109

def delete(request, slug=None):

110

"""

111

Delete notification (hard or soft based on settings) and redirect.

112

113

Args:

114

request: Django HTTP request object

115

slug (str): Notification ID slug

116

117

Query Parameters:

118

next (str, optional): URL to redirect to after deletion

119

120

Returns:

121

HttpResponseRedirect: Redirect to 'next' URL or notifications:all

122

123

Raises:

124

Http404: If notification not found or doesn't belong to user

125

126

Note:

127

Deletion behavior depends on SOFT_DELETE setting:

128

- If True: Sets deleted=True and saves

129

- If False: Permanently deletes from database

130

"""

131

```

132

133

### URL Configuration

134

135

Pre-configured URL patterns for notification views with proper namespacing.

136

137

```python { .api }

138

# In notifications/urls.py

139

app_name = 'notifications'

140

141

urlpatterns = [

142

# List views

143

re_path(r'^$', views.AllNotificationsList.as_view(), name='all'),

144

re_path(r'^unread/$', views.UnreadNotificationsList.as_view(), name='unread'),

145

146

# Mark as read/unread

147

re_path(r'^mark-all-as-read/$', views.mark_all_as_read, name='mark_all_as_read'),

148

re_path(r'^mark-as-read/(?P<slug>\d+)/$', views.mark_as_read, name='mark_as_read'),

149

re_path(r'^mark-as-unread/(?P<slug>\d+)/$', views.mark_as_unread, name='mark_as_unread'),

150

151

# Delete

152

re_path(r'^delete/(?P<slug>\d+)/$', views.delete, name='delete'),

153

154

# API endpoints (see API Endpoints documentation)

155

re_path(r'^api/unread_count/$', views.live_unread_notification_count, name='live_unread_notification_count'),

156

re_path(r'^api/all_count/$', views.live_all_notification_count, name='live_all_notification_count'),

157

re_path(r'^api/unread_list/$', views.live_unread_notification_list, name='live_unread_notification_list'),

158

re_path(r'^api/all_list/', views.live_all_notification_list, name='live_all_notification_list'),

159

]

160

```

161

162

### Usage Examples

163

164

#### URL Configuration Setup

165

166

```python

167

# In your main urls.py

168

from django.urls import path, include

169

import notifications.urls

170

171

urlpatterns = [

172

# Other URL patterns...

173

path('inbox/notifications/', include(notifications.urls, namespace='notifications')),

174

# More URL patterns...

175

]

176

```

177

178

#### Template Usage

179

180

```html

181

<!-- In your base template -->

182

<div class="notification-menu">

183

<a href="{% url 'notifications:unread' %}">

184

Unread Notifications

185

<span class="badge">{% notifications_unread %}</span>

186

</a>

187

<ul class="dropdown-menu">

188

<li><a href="{% url 'notifications:all' %}">All Notifications</a></li>

189

<li><a href="{% url 'notifications:unread' %}">Unread</a></li>

190

<li><a href="{% url 'notifications:mark_all_as_read' %}">Mark All as Read</a></li>

191

</ul>

192

</div>

193

194

<!-- In notification list template -->

195

{% for notification in notifications %}

196

<div class="notification {% if notification.unread %}unread{% endif %}">

197

<div class="notification-content">

198

{{ notification.description }}

199

<small>{{ notification.naturaltime }}</small>

200

</div>

201

<div class="notification-actions">

202

{% if notification.unread %}

203

<a href="{% url 'notifications:mark_as_read' notification.slug %}">Mark as Read</a>

204

{% else %}

205

<a href="{% url 'notifications:mark_as_unread' notification.slug %}">Mark as Unread</a>

206

{% endif %}

207

<a href="{% url 'notifications:delete' notification.slug %}"

208

onclick="return confirm('Delete this notification?')">Delete</a>

209

</div>

210

</div>

211

{% endfor %}

212

213

<!-- Pagination -->

214

{% if is_paginated %}

215

<div class="pagination">

216

{% if page_obj.has_previous %}

217

<a href="?page={{ page_obj.previous_page_number }}">&laquo; Previous</a>

218

{% endif %}

219

220

<span class="current">

221

Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}

222

</span>

223

224

{% if page_obj.has_next %}

225

<a href="?page={{ page_obj.next_page_number }}">Next &raquo;</a>

226

{% endif %}

227

</div>

228

{% endif %}

229

```

230

231

#### Custom Templates

232

233

Create your own notification templates by placing them in your templates directory:

234

235

```html

236

<!-- templates/notifications/list.html -->

237

{% extends "base.html" %}

238

{% load notifications_tags %}

239

240

{% block title %}Notifications{% endblock %}

241

242

{% block content %}

243

<div class="notifications-container">

244

<h1>

245

Notifications

246

{% if view.get_queryset|length > 0 %}

247

<span class="count">({{ view.get_queryset|length }})</span>

248

{% endif %}

249

</h1>

250

251

{% if notifications %}

252

<div class="notification-actions">

253

<a href="{% url 'notifications:mark_all_as_read' %}" class="btn btn-primary">

254

Mark All as Read

255

</a>

256

</div>

257

258

<div class="notifications-list">

259

{% for notification in notifications %}

260

{% include "notifications/notice.html" with notification=notification %}

261

{% endfor %}

262

</div>

263

264

<!-- Pagination controls -->

265

{% if is_paginated %}

266

<!-- Pagination HTML here -->

267

{% endif %}

268

269

{% else %}

270

<div class="no-notifications">

271

<p>No notifications found.</p>

272

<a href="{% url 'notifications:all' %}">View All Notifications</a>

273

</div>

274

{% endif %}

275

</div>

276

{% endblock %}

277

```

278

279

#### JavaScript Integration

280

281

```html

282

<!-- For AJAX-based mark as read -->

283

<script>

284

function markAsRead(notificationSlug) {

285

fetch(`/inbox/notifications/mark-as-read/${notificationSlug}/`, {

286

method: 'POST',

287

headers: {

288

'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,

289

},

290

})

291

.then(response => {

292

if (response.ok) {

293

// Update UI to show notification as read

294

document.querySelector(`[data-notification="${notificationSlug}"]`)

295

.classList.remove('unread');

296

}

297

})

298

.catch(error => console.error('Error:', error));

299

}

300

301

function deleteNotification(notificationSlug) {

302

if (confirm('Are you sure you want to delete this notification?')) {

303

fetch(`/inbox/notifications/delete/${notificationSlug}/`, {

304

method: 'POST',

305

headers: {

306

'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,

307

},

308

})

309

.then(response => {

310

if (response.ok) {

311

// Remove notification from DOM

312

document.querySelector(`[data-notification="${notificationSlug}"]`)

313

.remove();

314

}

315

})

316

.catch(error => console.error('Error:', error));

317

}

318

}

319

</script>

320

```

321

322

#### Redirect Handling

323

324

All view functions support the `next` query parameter for custom redirects:

325

326

```html

327

<!-- Redirect back to current page after action -->

328

<a href="{% url 'notifications:mark_as_read' notification.slug %}?next={{ request.get_full_path|urlencode }}">

329

Mark as Read

330

</a>

331

332

<!-- Redirect to specific page -->

333

<a href="{% url 'notifications:delete' notification.slug %}?next={% url 'dashboard' %}">

334

Delete

335

</a>

336

```

337

338

#### Authentication Requirements

339

340

All views require user authentication. For non-authenticated users, they will be redirected to the login page:

341

342

```python

343

# The @login_required decorator handles this automatically

344

# Users will be redirected to settings.LOGIN_URL

345

```