Skip to content

Commit 2d23ad7

Browse files
committed
Use AJAX for notifications table
Signed-off-by: Andrew Thornton <[email protected]>
1 parent 74cc3c5 commit 2d23ad7

File tree

4 files changed

+172
-95
lines changed

4 files changed

+172
-95
lines changed

routers/user/notification.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package user
77
import (
88
"errors"
99
"fmt"
10+
"net/http"
1011
"strconv"
1112
"strings"
1213

@@ -17,7 +18,8 @@ import (
1718
)
1819

1920
const (
20-
tplNotification base.TplName = "user/notification/notification"
21+
tplNotification base.TplName = "user/notification/notification"
22+
tplNotificationDiv = "user/notification/notification_div"
2123
)
2224

2325
// GetNotificationCount is the middleware that sets the notification count in the context
@@ -41,6 +43,14 @@ func GetNotificationCount(c *context.Context) {
4143

4244
// Notifications is the notifications page
4345
func Notifications(c *context.Context) {
46+
getNotifications(c)
47+
if c.Written() {
48+
return
49+
}
50+
c.HTML(http.StatusOK, tplNotification)
51+
}
52+
53+
func getNotifications(c *context.Context) {
4454
var (
4555
keyword = strings.Trim(c.Query("q"), " ")
4656
status models.NotificationStatus
@@ -126,8 +136,6 @@ func Notifications(c *context.Context) {
126136

127137
pager.SetDefaultParams(c)
128138
c.Data["Page"] = pager
129-
130-
c.HTML(200, tplNotification)
131139
}
132140

133141
// NotificationStatusPost is a route for changing the status of a notification
@@ -155,8 +163,17 @@ func NotificationStatusPost(c *context.Context) {
155163
return
156164
}
157165

158-
url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, c.Query("page"))
159-
c.Redirect(url, 303)
166+
if !c.QueryBool("noredirect") {
167+
url := fmt.Sprintf("%s/notifications?page=%s", setting.AppSubURL, c.Query("page"))
168+
c.Redirect(url, http.StatusSeeOther)
169+
}
170+
171+
getNotifications(c)
172+
if c.Written() {
173+
return
174+
}
175+
176+
c.HTML(http.StatusOK, tplNotificationDiv)
160177
}
161178

162179
// NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read
@@ -168,5 +185,5 @@ func NotificationPurgePost(c *context.Context) {
168185
}
169186

170187
url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
171-
c.Redirect(url, 303)
188+
c.Redirect(url, http.StatusSeeOther)
172189
}

templates/user/notification/notification.tmpl

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -23,95 +23,7 @@
2323
</form>
2424
{{end}}
2525
</div>
26-
<div class="ui bottom attached active tab segment">
27-
{{if eq (len .Notifications) 0}}
28-
{{if eq .Status 1}}
29-
{{.i18n.Tr "notification.no_unread"}}
30-
{{else}}
31-
{{.i18n.Tr "notification.no_read"}}
32-
{{end}}
33-
{{else}}
34-
<table class="ui unstackable striped very compact small selectable table">
35-
<tbody>
36-
{{range $notification := .Notifications}}
37-
{{$issue := $notification.Issue}}
38-
{{$repo := $notification.Repository}}
39-
{{$repoOwner := $repo.MustOwner}}
40-
41-
<tr data-href="{{$notification.HTMLURL}}">
42-
<td class="collapsing">
43-
{{if eq $notification.Status 3}}
44-
<span class="blue">{{svg "octicon-pin" 16}}</span>
45-
{{else if $issue.IsPull}}
46-
{{if $issue.IsClosed}}
47-
{{if $issue.GetPullRequest.HasMerged}}
48-
<span class="purple">{{svg "octicon-git-merge" 16}}</span>
49-
{{else}}
50-
<span class="red">{{svg "octicon-git-pull-request" 16}}</span>
51-
{{end}}
52-
{{else}}
53-
<span class="green">{{svg "octicon-git-pull-request" 16}}</span>
54-
{{end}}
55-
{{else}}
56-
{{if $issue.IsClosed}}
57-
<span class="red">{{svg "octicon-issue-closed" 16}}</span>
58-
{{else}}
59-
<span class="green">{{svg "octicon-issue-opened" 16}}</span>
60-
{{end}}
61-
{{end}}
62-
</td>
63-
<td class="eleven wide">
64-
<a class="item" href="{{$notification.HTMLURL}}">
65-
#{{$issue.Index}} - {{$issue.Title}}
66-
</a>
67-
</td>
68-
<td>
69-
<a class="item" href="{{AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}">
70-
{{$repoOwner.Name}}/{{$repo.Name}}
71-
</a>
72-
</td>
73-
<td class="collapsing">
74-
{{if ne $notification.Status 3}}
75-
<form action="{{AppSubUrl}}/notifications/status" method="POST">
76-
{{$.CsrfTokenHtml}}
77-
<input type="hidden" name="notification_id" value="{{$notification.ID}}" />
78-
<input type="hidden" name="status" value="pinned" />
79-
<button class="ui mini button" title='{{$.i18n.Tr "notification.pin"}}'>
80-
{{svg "octicon-pin" 16}}
81-
</button>
82-
</form>
83-
{{end}}
84-
</td>
85-
<td class="collapsing">
86-
{{if or (eq $notification.Status 1) (eq $notification.Status 3)}}
87-
<form action="{{AppSubUrl}}/notifications/status" method="POST">
88-
{{$.CsrfTokenHtml}}
89-
<input type="hidden" name="notification_id" value="{{$notification.ID}}" />
90-
<input type="hidden" name="status" value="read" />
91-
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}" />
92-
<button class="ui mini button" title='{{$.i18n.Tr "notification.mark_as_read"}}'>
93-
{{svg "octicon-check" 16}}
94-
</button>
95-
</form>
96-
{{else if eq $notification.Status 2}}
97-
<form action="{{AppSubUrl}}/notifications/status" method="POST">
98-
{{$.CsrfTokenHtml}}
99-
<input type="hidden" name="notification_id" value="{{$notification.ID}}" />
100-
<input type="hidden" name="status" value="unread" />
101-
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}" />
102-
<button class="ui mini button" title='{{$.i18n.Tr "notification.mark_as_unread"}}'>
103-
{{svg "octicon-bell" 16}}
104-
</button>
105-
</form>
106-
{{end}}
107-
</td>
108-
</tr>
109-
{{end}}
110-
</tbody>
111-
</table>
112-
{{end}}
113-
</div>
114-
26+
{{template "user/notification/notification_div" .}}
11527
{{template "base/paginate" .}}
11628
</div>
11729
</div>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<div class="ui bottom attached active tab segment" id="notification_div">
2+
{{if eq (len .Notifications) 0}}
3+
{{if eq .Status 1}}
4+
{{.i18n.Tr "notification.no_unread"}}
5+
{{else}}
6+
{{.i18n.Tr "notification.no_read"}}
7+
{{end}}
8+
{{else}}
9+
<table class="ui unstackable striped very compact small selectable table" id="notification_table">
10+
<tbody>
11+
{{range $notification := .Notifications}}
12+
{{$issue := .Issue}}
13+
{{$repo := .Repository}}
14+
{{$repoOwner := $repo.MustOwner}}
15+
<tr id="notification_{{.ID}}">
16+
<td class="collapsing" data-href="{{.HTMLURL}}">
17+
{{if eq .Status 3}}
18+
<span class="blue">{{svg "octicon-pin" 16}}</span>
19+
{{else if $issue.IsPull}}
20+
{{if $issue.IsClosed}}
21+
{{if $issue.GetPullRequest.HasMerged}}
22+
<span class="purple">{{svg "octicon-git-merge" 16}}</span>
23+
{{else}}
24+
<span class="red">{{svg "octicon-git-pull-request" 16}}</span>
25+
{{end}}
26+
{{else}}
27+
<span class="green">{{svg "octicon-git-pull-request" 16}}</span>
28+
{{end}}
29+
{{else}}
30+
{{if $issue.IsClosed}}
31+
<span class="red">{{svg "octicon-issue-closed" 16}}</span>
32+
{{else}}
33+
<span class="green">{{svg "octicon-issue-opened" 16}}</span>
34+
{{end}}
35+
{{end}}
36+
</td>
37+
<td class="eleven wide" data-href="{{.HTMLURL}}">
38+
<a class="item" href="{{.HTMLURL}}">
39+
#{{$issue.Index}} - {{$issue.Title}}
40+
</a>
41+
</td>
42+
<td data-href="{{AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}">
43+
<a class="item" href="{{AppSubUrl}}/{{$repoOwner.Name}}/{{$repo.Name}}">
44+
{{$repoOwner.Name}}/{{$repo.Name}}
45+
</a>
46+
</td>
47+
<td class="collapsing">
48+
{{if ne .Status 3}}
49+
<form action="{{AppSubUrl}}/notifications/status" method="POST">
50+
{{$.CsrfTokenHtml}}
51+
<input type="hidden" name="notification_id" value="{{.ID}}" />
52+
<input type="hidden" name="status" value="pinned" />
53+
<button class="ui mini button" title='{{$.i18n.Tr "notification.pin"}}'
54+
data-url="{{AppSubUrl}}/notifications/status"
55+
data-status="pinned"
56+
data-page="{{$.Page.Paginater.Current}}"
57+
data-notification-id="{{.ID}}"
58+
data-q="{{$.Keyword}}">
59+
{{svg "octicon-pin" 16}}
60+
</button>
61+
</form>
62+
{{end}}
63+
</td>
64+
<td class="collapsing">
65+
{{if or (eq .Status 1) (eq .Status 3)}}
66+
<form action="{{AppSubUrl}}/notifications/status" method="POST">
67+
{{$.CsrfTokenHtml}}
68+
<input type="hidden" name="notification_id" value="{{.ID}}" />
69+
<input type="hidden" name="status" value="read" />
70+
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}" />
71+
<button class="ui mini button" title='{{$.i18n.Tr "notification.mark_as_read"}}'
72+
data-url="{{AppSubUrl}}/notifications/status"
73+
data-status="read"
74+
data-page="{{$.Page.Paginater.Current}}"
75+
data-notification-id="{{.ID}}"
76+
data-q="{{$.Keyword}}">
77+
{{svg "octicon-check" 16}}
78+
</button>
79+
</form>
80+
{{else if eq .Status 2}}
81+
<form action="{{AppSubUrl}}/notifications/status" method="POST">
82+
{{$.CsrfTokenHtml}}
83+
<input type="hidden" name="notification_id" value="{{.ID}}" />
84+
<input type="hidden" name="status" value="unread" />
85+
<input type="hidden" name="page" value="{{$.Page.Paginater.Current}}" />
86+
<button class="ui mini button" title='{{$.i18n.Tr "notification.mark_as_unread"}}'
87+
data-url="{{AppSubUrl}}/notifications/status"
88+
data-status="unread"
89+
data-page="{{$.Page.Paginater.Current}}"
90+
data-notification-id="{{.ID}}"
91+
data-q="{{$.Keyword}}">
92+
{{svg "octicon-bell" 16}}
93+
</button>
94+
</form>
95+
{{end}}
96+
</td>
97+
</tr>
98+
{{end}}
99+
</tbody>
100+
</table>
101+
{{end}}
102+
</div>

web_src/js/index.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,46 @@ function updateIssuesMeta(url, action, issueIds, elementId, isAdd) {
180180
}));
181181
}
182182

183+
function initNotificationsTable() {
184+
const $notificationTable = $('#notification_table');
185+
if ($notificationTable) {
186+
$notificationTable.find('.button').click(function () {
187+
updateNotification(
188+
$(this).data('url'),
189+
$(this).data('status'),
190+
$(this).data('page'),
191+
$(this).data('q'),
192+
$(this).data('notification-id')
193+
).then((data) => {
194+
$('#notification_div').replaceWith(data);
195+
initNotificationsTable();
196+
});
197+
return false;
198+
});
199+
}
200+
}
201+
202+
function updateNotification(url, status, page, q, notificationID) {
203+
return new Promise(((resolve) => {
204+
if (status != "pinned") {
205+
$(`#notification_${notificationID}`).remove();
206+
}
207+
$.ajax({
208+
type: 'POST',
209+
url,
210+
data: {
211+
_csrf: csrf,
212+
notification_id: notificationID,
213+
status,
214+
page,
215+
q,
216+
noredirect: true,
217+
},
218+
success: resolve
219+
});
220+
}));
221+
}
222+
183223
function initRepoStatusChecker() {
184224
const migrating = $('#repo_migrating');
185225
$('#repo_migrating_failed').hide();
@@ -2431,6 +2471,11 @@ $(document).ready(async () => {
24312471
window.location = $(this).data('href');
24322472
});
24332473

2474+
// make table <td> element clickable like a link
2475+
$('td[data-href]').click(function () {
2476+
window.location = $(this).data('href');
2477+
});
2478+
24342479
// Dropzone
24352480
const $dropzone = $('#dropzone');
24362481
if ($dropzone.length > 0) {
@@ -2606,6 +2651,7 @@ $(document).ready(async () => {
26062651
initRepoStatusChecker();
26072652
initTemplateSearch();
26082653
initContextPopups();
2654+
initNotificationsTable();
26092655

26102656
// Repo clone url.
26112657
if ($('#repo-clone-url').length > 0) {

0 commit comments

Comments
 (0)