Show count of feeds with permanent errors in header menu

Only for feeds that reach `maxParsingError` are counted (so transient errors do not trigger counter).
This commit is contained in:
Dave Z 2018-08-26 19:18:07 -04:00 committed by Frédéric Guillot
parent aae62aae08
commit 9169fbafb2
42 changed files with 71 additions and 13 deletions

View file

@ -46,6 +46,17 @@ func (s *Storage) CountFeeds(userID int64) int {
return result
}
// CountErrorFeeds returns the number of feeds with parse errors that belong to the given user.
func (s *Storage) CountErrorFeeds(userID int64) int {
var result int
err := s.db.QueryRow(`SELECT count(*) FROM feeds WHERE user_id=$1 AND parsing_error_count>=$2`, userID, maxParsingError).Scan(&result)
if err != nil {
return 0
}
return result
}
// Feeds returns all feeds of the given user.
func (s *Storage) Feeds(userID int64) (model.Feeds, error) {
defer timer.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Feeds] userID=%d", userID))

View file

@ -134,7 +134,11 @@ var templateCommonMap = map[string]string{
<a href="{{ route "history" }}" data-page="history">{{ t "History" }}</a>
</li>
<li {{ if eq .menu "feeds" }}class="active"{{ end }} title="{{ t "Keyboard Shortcut: %s" "g f" }}">
<a href="{{ route "feeds" }}" data-page="feeds">{{ t "Feeds" }}</a>
<a href="{{ route "feeds" }}" data-page="feeds">{{ t "Feeds" }}
{{ if gt .countErrorFeeds 0 }}
<span class="error-feeds-counter-wrapper">(<span class="error-feeds-counter">{{ .countErrorFeeds }}</span>)</span>
{{ end }}
</a>
</li>
<li {{ if eq .menu "categories" }}class="active"{{ end }} title="{{ t "Keyboard Shortcut: %s" "g c" }}">
<a href="{{ route "categories" }}" data-page="categories">{{ t "Categories" }}</a>
@ -239,6 +243,6 @@ var templateCommonMap = map[string]string{
var templateCommonMapChecksums = map[string]string{
"entry_pagination": "756ef122f3ebc73754b5fc4304bf05e59da0ab4af030b2509ff4c9b4a74096ce",
"item_meta": "2da78476f6c7fb8742c969ad1bfc20b7b61fddf97d79a77baf3cabda52f6fb49",
"layout": "952632cafa23e02e3ae74c33a6606e127ab7bff0b82a2aa848967da8966475a5",
"layout": "2491695e33a496c9bd902a2cb5bc3a6a540f98ac7c24591d503a77ba0f5f0ebe",
"pagination": "b592d58ea9d6abf2dc0b158621404cbfaeea5413b1c8b8b9818725963096b196",
}

View file

@ -60,7 +60,11 @@
<a href="{{ route "history" }}" data-page="history">{{ t "History" }}</a>
</li>
<li {{ if eq .menu "feeds" }}class="active"{{ end }} title="{{ t "Keyboard Shortcut: %s" "g f" }}">
<a href="{{ route "feeds" }}" data-page="feeds">{{ t "Feeds" }}</a>
<a href="{{ route "feeds" }}" data-page="feeds">{{ t "Feeds" }}
{{ if gt .countErrorFeeds 0 }}
<span class="error-feeds-counter-wrapper">(<span class="error-feeds-counter">{{ .countErrorFeeds }}</span>)</span>
{{ end }}
</a>
</li>
<li {{ if eq .menu "categories" }}class="active"{{ end }} title="{{ t "Keyboard Shortcut: %s" "g c" }}">
<a href="{{ route "categories" }}" data-page="categories">{{ t "Categories" }}</a>

View file

@ -31,6 +31,7 @@ func (c *Controller) About(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("about"))
}

View file

@ -56,6 +56,7 @@ func (c *Controller) ShowStarredPage(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "starred")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("bookmark_entries"))

View file

@ -28,6 +28,7 @@ func (c *Controller) CreateCategory(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("create_category"))
}

View file

@ -53,6 +53,7 @@ func (c *Controller) EditCategory(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("edit_category"))
}

View file

@ -73,6 +73,7 @@ func (c *Controller) CategoryEntries(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("category_entries"))

View file

@ -36,6 +36,7 @@ func (c *Controller) CategoryList(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("categories"))
}

View file

@ -36,6 +36,7 @@ func (c *Controller) SaveCategory(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
if err := categoryForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())

View file

@ -54,6 +54,7 @@ func (c *Controller) UpdateCategory(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
if err := categoryForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())

View file

@ -86,6 +86,7 @@ func (c *Controller) ShowStarredEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "starred")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("entry"))

View file

@ -93,6 +93,7 @@ func (c *Controller) ShowCategoryEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "categories")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("entry"))

View file

@ -93,6 +93,7 @@ func (c *Controller) ShowFeedEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("entry"))

View file

@ -76,6 +76,7 @@ func (c *Controller) ShowReadEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "history")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("entry"))

View file

@ -89,6 +89,7 @@ func (c *Controller) ShowSearchEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "search")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("entry"))

View file

@ -95,6 +95,7 @@ func (c *Controller) ShowUnreadEntry(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "unread")
view.Set("user", user)
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
// Fetching the counter here avoid to be off by one.
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))

View file

@ -68,6 +68,7 @@ func (c *Controller) EditFeed(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("edit_feed"))
}

View file

@ -73,6 +73,7 @@ func (c *Controller) ShowFeedEntries(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("feed_entries"))

View file

@ -36,6 +36,7 @@ func (c *Controller) ShowFeedsPage(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("feeds"))
}

View file

@ -61,6 +61,7 @@ func (c *Controller) UpdateFeed(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
if err := feedForm.ValidateModification(); err != nil {
view.Set("errorMessage", err.Error())

View file

@ -54,6 +54,7 @@ func (c *Controller) ShowHistoryPage(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "history")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("history_entries"))

View file

@ -61,6 +61,7 @@ func (c *Controller) ShowIntegrations(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasPocketConsumerKeyConfigured", c.cfg.PocketConsumerKey("") != "")
html.OK(w, r, view.Render("integrations"))

View file

@ -28,6 +28,7 @@ func (c *Controller) Import(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("import"))
}

View file

@ -47,6 +47,7 @@ func (c *Controller) UploadOPML(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
if fileHeader.Size == 0 {
view.Set("errorMessage", "This file is empty")

View file

@ -60,6 +60,7 @@ func (c *Controller) ShowSearchEntries(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "search")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("search_entries"))

View file

@ -39,6 +39,7 @@ func (c *Controller) ShowSessions(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("sessions"))
}

View file

@ -49,6 +49,7 @@ func (c *Controller) ShowSettings(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("settings"))
}

View file

@ -46,6 +46,7 @@ func (c *Controller) UpdateSettings(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
if err := settingsForm.Validate(); err != nil {
view.Set("errorMessage", err.Error())

File diff suppressed because one or more lines are too long

View file

@ -125,8 +125,9 @@ input[type="text"]:focus {
color: #9b9b9b;
}
/* Counter */
.unread-counter-wrapper {
/* Counters */
.unread-counter-wrapper,
.error-feeds-counter-wrapper {
color: #bbb;
}

View file

@ -467,8 +467,9 @@ a.button {
max-width: 280px;
}
/* Counter */
.unread-counter-wrapper {
/* Counters */
.unread-counter-wrapper,
.error-feeds-counter-wrapper {
font-size: 0.9em;
font-weight: 300;
color: #666;

View file

@ -35,6 +35,7 @@ func (c *Controller) AddSubscription(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("add_subscription"))
}

View file

@ -40,6 +40,7 @@ func (c *Controller) Bookmarklet(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("add_subscription"))
}

View file

@ -38,6 +38,7 @@ func (c *Controller) ChooseSubscription(w http.ResponseWriter, r *http.Request)
view.Set("menu", "feeds")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
subscriptionForm := form.NewSubscriptionForm(r)
if err := subscriptionForm.Validate(); err != nil {

View file

@ -40,6 +40,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
v.Set("menu", "feeds")
v.Set("user", user)
v.Set("countUnread", c.store.CountUnreadEntries(user.ID))
v.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
subscriptionForm := form.NewSubscriptionForm(r)
if err := subscriptionForm.Validate(); err != nil {
@ -94,6 +95,7 @@ func (c *Controller) SubmitSubscription(w http.ResponseWriter, r *http.Request)
v.Set("menu", "feeds")
v.Set("user", user)
v.Set("countUnread", c.store.CountUnreadEntries(user.ID))
v.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, v.Render("choose_subscription"))
}

View file

@ -58,6 +58,7 @@ func (c *Controller) ShowUnreadPage(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "unread")
view.Set("user", user)
view.Set("countUnread", countUnread)
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("hasSaveEntry", c.store.HasSaveEntry(user.ID))
html.OK(w, r, view.Render("unread_entries"))

View file

@ -35,6 +35,7 @@ func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("create_user"))
}

View file

@ -59,6 +59,7 @@ func (c *Controller) EditUser(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("edit_user"))
}

View file

@ -42,6 +42,7 @@ func (c *Controller) ShowUsers(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
html.OK(w, r, view.Render("users"))
}

View file

@ -39,6 +39,7 @@ func (c *Controller) SaveUser(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("form", userForm)
if err := userForm.ValidateCreation(); err != nil {

View file

@ -57,6 +57,7 @@ func (c *Controller) UpdateUser(w http.ResponseWriter, r *http.Request) {
view.Set("menu", "settings")
view.Set("user", user)
view.Set("countUnread", c.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", c.store.CountErrorFeeds(user.ID))
view.Set("selected_user", selectedUser)
view.Set("form", userForm)