From fad9ad2be4fc800f8710e2a498cc8f536af8827c Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Sun, 17 Nov 2019 19:44:12 -0800 Subject: Display list of feeds per category --- locale/translations.go | 36 ++++++++--- locale/translations/de_DE.json | 2 + locale/translations/en_US.json | 2 + locale/translations/es_ES.json | 2 + locale/translations/fr_FR.json | 2 + locale/translations/it_IT.json | 2 + locale/translations/nl_NL.json | 2 + locale/translations/pl_PL.json | 2 + locale/translations/ru_RU.json | 2 + locale/translations/zh_CN.json | 2 + storage/feed.go | 42 ++++++++++++- template/common.go | 57 ++++++++++++++++++ template/html/categories.html | 9 +-- template/html/category_entries.html | 3 + template/html/category_feeds.html | 34 +++++++++++ template/html/common/feed_list.html | 56 +++++++++++++++++ template/html/edit_category.html | 5 +- template/html/feeds.html | 55 +---------------- template/views.go | 116 ++++++++++++++++-------------------- ui/category_feeds.go | 52 ++++++++++++++++ ui/category_update.go | 2 +- ui/ui.go | 1 + 22 files changed, 345 insertions(+), 141 deletions(-) create mode 100644 template/html/category_feeds.html create mode 100644 template/html/common/feed_list.html create mode 100644 ui/category_feeds.go diff --git a/locale/translations.go b/locale/translations.go index b0e09b3..fa04cde 100644 --- a/locale/translations.go +++ b/locale/translations.go @@ -76,6 +76,7 @@ var translations = map[string]string{ "page.starred.title": "Lesezeichen", "page.categories.title": "Kategorien", "page.categories.no_feed": "Kein Abonnement.", + "page.categories.feeds": "Siehe Abonnements", "page.categories.feed_count": [ "Es gibt %d Abonnement.", "Es gibt %d Abonnements." @@ -175,6 +176,7 @@ var translations = map[string]string{ "alert.no_category_entry": "Es befindet sich kein Artikel in dieser Kategorie.", "alert.no_feed_entry": "Es existiert kein Artikel für dieses Abonnement.", "alert.no_feed": "Es sind keine Abonnements vorhanden.", + "alert.no_feed_in_category": "Für diese Kategorie gibt es kein Abonnement.", "alert.no_history": "Es existiert zur Zeit kein Verlauf.", "alert.feed_error": "Es gibt ein Problem mit diesem Abonnement", "alert.no_search_result": "Es gibt kein Ergebnis für diese Suche.", @@ -379,6 +381,7 @@ var translations = map[string]string{ "page.starred.title": "Starred", "page.categories.title": "Categories", "page.categories.no_feed": "No feed.", + "page.categories.feeds": "See subscriptions", "page.categories.feed_count": [ "There is %d feed.", "There are %d feeds." @@ -478,6 +481,7 @@ var translations = map[string]string{ "alert.no_category_entry": "There are no articles in this category.", "alert.no_feed_entry": "There are no articles for this feed.", "alert.no_feed": "You don't have any subscriptions.", + "alert.no_feed_in_category": "There is no subscription for this category.", "alert.no_history": "There is no history at the moment.", "alert.feed_error": "There is a problem with this feed", "alert.no_search_result": "There are no results for this search.", @@ -662,6 +666,7 @@ var translations = map[string]string{ "page.starred.title": "Marcadores", "page.categories.title": "Categorias", "page.categories.no_feed": "No fuente.", + "page.categories.feeds": "Ver suscripciones", "page.categories.feed_count": [ "Hay %d fuente.", "Hay %d fuentes." @@ -761,6 +766,7 @@ var translations = map[string]string{ "alert.no_category_entry": "No hay artículos en esta categoria.", "alert.no_feed_entry": "No hay artículos para esta fuente.", "alert.no_feed": "No tienes suscripciones.", + "alert.no_feed_in_category": "No hay suscripción para esta categoría.", "alert.no_history": "No hay historial en este momento.", "alert.feed_error": "Hay un problema con esta fuente.", "alert.no_search_result": "No hay resultados para esta búsqueda.", @@ -945,6 +951,7 @@ var translations = map[string]string{ "page.starred.title": "Favoris", "page.categories.title": "Catégories", "page.categories.no_feed": "Aucun abonnement.", + "page.categories.feeds": "Voir les abonnements", "page.categories.feed_count": [ "Il y a %d abonnement.", "Il y a %d abonnements." @@ -1044,6 +1051,7 @@ var translations = map[string]string{ "alert.no_category_entry": "Il n'y a aucun article dans cette catégorie.", "alert.no_feed_entry": "Il n'y a aucun article pour cet abonnement.", "alert.no_feed": "Vous n'avez aucun abonnement.", + "alert.no_feed_in_category": "Il n'y a pas d'abonnement pour cette catégorie.", "alert.no_history": "Il n'y a aucun historique pour le moment.", "alert.feed_error": "Il y a un problème avec cet abonnement", "alert.no_search_result": "Il n'y a aucun résultat pour cette recherche.", @@ -1248,6 +1256,7 @@ var translations = map[string]string{ "page.starred.title": "Preferiti", "page.categories.title": "Categorie", "page.categories.no_feed": "Nessun feed.", + "page.categories.feeds": "Vedi abbonamenti", "page.categories.feed_count": [ "C'è %d feed.", "Ci sono %d feed." @@ -1347,6 +1356,7 @@ var translations = map[string]string{ "alert.no_category_entry": "Questa categoria non contiene alcun articolo.", "alert.no_feed_entry": "Questo feed non contiene alcun articolo.", "alert.no_feed": "Nessun feed disponibile.", + "alert.no_feed_in_category": "Non esiste un abbonamento per questa categoria.", "alert.no_history": "La tua cronologia al momento è vuota.", "alert.feed_error": "Sembra ci sia un problema con questo feed", "alert.no_search_result": "La ricerca non ha prodotto risultati.", @@ -1531,6 +1541,7 @@ var translations = map[string]string{ "page.starred.title": "Favorieten", "page.categories.title": "Categorieën", "page.categories.no_feed": "Geen feeds.", + "page.categories.feeds": "Zie abonnementen", "page.categories.feed_count": [ "Er is %d feed.", "Er zijn %d feeds." @@ -1630,6 +1641,7 @@ var translations = map[string]string{ "alert.no_category_entry": "Deze categorie bevat geen feeds.", "alert.no_feed_entry": "Er zijn geen artikelen in deze feed.", "alert.no_feed": "Je hebt nog geen feeds geabboneerd staan.", + "alert.no_feed_in_category": "Er is geen abonnement voor deze categorie.", "alert.no_history": "Geschiedenis is op dit moment leeg.", "alert.feed_error": "Er is een probleem met deze feed", "alert.no_search_result": "Er is geen resultaat voor deze zoekopdracht.", @@ -1832,6 +1844,7 @@ var translations = map[string]string{ "page.starred.title": "Oznaczone gwiazdką", "page.categories.title": "Kategorie", "page.categories.no_feed": "Brak kanałów.", + "page.categories.feeds": "Zobacz subskrypcje", "page.categories.feed_count": [ "Jest %d kanał.", "Są %d kanały.", @@ -1933,6 +1946,7 @@ var translations = map[string]string{ "alert.no_category_entry": "W tej kategorii nie ma żadnych artykułów", "alert.no_feed_entry": "Nie ma artykułu dla tego kanału.", "alert.no_feed": "Nie masz żadnej subskrypcji.", + "alert.no_feed_in_category": "Nie ma subskrypcji dla tej kategorii.", "alert.no_history": "Obecnie nie ma żadnej historii.", "alert.feed_error": "Z tym kanałem jest problem", "alert.no_search_result": "Brak wyników dla tego wyszukiwania.", @@ -2141,6 +2155,7 @@ var translations = map[string]string{ "page.starred.title": "Избранное", "page.categories.title": "Категории", "page.categories.no_feed": "Нет подписок.", + "page.categories.feeds": "Посмотреть подписку", "page.categories.feed_count": [ "Есть %d подписка.", "Есть %d подписки.", @@ -2242,6 +2257,7 @@ var translations = map[string]string{ "alert.no_category_entry": "В этой категории нет статей.", "alert.no_feed_entry": "В этой подписке отсутствуют статьи.", "alert.no_feed": "У вас нет ни одной подписки.", + "alert.no_feed_in_category": "Для этой категории нет подписки.", "alert.no_history": "Истории пока нет.", "alert.feed_error": "С этой подпиской есть проблема", "alert.no_search_result": "Нет результатов для данного поискового запроса.", @@ -2432,6 +2448,7 @@ var translations = map[string]string{ "page.starred.title": "星标", "page.categories.title": "分类", "page.categories.no_feed": "没有源", + "page.categories.feeds": "查看订阅", "page.categories.feed_count": [ "有 %d 个源" ], @@ -2532,6 +2549,7 @@ var translations = map[string]string{ "alert.no_history": "目前没有历史", "alert.feed_error": "该源存在问题", "alert.no_search_result": "该搜索没有结果", + "alert.no_feed_in_category": "没有该类别的订阅。", "alert.no_unread_entry": "目前没有未读文章", "alert.no_user": "您是目前仅有的用户", "alert.account_unlinked": "您的外部帐户现已解除关联!", @@ -2656,13 +2674,13 @@ var translations = map[string]string{ } var translationsChecksums = map[string]string{ - "de_DE": "ec2dd4be11e4bb29efaa6cd124a1edd2e5271889d31d7fda92781be014388387", - "en_US": "8010481cea76d28aad37c00fb0f481514f81c1581a6172b4a4ad17ad61e2eee0", - "es_ES": "be58c4452068277826022931d86bd561fe150250756a6254985de5aa6d8129b7", - "fr_FR": "4d3fa6084994a7b3121dd9c1f3baf8c1b0e519f6012aeaa805e5132ec1eaa60e", - "it_IT": "3246b020b7ea01f762f19c9ee2825605b0e42f6ffdd34fd6306193597650f8d7", - "nl_NL": "c58d1100bcd345824086d0df255381f7789379d0e2b95e146be009ad82e0aa5f", - "pl_PL": "b438c4119ed5685950293f5c3c629a940c6475ca243c53f65879dfca6fc8cdd6", - "ru_RU": "5b42510b54c678563791010f4c1fad1a024fa7029d268667bbfde1e7a1f02d88", - "zh_CN": "30f72b341911682877bb86b0e82e9127be833625502ae41e9530447bb2f27de3", + "de_DE": "08618fb4a57b1d427ec627ac6c46958bbe16b262a588aa640ad5be8b5e15562d", + "en_US": "a611f133d106bb896bbe15df036838f33b7c7848abbf15829e918233e91783eb", + "es_ES": "f47862bcd9af07d96510c3c24f89f0718f1325cde375954babe73766c62a6eca", + "fr_FR": "0aca382d06630935b905452960a8dceac6f062cd5ebe2967b3837006a282f171", + "it_IT": "60716683ca6d6e311154900508c0f8c389664096f3ab41eb9dd745914d497034", + "nl_NL": "516c91a2be0f0b5c09e0183d61e53bfce2c8f60b8a5cb06593f0170ad6043f99", + "pl_PL": "1fcf9422514fc7ebac57355a50c37d146fad6d19b879ba0dad29c49dfb20e00a", + "ru_RU": "e701297d7c1b456dda066877bc5c6d18c9523f96eff3b4d53d13c6e6bf8f84a6", + "zh_CN": "4da796ef2fdaf1898d2a17be6668b8308daebc97185bf69a698809067856c6ce", } diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json index 83325e0..4960836 100644 --- a/locale/translations/de_DE.json +++ b/locale/translations/de_DE.json @@ -71,6 +71,7 @@ "page.starred.title": "Lesezeichen", "page.categories.title": "Kategorien", "page.categories.no_feed": "Kein Abonnement.", + "page.categories.feeds": "Siehe Abonnements", "page.categories.feed_count": [ "Es gibt %d Abonnement.", "Es gibt %d Abonnements." @@ -170,6 +171,7 @@ "alert.no_category_entry": "Es befindet sich kein Artikel in dieser Kategorie.", "alert.no_feed_entry": "Es existiert kein Artikel für dieses Abonnement.", "alert.no_feed": "Es sind keine Abonnements vorhanden.", + "alert.no_feed_in_category": "Für diese Kategorie gibt es kein Abonnement.", "alert.no_history": "Es existiert zur Zeit kein Verlauf.", "alert.feed_error": "Es gibt ein Problem mit diesem Abonnement", "alert.no_search_result": "Es gibt kein Ergebnis für diese Suche.", diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json index c86e3e2..2153243 100644 --- a/locale/translations/en_US.json +++ b/locale/translations/en_US.json @@ -71,6 +71,7 @@ "page.starred.title": "Starred", "page.categories.title": "Categories", "page.categories.no_feed": "No feed.", + "page.categories.feeds": "See subscriptions", "page.categories.feed_count": [ "There is %d feed.", "There are %d feeds." @@ -170,6 +171,7 @@ "alert.no_category_entry": "There are no articles in this category.", "alert.no_feed_entry": "There are no articles for this feed.", "alert.no_feed": "You don't have any subscriptions.", + "alert.no_feed_in_category": "There is no subscription for this category.", "alert.no_history": "There is no history at the moment.", "alert.feed_error": "There is a problem with this feed", "alert.no_search_result": "There are no results for this search.", diff --git a/locale/translations/es_ES.json b/locale/translations/es_ES.json index ba8f076..de2912a 100644 --- a/locale/translations/es_ES.json +++ b/locale/translations/es_ES.json @@ -71,6 +71,7 @@ "page.starred.title": "Marcadores", "page.categories.title": "Categorias", "page.categories.no_feed": "No fuente.", + "page.categories.feeds": "Ver suscripciones", "page.categories.feed_count": [ "Hay %d fuente.", "Hay %d fuentes." @@ -170,6 +171,7 @@ "alert.no_category_entry": "No hay artículos en esta categoria.", "alert.no_feed_entry": "No hay artículos para esta fuente.", "alert.no_feed": "No tienes suscripciones.", + "alert.no_feed_in_category": "No hay suscripción para esta categoría.", "alert.no_history": "No hay historial en este momento.", "alert.feed_error": "Hay un problema con esta fuente.", "alert.no_search_result": "No hay resultados para esta búsqueda.", diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json index 052913c..9df25d6 100644 --- a/locale/translations/fr_FR.json +++ b/locale/translations/fr_FR.json @@ -71,6 +71,7 @@ "page.starred.title": "Favoris", "page.categories.title": "Catégories", "page.categories.no_feed": "Aucun abonnement.", + "page.categories.feeds": "Voir les abonnements", "page.categories.feed_count": [ "Il y a %d abonnement.", "Il y a %d abonnements." @@ -170,6 +171,7 @@ "alert.no_category_entry": "Il n'y a aucun article dans cette catégorie.", "alert.no_feed_entry": "Il n'y a aucun article pour cet abonnement.", "alert.no_feed": "Vous n'avez aucun abonnement.", + "alert.no_feed_in_category": "Il n'y a pas d'abonnement pour cette catégorie.", "alert.no_history": "Il n'y a aucun historique pour le moment.", "alert.feed_error": "Il y a un problème avec cet abonnement", "alert.no_search_result": "Il n'y a aucun résultat pour cette recherche.", diff --git a/locale/translations/it_IT.json b/locale/translations/it_IT.json index 60daa20..9d84f96 100644 --- a/locale/translations/it_IT.json +++ b/locale/translations/it_IT.json @@ -71,6 +71,7 @@ "page.starred.title": "Preferiti", "page.categories.title": "Categorie", "page.categories.no_feed": "Nessun feed.", + "page.categories.feeds": "Vedi abbonamenti", "page.categories.feed_count": [ "C'è %d feed.", "Ci sono %d feed." @@ -170,6 +171,7 @@ "alert.no_category_entry": "Questa categoria non contiene alcun articolo.", "alert.no_feed_entry": "Questo feed non contiene alcun articolo.", "alert.no_feed": "Nessun feed disponibile.", + "alert.no_feed_in_category": "Non esiste un abbonamento per questa categoria.", "alert.no_history": "La tua cronologia al momento è vuota.", "alert.feed_error": "Sembra ci sia un problema con questo feed", "alert.no_search_result": "La ricerca non ha prodotto risultati.", diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json index 87e2e08..0765a7d 100644 --- a/locale/translations/nl_NL.json +++ b/locale/translations/nl_NL.json @@ -71,6 +71,7 @@ "page.starred.title": "Favorieten", "page.categories.title": "Categorieën", "page.categories.no_feed": "Geen feeds.", + "page.categories.feeds": "Zie abonnementen", "page.categories.feed_count": [ "Er is %d feed.", "Er zijn %d feeds." @@ -170,6 +171,7 @@ "alert.no_category_entry": "Deze categorie bevat geen feeds.", "alert.no_feed_entry": "Er zijn geen artikelen in deze feed.", "alert.no_feed": "Je hebt nog geen feeds geabboneerd staan.", + "alert.no_feed_in_category": "Er is geen abonnement voor deze categorie.", "alert.no_history": "Geschiedenis is op dit moment leeg.", "alert.feed_error": "Er is een probleem met deze feed", "alert.no_search_result": "Er is geen resultaat voor deze zoekopdracht.", diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json index 9fe141b..413945b 100644 --- a/locale/translations/pl_PL.json +++ b/locale/translations/pl_PL.json @@ -71,6 +71,7 @@ "page.starred.title": "Oznaczone gwiazdką", "page.categories.title": "Kategorie", "page.categories.no_feed": "Brak kanałów.", + "page.categories.feeds": "Zobacz subskrypcje", "page.categories.feed_count": [ "Jest %d kanał.", "Są %d kanały.", @@ -172,6 +173,7 @@ "alert.no_category_entry": "W tej kategorii nie ma żadnych artykułów", "alert.no_feed_entry": "Nie ma artykułu dla tego kanału.", "alert.no_feed": "Nie masz żadnej subskrypcji.", + "alert.no_feed_in_category": "Nie ma subskrypcji dla tej kategorii.", "alert.no_history": "Obecnie nie ma żadnej historii.", "alert.feed_error": "Z tym kanałem jest problem", "alert.no_search_result": "Brak wyników dla tego wyszukiwania.", diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json index 27ed092..03ba8cb 100644 --- a/locale/translations/ru_RU.json +++ b/locale/translations/ru_RU.json @@ -71,6 +71,7 @@ "page.starred.title": "Избранное", "page.categories.title": "Категории", "page.categories.no_feed": "Нет подписок.", + "page.categories.feeds": "Посмотреть подписку", "page.categories.feed_count": [ "Есть %d подписка.", "Есть %d подписки.", @@ -172,6 +173,7 @@ "alert.no_category_entry": "В этой категории нет статей.", "alert.no_feed_entry": "В этой подписке отсутствуют статьи.", "alert.no_feed": "У вас нет ни одной подписки.", + "alert.no_feed_in_category": "Для этой категории нет подписки.", "alert.no_history": "Истории пока нет.", "alert.feed_error": "С этой подпиской есть проблема", "alert.no_search_result": "Нет результатов для данного поискового запроса.", diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json index 8748695..da0febc 100644 --- a/locale/translations/zh_CN.json +++ b/locale/translations/zh_CN.json @@ -71,6 +71,7 @@ "page.starred.title": "星标", "page.categories.title": "分类", "page.categories.no_feed": "没有源", + "page.categories.feeds": "查看订阅", "page.categories.feed_count": [ "有 %d 个源" ], @@ -171,6 +172,7 @@ "alert.no_history": "目前没有历史", "alert.feed_error": "该源存在问题", "alert.no_search_result": "该搜索没有结果", + "alert.no_feed_in_category": "没有该类别的订阅。", "alert.no_unread_entry": "目前没有未读文章", "alert.no_user": "您是目前仅有的用户", "alert.account_unlinked": "您的外部帐户现已解除关联!", diff --git a/storage/feed.go b/storage/feed.go index f6ad021..6db3488 100644 --- a/storage/feed.go +++ b/storage/feed.go @@ -139,7 +139,6 @@ func (s *Storage) Feeds(userID int64) (model.Feeds, error) { // FeedsWithCounters returns all feeds of the given user with counters of read and unread entries. func (s *Storage) FeedsWithCounters(userID int64) (model.Feeds, error) { - feeds := make(model.Feeds, 0) query := ` SELECT f.id, @@ -166,7 +165,43 @@ func (s *Storage) FeedsWithCounters(userID int64) (model.Feeds, error) { f.user_id=$1 ORDER BY f.parsing_error_count DESC, unread_count DESC, lower(f.title) ASC ` - rows, err := s.db.Query(query, userID) + return s.fetchFeedsWithCounters(query, userID) +} + +// FeedsByCategoryWithCounters returns all feeds of the given user/category with counters of read and unread entries. +func (s *Storage) FeedsByCategoryWithCounters(userID, categoryID int64) (model.Feeds, error) { + query := ` + SELECT + f.id, + f.feed_url, + f.site_url, + f.title, + f.etag_header, + f.last_modified_header, + f.user_id, + f.checked_at at time zone u.timezone, + f.parsing_error_count, f.parsing_error_msg, + f.scraper_rules, f.rewrite_rules, f.crawler, f.user_agent, + f.username, f.password, f.disabled, + f.category_id, c.title as category_title, + fi.icon_id, + u.timezone, + (SELECT count(*) FROM entries WHERE entries.feed_id=f.id AND status='unread') as unread_count, + (SELECT count(*) FROM entries WHERE entries.feed_id=f.id AND status='read') as read_count + FROM feeds f + LEFT JOIN categories c ON c.id=f.category_id + LEFT JOIN feed_icons fi ON fi.feed_id=f.id + LEFT JOIN users u ON u.id=f.user_id + WHERE + f.user_id=$1 AND f.category_id=$2 + ORDER BY f.parsing_error_count DESC, unread_count DESC, lower(f.title) ASC + ` + return s.fetchFeedsWithCounters(query, userID, categoryID) +} + +func (s *Storage) fetchFeedsWithCounters(query string, args ...interface{}) (model.Feeds, error) { + feeds := make(model.Feeds, 0) + rows, err := s.db.Query(query, args...) if err != nil { return nil, fmt.Errorf(`store: unable to fetch feeds: %v`, err) } @@ -176,7 +211,7 @@ func (s *Storage) FeedsWithCounters(userID int64) (model.Feeds, error) { var feed model.Feed var iconID interface{} var tz string - feed.Category = &model.Category{UserID: userID} + feed.Category = &model.Category{} err := rows.Scan( &feed.ID, @@ -213,6 +248,7 @@ func (s *Storage) FeedsWithCounters(userID int64) (model.Feeds, error) { } feed.CheckedAt = timezone.Convert(tz, feed.CheckedAt) + feed.Category.UserID = feed.UserID feeds = append(feeds, &feed) } diff --git a/template/common.go b/template/common.go index 574e4e1..2539cad 100644 --- a/template/common.go +++ b/template/common.go @@ -21,6 +21,62 @@ var templateCommonMap = map[string]string{ {{ end }} +{{ end }}`, + "feed_list": `{{ define "feed_list" }} +
+ {{ range .feeds }} +
+
+ + {{ if .Icon }} + {{ .Title }} + {{ end }} + {{ if .Disabled }} 🚫 {{ end }} + {{ .Title }} + + + ({{ .UnreadCount }}/{{ .ReadCount }}) + + + {{ .Category.Title }} + +
+
+
    +
  • + {{ domain .SiteURL }} +
  • +
  • + {{ t "page.feeds.last_check" }} +
  • +
+ +
+ {{ if ne .ParsingErrorCount 0 }} +
+ {{ plural "page.feeds.error_count" .ParsingErrorCount .ParsingErrorCount }} + - {{ .ParsingErrorMsg }} +
+ {{ end }} +
+ {{ end }} +
{{ end }}`, "item_meta": `{{ define "item_meta" }}
@@ -274,6 +330,7 @@ var templateCommonMap = map[string]string{ var templateCommonMapChecksums = map[string]string{ "entry_pagination": "4faa91e2eae150c5e4eab4d258e039dfdd413bab7602f0009360e6d52898e353", + "feed_list": "7b7ea2c7df07d048c83d86237d5b5e41bddce561273c652d9265950093ca261b", "item_meta": "34deb081a054f2948ad808bdb2c8603d6ab00c58f2f50c4ead0b47ae092888eb", "layout": "010e31c9dde88cb429b21f4b0c24bb3769043a3ef1ef4a57100314f5910c8725", "pagination": "3386e90c6e1230311459e9a484629bc5d5bf39514a75ef2e73bbbc61142f7abb", diff --git a/template/html/categories.html b/template/html/categories.html index b534ba1..4be3c2f 100644 --- a/template/html/categories.html +++ b/template/html/categories.html @@ -20,18 +20,13 @@ {{ .Title }} + ({{ .FeedCount }})
- diff --git a/template/html/category_feeds.html b/template/html/category_feeds.html new file mode 100644 index 0000000..b903256 --- /dev/null +++ b/template/html/category_feeds.html @@ -0,0 +1,34 @@ +{{ define "title"}}{{ .category.Title }} > {{ t "page.feeds.title" }} ({{ .total }}){{ end }} + +{{ define "content"}} + + +{{ if not .feeds }} +

{{ t "alert.no_feed_in_category" }}

+{{ else }} + {{ template "feed_list" dict "user" .user "feeds" .feeds "ParsingErrorCount" .ParsingErrorCount }} +{{ end }} + +{{ end }} diff --git a/template/html/common/feed_list.html b/template/html/common/feed_list.html new file mode 100644 index 0000000..cb80a1f --- /dev/null +++ b/template/html/common/feed_list.html @@ -0,0 +1,56 @@ +{{ define "feed_list" }} +
+ {{ range .feeds }} +
+
+ + {{ if .Icon }} + {{ .Title }} + {{ end }} + {{ if .Disabled }} 🚫 {{ end }} + {{ .Title }} + + + ({{ .UnreadCount }}/{{ .ReadCount }}) + + + {{ .Category.Title }} + +
+
+
    +
  • + {{ domain .SiteURL }} +
  • +
  • + {{ t "page.feeds.last_check" }} +
  • +
+ +
+ {{ if ne .ParsingErrorCount 0 }} +
+ {{ plural "page.feeds.error_count" .ParsingErrorCount .ParsingErrorCount }} + - {{ .ParsingErrorMsg }} +
+ {{ end }} +
+ {{ end }} +
+{{ end }} \ No newline at end of file diff --git a/template/html/edit_category.html b/template/html/edit_category.html index 6b21e46..3506e45 100644 --- a/template/html/edit_category.html +++ b/template/html/edit_category.html @@ -7,6 +7,9 @@
  • {{ t "menu.categories" }}
  • +
  • + {{ t "menu.feeds" }} +
  • {{ t "menu.create_category" }}
  • @@ -24,7 +27,7 @@
    - {{ t "action.or" }} {{ t "action.cancel" }} +
    {{ end }} diff --git a/template/html/feeds.html b/template/html/feeds.html index 7d4a428..e4d24bf 100644 --- a/template/html/feeds.html +++ b/template/html/feeds.html @@ -22,60 +22,7 @@ {{ if not .feeds }}

    {{ t "alert.no_feed" }}

    {{ else }} -
    - {{ range .feeds }} -
    -
    - - {{ if .Icon }} - {{ .Title }} - {{ end }} - {{ if .Disabled }} 🚫 {{ end }} - {{ .Title }} - - - ({{ .UnreadCount }}/{{ .ReadCount }}) - - - {{ .Category.Title }} - -
    -
    -
      -
    • - {{ domain .SiteURL }} -
    • -
    • - {{ t "page.feeds.last_check" }} -
    • -
    - -
    - {{ if ne .ParsingErrorCount 0 }} -
    - {{ plural "page.feeds.error_count" .ParsingErrorCount .ParsingErrorCount }} - - {{ .ParsingErrorMsg }} -
    - {{ end }} -
    - {{ end }} -
    + {{ template "feed_list" dict "user" .user "feeds" .feeds "ParsingErrorCount" .ParsingErrorCount }} {{ end }} {{ end }} diff --git a/template/views.go b/template/views.go index 788e2f5..c4fadb4 100644 --- a/template/views.go +++ b/template/views.go @@ -151,18 +151,13 @@ var templateViewsMap = map[string]string{ {{ .Title }} + ({{ .FeedCount }})
    - @@ -252,6 +250,41 @@ var templateViewsMap = map[string]string{ {{ template "pagination" .pagination }} {{ end }} +{{ end }} +`, + "category_feeds": `{{ define "title"}}{{ .category.Title }} > {{ t "page.feeds.title" }} ({{ .total }}){{ end }} + +{{ define "content"}} + + +{{ if not .feeds }} +

    {{ t "alert.no_feed_in_category" }}

    +{{ else }} + {{ template "feed_list" dict "user" .user "feeds" .feeds "ParsingErrorCount" .ParsingErrorCount }} +{{ end }} + {{ end }} `, "choose_subscription": `{{ define "title"}}{{ t "page.add_feed.title" }}{{ end }} @@ -366,6 +399,9 @@ var templateViewsMap = map[string]string{
  • {{ t "menu.categories" }}
  • +
  • + {{ t "menu.feeds" }} +
  • {{ t "menu.create_category" }}
  • @@ -383,7 +419,7 @@ var templateViewsMap = map[string]string{
    - {{ t "action.or" }} {{ t "action.cancel" }} +
    {{ end }} @@ -778,60 +814,7 @@ var templateViewsMap = map[string]string{ {{ if not .feeds }}

    {{ t "alert.no_feed" }}

    {{ else }} -
    - {{ range .feeds }} -
    -
    - - {{ if .Icon }} - {{ .Title }} - {{ end }} - {{ if .Disabled }} 🚫 {{ end }} - {{ .Title }} - - - ({{ .UnreadCount }}/{{ .ReadCount }}) - - - {{ .Category.Title }} - -
    -
    -
      -
    • - {{ domain .SiteURL }} -
    • -
    • - {{ t "page.feeds.last_check" }} -
    • -
    - -
    - {{ if ne .ParsingErrorCount 0 }} -
    - {{ plural "page.feeds.error_count" .ParsingErrorCount .ParsingErrorCount }} - - {{ .ParsingErrorMsg }} -
    - {{ end }} -
    - {{ end }} -
    + {{ template "feed_list" dict "user" .user "feeds" .feeds "ParsingErrorCount" .ParsingErrorCount }} {{ end }} {{ end }} @@ -1362,17 +1345,18 @@ var templateViewsMapChecksums = map[string]string{ "about": "4035658497363d7af7f79be83190404eb21ec633fe8ec636bdfc219d9fc78cfc", "add_subscription": "a0f1d2bc02b6adc83dbeae593f74d9b936102cd6dd73302cdbec2137cafdcdd9", "bookmark_entries": "65588da78665699dd3f287f68325e9777d511f1a57fee4131a5bb6d00bb68df8", - "categories": "642ee3cddbd825ee6ab5a77caa0d371096b55de0f1bd4ae3055b8c8a70507d8d", - "category_entries": "3ec30d2cb97f29514ff61898a4f23d2aa73a24b3468b6d410b1c2d18c8808927", + "categories": "2c5dd0ed6355bd5acc393bbf6117d20458b5581aab82036008324f6bbbe2af75", + "category_entries": "dee7b9cd60c6c46f01dd4289940679df31c1fce28ce4aa7249fa459023e1eeb4", + "category_feeds": "527c2ffbc4fcec775071424ba1022ae003525dba53a28cc41f48fb7b30aa984b", "choose_subscription": "33c04843d7c1b608d034e605e52681822fc6d79bc6b900c04915dd9ebae584e2", "create_category": "6b22b5ce51abf4e225e23a79f81be09a7fb90acb265e93a8faf9446dff74018d", "create_user": "9b73a55233615e461d1f07d99ad1d4d3b54532588ab960097ba3e090c85aaf3a", - "edit_category": "daf073d2944a180ce5aaeb80b597eb69597a50dff55a9a1d6cf7938b48d768cb", + "edit_category": "b1c0b38f1b714c5d884edcd61e5b5295a5f1c8b71c469b35391e4dcc97cc6d36", "edit_feed": "34aa0d668b3ea1a1b5fa480c20cebeae729b37010af3bb915d2a9eed73d3b996", "edit_user": "c692db9de1a084c57b93e95a14b041d39bf489846cbb91fc982a62b72b77062a", "entry": "24aeba26ef9a51ce585ca5c4af090f1de7d7bfd7f1e3ff1b63af520e2afa76bd", "feed_entries": "9c70b82f55e4b311eff20be1641733612e3c1b406ce8010861e4c417d97b6dcc", - "feeds": "f11ba1c45cf3966843ddc406d96e048fc8f2235428e10111a1660a141ea2c42f", + "feeds": "fa06cd1e1e3fec79132386972c640a2fe91237f5dba572389d5f45be74545f25", "history_entries": "87e17d39de70eb3fdbc4000326283be610928758eae7924e4b08dcb446f3b6a9", "import": "5eb56cecaa4d369b9acc991a82be7617710c551089a2e99d34ce8b6e5c37df0a", "integrations": "6104ff6ff3ac3c1ae5e850c78250aab6e99e2342a337589f3848459fa333766a", diff --git a/ui/category_feeds.go b/ui/category_feeds.go new file mode 100644 index 0000000..202fc3e --- /dev/null +++ b/ui/category_feeds.go @@ -0,0 +1,52 @@ +// Copyright 2019 Frédéric Guillot. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package ui // import "miniflux.app/ui" + +import ( + "net/http" + + "miniflux.app/http/request" + "miniflux.app/http/response/html" + "miniflux.app/ui/session" + "miniflux.app/ui/view" +) + +func (h *handler) showCategoryFeedsPage(w http.ResponseWriter, r *http.Request) { + user, err := h.store.UserByID(request.UserID(r)) + if err != nil { + html.ServerError(w, r, err) + return + } + + categoryID := request.RouteInt64Param(r, "categoryID") + category, err := h.store.Category(request.UserID(r), categoryID) + if err != nil { + html.ServerError(w, r, err) + return + } + + if category == nil { + html.NotFound(w, r) + return + } + + feeds, err := h.store.FeedsByCategoryWithCounters(user.ID, categoryID) + if err != nil { + html.ServerError(w, r, err) + return + } + + sess := session.New(h.store, request.SessionID(r)) + view := view.New(h.tpl, r, sess) + view.Set("category", category) + view.Set("feeds", feeds) + view.Set("total", len(feeds)) + view.Set("menu", "categories") + view.Set("user", user) + view.Set("countUnread", h.store.CountUnreadEntries(user.ID)) + view.Set("countErrorFeeds", h.store.CountErrorFeeds(user.ID)) + + html.OK(w, r, view.Render("category_feeds")) +} diff --git a/ui/category_update.go b/ui/category_update.go index 026f991..591063a 100644 --- a/ui/category_update.go +++ b/ui/category_update.go @@ -66,5 +66,5 @@ func (h *handler) updateCategory(w http.ResponseWriter, r *http.Request) { return } - html.Redirect(w, r, route.Path(h.router, "categories")) + html.Redirect(w, r, route.Path(h.router, "categoryFeeds", "categoryID", categoryID)) } diff --git a/ui/ui.go b/ui/ui.go index dd1a9d8..dabc2fc 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -74,6 +74,7 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool, feedHa uiRouter.HandleFunc("/categories", handler.showCategoryListPage).Name("categories").Methods("GET") uiRouter.HandleFunc("/category/create", handler.showCreateCategoryPage).Name("createCategory").Methods("GET") uiRouter.HandleFunc("/category/save", handler.saveCategory).Name("saveCategory").Methods("POST") + uiRouter.HandleFunc("/category/{categoryID}/feeds", handler.showCategoryFeedsPage).Name("categoryFeeds").Methods("GET") uiRouter.HandleFunc("/category/{categoryID}/entries", handler.showCategoryEntriesPage).Name("categoryEntries").Methods("GET") uiRouter.HandleFunc("/category/{categoryID}/entries/all", handler.showCategoryEntriesAllPage).Name("categoryEntriesAll").Methods("GET") uiRouter.HandleFunc("/category/{categoryID}/edit", handler.showEditCategoryPage).Name("editCategory").Methods("GET") -- cgit v1.2.3