Add web sort controls and verify live/navigation behavior #117
Description
Work
Add compact sort selectors to the task and memory lists, defaulting to Newest created, and keep the choice with the filters in URL and Back navigation.
Acceptance
- A new task or memory is visible at the expected position.
- Updating an old item moves it only in Recently updated mode.
- Closed/archive filters, parent grouping and Back behave correctly.
- Live inserts and targeted service/HTTP sorting tests pass.
- Narrow screens and keyboard: built for, not visually confirmed. See below.
What was built
Shared/SortSelect.razor is one compact chooser used by the project task list, the project memories tab and the global knowledge page. It is a plain <label> with a native <select>, so keyboard and screen-reader behaviour come from the element rather than from custom handlers.
State moved into the query string. WorkspacePage.LinkQuery builds a query string from only the values that differ from the page default, so an unfiltered list stays at a bare URL while every deliberate choice survives reload, sharing and Back. Tasks, NewTask, TaskDetail and TaskEditor carry the same string on every link between them, so leaving a list and returning lands on the same view.
The knowledge page previously held its five filters in component state and applied them in the browser after the service had already capped the result. All five now travel in the URL and are answered by the database. The "Showing X of Y" line became an honest count that says when the page limit was reached.
Live updates need no special handling: the existing subscription reloads through the same service call, so an inserted item lands wherever the chosen sort puts it.
Verification
TaskListPageRendersTheChosenOrderAndKeepsOpenSubtasksVisible asserts the rendered HTML: default newest-first order, reversed order under created_asc, sort carried on the outgoing links, and a reopened subtask under a closed parent still visible. That test was confirmed to fail against the previous list component, so it is not a vacuous assertion. The browser smoke loop now also renders the filtered, sorted and deliberately malformed knowledge URLs.
Open
The responsive rules (.toolbar-end, .sort-control, the 560px stack) and keyboard behaviour were written but never looked at in a real browser, because the project has no visual test harness and no screenshot step. Worth one manual pass on a phone width.