mirror of
				https://github.com/nkanaev/yarr.git
				synced 2025-10-29 22:29:59 +00:00 
			
		
		
		
	mark items read
This commit is contained in:
		| @@ -300,7 +300,19 @@ func ItemListHandler(rw http.ResponseWriter, req *http.Request) { | |||||||
| 			filter.Status = &statusValue | 			filter.Status = &statusValue | ||||||
| 		} | 		} | ||||||
| 		items := db(req).ListItems(filter)	 | 		items := db(req).ListItems(filter)	 | ||||||
|  | 		rw.WriteHeader(http.StatusOK) | ||||||
| 		writeJSON(rw, items) | 		writeJSON(rw, items) | ||||||
|  | 	} else if req.Method == "PUT" { | ||||||
|  | 		query := req.URL.Query() | ||||||
|  | 		filter := storage.ItemFilter{} | ||||||
|  | 		if folderID, err := strconv.ParseInt(query.Get("folder_id"), 10, 64); err == nil { | ||||||
|  | 			filter.FolderID = &folderID | ||||||
|  | 		} | ||||||
|  | 		if feedID, err := strconv.ParseInt(query.Get("feed_id"), 10, 64); err == nil { | ||||||
|  | 			filter.FeedID = &feedID | ||||||
|  | 		} | ||||||
|  | 		db(req).MarkItemsRead(filter) | ||||||
|  | 		rw.WriteHeader(http.StatusOK) | ||||||
| 	} else { | 	} else { | ||||||
| 		rw.WriteHeader(http.StatusMethodNotAllowed) | 		rw.WriteHeader(http.StatusMethodNotAllowed) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -161,3 +161,34 @@ func (s *Storage) UpdateItemStatus(item_id int64, status ItemStatus) bool { | |||||||
| 	_, err := s.db.Exec(`update items set status = ? where id = ?`, status, item_id) | 	_, err := s.db.Exec(`update items set status = ? where id = ?`, status, item_id) | ||||||
| 	return err == nil | 	return err == nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (s *Storage) MarkItemsRead(filter ItemFilter) bool { | ||||||
|  | 	cond := make([]string, 0) | ||||||
|  | 	args := make([]interface{}, 0) | ||||||
|  |  | ||||||
|  | 	if filter.FolderID != nil { | ||||||
|  | 		cond = append(cond, "f.folder_id = ?") | ||||||
|  | 		args = append(args, *filter.FolderID) | ||||||
|  | 	} | ||||||
|  | 	if filter.FeedID != nil { | ||||||
|  | 		cond = append(cond, "i.feed_id = ?") | ||||||
|  | 		args = append(args, *filter.FeedID) | ||||||
|  | 	} | ||||||
|  | 	predicate := "1" | ||||||
|  | 	if len(cond) > 0 { | ||||||
|  | 		predicate = strings.Join(cond, " and ") | ||||||
|  | 	} | ||||||
|  | 	query := fmt.Sprintf(` | ||||||
|  | 		update items set status = %d | ||||||
|  | 		where id in ( | ||||||
|  | 			select i.id from items i | ||||||
|  | 			join feeds f on f.id = i.feed_id | ||||||
|  | 			where %s and i.status != %d | ||||||
|  | 		) | ||||||
|  | 		`, READ, predicate, STARRED) | ||||||
|  | 	_, err := s.db.Exec(query, args...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		s.log.Print(err) | ||||||
|  | 	} | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -71,8 +71,13 @@ | |||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="vh-100 overflow-auto border-right flex-shrink-0" style="width: 300px"> |         <div class="vh-100 d-flex flex-column border-right flex-shrink-0" style="width: 300px"> | ||||||
|             <div class="my-2 mx-2"> |             <div class="p-2 border-bottom" v-if="filterSelected != 'starred'"> | ||||||
|  |                 <button class="btn btn-outline-secondary p-0" @click="markItemsRead()"> | ||||||
|  |                     <img src="./static/images/check.svg" alt="" style="width: 20px; height: 20px;"> | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|  |             <div class="p-2 overflow-auto"> | ||||||
|                 <label v-for="item in items" :key="item.id" |                 <label v-for="item in items" :key="item.id" | ||||||
|                        class="nav-select mb-1" |                        class="nav-select mb-1" | ||||||
|                        :class="{'text-muted'  : filterSelected=='all' && item.status=='read', |                        :class="{'text-muted'  : filterSelected=='all' && item.status=='read', | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								template/static/images/check.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								template/static/images/check.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg> | ||||||
| After Width: | Height: | Size: 262 B | 
| @@ -61,7 +61,10 @@ | |||||||
|       }, |       }, | ||||||
|       update: function(id, data) { |       update: function(id, data) { | ||||||
|         return api('put', '/api/items/' + id, data) |         return api('put', '/api/items/' + id, data) | ||||||
|       } |       }, | ||||||
|  |       mark_read: function(query) { | ||||||
|  |         return api('put', '/api/items' + param(query)) | ||||||
|  |       }, | ||||||
|     }, |     }, | ||||||
|     settings: { |     settings: { | ||||||
|       get: function() { |       get: function() { | ||||||
|   | |||||||
| @@ -66,17 +66,7 @@ var vm = new Vue({ | |||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     refreshFeeds: function() { |     getItemsQuery: function() { | ||||||
|       var vm = this |  | ||||||
|       Promise |  | ||||||
|         .all([api.folders.list(), api.feeds.list()]) |  | ||||||
|         .then(function(values) { |  | ||||||
|           vm.folders = values[0] |  | ||||||
|           vm.feeds = values[1] |  | ||||||
|         }) |  | ||||||
|     }, |  | ||||||
|     refreshItems: function() { |  | ||||||
|       var promise = null |  | ||||||
|       var query = {} |       var query = {} | ||||||
|       if (this.feedSelected) { |       if (this.feedSelected) { | ||||||
|         var parts = this.feedSelected.split(':', 2) |         var parts = this.feedSelected.split(':', 2) | ||||||
| @@ -91,10 +81,34 @@ var vm = new Vue({ | |||||||
|       if (this.filterSelected) { |       if (this.filterSelected) { | ||||||
|         query.status = this.filterSelected |         query.status = this.filterSelected | ||||||
|       } |       } | ||||||
|  |       return query | ||||||
|  |     }, | ||||||
|  |     refreshFeeds: function() { | ||||||
|  |       var vm = this | ||||||
|  |       Promise | ||||||
|  |         .all([api.folders.list(), api.feeds.list()]) | ||||||
|  |         .then(function(values) { | ||||||
|  |           vm.folders = values[0] | ||||||
|  |           vm.feeds = values[1] | ||||||
|  |         }) | ||||||
|  |     }, | ||||||
|  |     refreshItems: function() { | ||||||
|  |       var query = this.getItemsQuery() | ||||||
|       api.items.list(query).then(function(items) { |       api.items.list(query).then(function(items) { | ||||||
|         vm.items = items |         vm.items = items | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|  |     markItemsRead: function() { | ||||||
|  |       var vm = this | ||||||
|  |       var query = this.getItemsQuery() | ||||||
|  |       api.items.mark_read(query).then(function() { | ||||||
|  |         vm.items.forEach(function(item) { | ||||||
|  |           if (item.status != 'starred') { | ||||||
|  |             item.status = 'read' | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|     toggleFolderExpanded: function(folder) { |     toggleFolderExpanded: function(folder) { | ||||||
|       folder.is_expanded = !folder.is_expanded |       folder.is_expanded = !folder.is_expanded | ||||||
|     }, |     }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user