diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-13 12:26:43 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-13 12:26:43 -0800 |
| commit | a1baa8f9655e6fc4343475d2a38b2d7f6c7d0955 (patch) | |
| tree | cf48c128f3690440262dfb251f6e7d265763716c | |
| parent | f8fcc0be57fa7f471ffd22d4b9559cb6d0ff20bf (diff) | |
| download | neko-a1baa8f9655e6fc4343475d2a38b2d7f6c7d0955.tar.gz neko-a1baa8f9655e6fc4343475d2a38b2d7f6c7d0955.tar.bz2 neko-a1baa8f9655e6fc4343475d2a38b2d7f6c7d0955.zip | |
UI: remove explicit mark read buttons (NK-ahzf5c)
| -rw-r--r-- | .thicket/tickets.jsonl | 13 | ||||
| -rw-r--r-- | frontend/src/components/FeedItem.test.tsx | 38 | ||||
| -rw-r--r-- | frontend/src/components/FeedItem.tsx | 10 |
3 files changed, 10 insertions, 51 deletions
diff --git a/.thicket/tickets.jsonl b/.thicket/tickets.jsonl index 953cce0..d3c70fc 100644 --- a/.thicket/tickets.jsonl +++ b/.thicket/tickets.jsonl @@ -8,31 +8,38 @@ {"id":"NK-5ocxgm","title":"Infinite scroll","description":"a key feature of the original version that when you scroll to the bottom, it catches that and loads more (based on the current filters, etc)","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:27:01.14879752Z","updated":"2026-02-13T19:45:02.283640203Z"} {"id":"NK-6q9nyg","title":"Refactor HTTP-dependent functions for testability","description":"Several functions use http.Get or external libraries directly (GetFullContent uses goose, ResolveFeedURL uses http.Get + goquery, imageProxyHandler uses http.Client). Refactor these to accept interfaces for HTTP fetching so they can be unit tested with mocks. This is the primary blocker for reaching 90% coverage.","type":"cleanup","status":"open","priority":3,"labels":null,"assignee":"","created":"2026-02-13T03:54:37.630148644Z","updated":"2026-02-13T03:54:37.630148644Z"} {"id":"NK-7tzbql","title":"Fix TUI Content View Navigation and Interaction","description":"The TUI content view (reading a single item) is currently non-functional or severely limited. Users cannot easily navigate back, scroll, or interact with the content. This task involves improving the 'viewContent' state in the TUI.","type":"bug","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T05:02:57.382793121Z","updated":"2026-02-13T05:06:15.144485446Z"} +{"id":"NK-8s75ec","title":"page size and performance","description":"Do some analysis of page size (css/html/javascript) on the legacy version vs. new version and give me a report. We want it to be small and fast! If the new version is much worse file some tickets to investigate further.","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T20:16:13.898081788Z","updated":"2026-02-13T20:16:13.898081788Z"} {"id":"NK-9hx0y7","title":"Implement Frontend Login","description":"Create login page and auth logic in the new React frontend. Port functionality from legacy login.html.","type":"","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T05:44:01.546395342Z","updated":"2026-02-13T05:50:33.877452063Z"} -{"id":"NK-ahzf5c","title":"drop \"mark read\" button","description":"there's no mark read/unread buttons, it's just by scrolling!","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:28:20.708443259Z","updated":"2026-02-13T19:28:20.708443259Z"} +{"id":"NK-ahzf5c","title":"drop \"mark read\" button","description":"there's no mark read/unread buttons, it's just by scrolling!","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:28:20.708443259Z","updated":"2026-02-13T20:26:43.029168286Z"} {"id":"NK-bsdwqz","title":"terminal UI","description":"once there is good test coverage and a clean backend API, work on a nice efficient TUI with https://github.com/charmbracelet/bubbletea","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T01:54:02.285738454Z","updated":"2026-02-13T04:42:09.824268427Z"} {"id":"NK-ed1iah","title":"Make feed crawling async in API","description":"Currently, POST /api/feed triggers an immediate crawl which blocks the response (or at least keeps the goroutine alive). Refactor the crawling architecture to be truly async with a job queue or status updates, improving API responsiveness and reliability.","type":"cleanup","status":"open","priority":4,"labels":null,"assignee":"","created":"2026-02-13T04:26:55.908243985Z","updated":"2026-02-13T04:26:55.908243985Z"} {"id":"NK-ek0cox","title":"Implement Item Interactions","description":"Add ability to toggle read/unread and star/unstar status for items. Use PUT /item/:id","type":"","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T14:55:14.825454967Z","updated":"2026-02-13T14:58:18.307521003Z"} {"id":"NK-fnaohu","title":"UI Styling: Dark Mode Support","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:05:19.59504351Z","updated":"2026-02-13T18:11:46.326064329Z"} {"id":"NK-gqkh96","title":"Remaining test coverage gaps","description":"Cross-package test coverage is at 81.2%. The remaining untested functions are: GetFullContent (goose HTTP extraction), indexHandler/serveBoxedFile (rice.MustFindBox), Serve (starts HTTP server), main, util.init. To reach 90%, consider: (1) refactoring GetFullContent to accept an interface for HTTP fetching, (2) refactoring Serve to extract route setup into a testable function, (3) mocking rice.MustFindBox, (4) using feeds from https://trenchant.org/feeds.txt as static test fixtures for integration tests.","type":"cleanup","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T03:54:30.298141982Z","updated":"2026-02-13T03:54:30.298141982Z"} +{"id":"NK-jhludy","title":"600px width by default, closer to left panel","description":"On desktop the feed items are too narrow (~500px) compared to legacy version which is ~600px.","type":"bug","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T20:14:48.84900972Z","updated":"2026-02-13T20:14:48.84900972Z"} +{"id":"NK-kqt9oc","title":"docker support","description":"add support so people can self-host this in docker and (maybe) test it yourself. maybe keep it in a docker directory with separate docs etc.","type":"epic","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T20:19:10.70328135Z","updated":"2026-02-13T20:19:10.70328135Z"} {"id":"NK-lrew5z","title":"UI Styling: Global Typography \u0026 Layout (Fixed Width)","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:04:57.254341682Z","updated":"2026-02-13T18:11:31.436752093Z"} {"id":"NK-mwf9q2","title":"Implement Tag View","description":"Create frontend view for browsing items by tag/category. Use /tag/:id endpoint.","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T15:04:12.441165286Z","updated":"2026-02-13T18:04:38.644796168Z"} +{"id":"NK-ojdcmq","title":"UI: Add skeleton loaders for feed item loading","description":"The currently 'Loading more...' text is basic. We should add skeleton loaders for a smoother infinite scroll experience.","type":"task","status":"open","priority":3,"labels":null,"assignee":"","created":"2026-02-13T19:45:07.376295295Z","updated":"2026-02-13T19:45:07.376295295Z"} {"id":"NK-op5594","title":"Ensure 80% Frontend Test Coverage","description":"Configure coverage reporting in vitest and ensure the frontend codebase maintains at least 80% test coverage.","type":"task","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T05:46:24.13314466Z","updated":"2026-02-13T05:50:46.728239299Z"} {"id":"NK-qwef98","title":"UI Styling: Controls \u0026 Header","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:05:18.450759919Z","updated":"2026-02-13T18:11:46.291830432Z"} -{"id":"NK-ric1zs","title":"Migrate frontend to /api/ endpoints","description":"The backend now provides a clean REST API at /api/. Update the frontend UI to use these new endpoints instead of the legacy backward-compatibility routes (/stream/, /feed/, etc.). This will allow for cleaner separation and better utilization of proper REST patterns.","type":"cleanup","status":"open","priority":3,"labels":null,"assignee":"","created":"2026-02-13T04:26:55.864725765Z","updated":"2026-02-13T04:26:55.864725765Z"} +{"id":"NK-ric1zs","title":"Migrate frontend to /api/ endpoints","description":"The backend now provides a clean REST API at /api/. Update the frontend UI to use these new endpoints instead of the legacy backward-compatibility routes (/stream/, /feed/, etc.). This will allow for cleaner separation and better utilization of proper REST patterns.","type":"cleanup","status":"closed","priority":3,"labels":null,"assignee":"","created":"2026-02-13T04:26:55.864725765Z","updated":"2026-02-13T04:26:55.864725765Z"} {"id":"NK-shpyxh","title":"add search to new ui","description":"","type":"epic","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T19:29:44.251257089Z","updated":"2026-02-13T19:29:44.251257089Z"} {"id":"NK-sne5ox","title":"Implement Export/Import UI","description":"Add UI in settings to download OPML export and upload OPML import. Use /export/ and /import/ (need to check if import exists).","type":"feature","status":"open","priority":3,"labels":null,"assignee":"","created":"2026-02-13T15:05:23.266731399Z","updated":"2026-02-13T15:05:23.266731399Z"} {"id":"NK-t0nmbj","title":"new web frontend","description":"The current frontend uses an old version of backbone and jquery. Let's \"deprecate\" it -- keep it arouond so we can test against it and use it, but let's be able to also serve and use a nice shiny new frontend written in either simiple, highly efficient vanilla javascript, or put together something in react or similar. Needs to feel fast and low latency!\n\nIt's very important that this new frontend has all the functionality of the existing one AND looks similar (use same style, etc, but adjust a little if needed.)\n\nALSO make it highly testable and have high test coverage as you go. I don't want it to use the Chrome browser plugin thing, just test it on your own using things from the command line you can do.","type":"epic","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T02:01:37.2107893Z","updated":"2026-02-13T05:43:47.613995925Z"} {"id":"NK-tw0nga","title":"E2E Testing","description":"Set up E2E testing with Playwright or Cypress to verify full flows: Login -\u003e View Feeds -\u003e View Items -\u003e Logout","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T15:01:33.817314728Z","updated":"2026-02-13T15:46:57.094062908Z"} {"id":"NK-uy90he","title":"UI Styling: Feed Items (Spacing, Dateline)","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:05:17.289457994Z","updated":"2026-02-13T18:11:46.255816698Z"} +{"id":"NK-uywybr","title":"https://computer.rip/rss.xml fails to importa","description":"running neko -a https://computer.rip/rss.xml gave an error. debug it and add test case to catch.","type":"bug","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T20:12:28.54350403Z","updated":"2026-02-13T20:12:28.54350403Z"} +{"id":"NK-wibjlg","title":"update README.md","description":"Ensure the build, configuration, etc are up too date.\nNote the git change when we started to vibe-code this in the history (with dates etc.)","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T20:18:08.790048498Z","updated":"2026-02-13T20:18:08.790048498Z"} {"id":"NK-x924bu","title":"test coverage","description":"assume the code works properly (it mostly does)\nget to 90% test coverage on the go code","type":"task","status":"closed","priority":0,"labels":null,"assignee":"","created":"2026-02-13T01:52:01.042476226Z","updated":"2026-02-13T03:54:21.526519915Z"} -{"id":"NK-ymf1jb","title":"add \"star\" back in","description":"rather than the word \"star\" it should just have a star that changes colors right next to the title","type":"task","status":"open","priority":1,"labels":null,"assignee":"","created":"2026-02-13T19:29:05.582140321Z","updated":"2026-02-13T19:29:05.582140321Z"} +{"id":"NK-ymf1jb","title":"add \"star\" back in","description":"rather than the word \"star\" it should just have a star that changes colors right next to the title","type":"task","status":"open","priority":0,"labels":null,"assignee":"","created":"2026-02-13T19:29:05.582140321Z","updated":"2026-02-13T19:29:05.582140321Z"} {"id":"NK-zs9we8","title":"UI Styling: Sidebar (Fixed, Gray Background)","description":"","type":"","status":"closed","priority":2,"labels":null,"assignee":"","created":"2026-02-13T18:05:16.188317572Z","updated":"2026-02-13T18:11:46.213993245Z"} {"id":"NK-zt4e32","title":"Implement Frontend Feed List","description":"Create feed list view in new frontend. Fetch feeds from API.","type":"task","status":"closed","priority":1,"labels":null,"assignee":"","created":"2026-02-13T05:44:01.58866298Z","updated":"2026-02-13T05:59:46.132148641Z"} {"id":"NK-d0ghccy","from_ticket_id":"NK-ric1zs","to_ticket_id":"NK-1phdpf","type":"created_from","created":"2026-02-13T04:26:55.875394997Z"} {"id":"NK-d0lgaab","from_ticket_id":"NK-sne5ox","to_ticket_id":"NK-0ppv3f","type":"created_from","created":"2026-02-13T15:05:23.289745853Z"} {"id":"NK-d1uyy71","from_ticket_id":"NK-27or4b","to_ticket_id":"NK-bsdwqz","type":"created_from","created":"2026-02-13T05:03:09.689282214Z"} {"id":"NK-d50pbhs","from_ticket_id":"NK-zt4e32","to_ticket_id":"NK-t0nmbj","type":"created_from","created":"2026-02-13T05:44:01.598803513Z"} +{"id":"NK-d58l5y5","from_ticket_id":"NK-ojdcmq","to_ticket_id":"NK-5ocxgm","type":"created_from","created":"2026-02-13T19:45:07.395109046Z"} {"id":"NK-d86tgcs","from_ticket_id":"NK-ed1iah","to_ticket_id":"NK-1phdpf","type":"created_from","created":"2026-02-13T04:26:55.917754798Z"} {"id":"NK-dda9zfr","from_ticket_id":"NK-lrew5z","to_ticket_id":"NK-mwf9q2","type":"created_from","created":"2026-02-13T18:04:57.273164732Z"} {"id":"NK-dew7hvb","from_ticket_id":"NK-tw0nga","to_ticket_id":"NK-59kbij","type":"created_from","created":"2026-02-13T15:01:33.825547908Z"} diff --git a/frontend/src/components/FeedItem.test.tsx b/frontend/src/components/FeedItem.test.tsx index d46afaf..5e7522f 100644 --- a/frontend/src/components/FeedItem.test.tsx +++ b/frontend/src/components/FeedItem.test.tsx @@ -30,27 +30,6 @@ describe('FeedItem Component', () => { // Check for relative time or date formatting? For now just check it renders }); - it('toggles read status', async () => { - (global.fetch as any).mockResolvedValueOnce({ ok: true, json: async () => ({}) }); - - render(<FeedItem item={mockItem} />); - - const readBtn = screen.getByTitle('Mark as read'); - fireEvent.click(readBtn); - - // Optimistic update - expect(await screen.findByTitle('Mark as unread')).toBeInTheDocument(); - - expect(global.fetch).toHaveBeenCalledWith('/api/item/1', expect.objectContaining({ - method: 'PUT', - body: JSON.stringify({ - _id: 1, - read: true, - starred: false - }) - })); - }); - it('toggles star status', async () => { (global.fetch as any).mockResolvedValueOnce({ ok: true, json: async () => ({}) }); @@ -71,21 +50,4 @@ describe('FeedItem Component', () => { }) })); }); - - it('reverts optimistic update on failure', async () => { - (global.fetch as any).mockRejectedValueOnce(new Error('API Error')); - const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { }); - - render(<FeedItem item={mockItem} />); - - const readBtn = screen.getByTitle('Mark as read'); - fireEvent.click(readBtn); - - // Should revert to unread - await waitFor(() => { - expect(screen.getByTitle('Mark as read')).toBeInTheDocument(); - }); - - consoleSpy.mockRestore(); - }); }); diff --git a/frontend/src/components/FeedItem.tsx b/frontend/src/components/FeedItem.tsx index ae6f8a5..03910e4 100644 --- a/frontend/src/components/FeedItem.tsx +++ b/frontend/src/components/FeedItem.tsx @@ -10,9 +10,6 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) { const [item, setItem] = useState(initialItem); const [loading, setLoading] = useState(false); - const toggleRead = () => { - updateItem({ ...item, read: !item.read }); - }; const toggleStar = () => { updateItem({ ...item, starred: !item.starred }); @@ -68,13 +65,6 @@ export default function FeedItem({ item: initialItem }: FeedItemProps) { </a> <div className="item-actions" style={{ display: 'inline-block', float: 'right' }}> <button - onClick={toggleRead} - className={`action-btn ${item.read ? 'is-read' : 'is-unread'}`} - title={item.read ? "Mark as unread" : "Mark as read"} - > - {item.read ? 'keep unread' : 'mark read'} - </button> - <button onClick={toggleStar} className={`action-btn ${item.starred ? 'is-starred' : 'is-unstarred'}`} title={item.starred ? "Unstar" : "Star"} |
