labtasker-webui 0.1.1__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.agents/sops/qa.md +15 -1
  2. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/AGENTS.md +1 -1
  3. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/PKG-INFO +22 -2
  4. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/README.md +20 -1
  5. labtasker_webui-0.2.0/assets/screenshot.png +0 -0
  6. labtasker_webui-0.2.0/docs/reference/specification.md +245 -0
  7. labtasker_webui-0.2.0/docs/releases/v0.2.0.md +14 -0
  8. labtasker_webui-0.2.0/frontend/dist/assets/index-4SEd7ZLC.js +54 -0
  9. labtasker_webui-0.2.0/frontend/dist/assets/index-CLoY3LJ8.css +1 -0
  10. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/frontend/dist/index.html +3 -3
  11. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/frontend/package-lock.json +2 -2
  12. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/frontend/package.json +1 -1
  13. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/pyproject.toml +3 -2
  14. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/__init__.py +1 -1
  15. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/app.py +119 -3
  16. labtasker_webui-0.2.0/src/labtasker_webui/compatibility.py +27 -0
  17. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/profile.py +1 -0
  18. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/schemas.py +28 -0
  19. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/upstream.py +3 -0
  20. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/fixture_server.py +38 -3
  21. labtasker_webui-0.2.0/tests/test_compatibility.py +75 -0
  22. labtasker_webui-0.2.0/tests/test_name_fuzzy.py +39 -0
  23. labtasker_webui-0.2.0/tests/test_observations.py +54 -0
  24. labtasker_webui-0.2.0/tests/test_upstream_source.py +100 -0
  25. labtasker_webui-0.1.1/assets/screenshot.png +0 -0
  26. labtasker_webui-0.1.1/docs/reference/specification.md +0 -77
  27. labtasker_webui-0.1.1/frontend/dist/assets/index-CscGvBx9.css +0 -1
  28. labtasker_webui-0.1.1/frontend/dist/assets/index-D2PfKj6B.js +0 -54
  29. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.agents/skills/release/SKILL.md +0 -0
  30. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.agents/skills/ui-change/SKILL.md +0 -0
  31. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.agents/sops/development.md +0 -0
  32. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.agents/sops/releasing.md +0 -0
  33. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/.gitignore +0 -0
  34. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/CONTRIBUTING.md +0 -0
  35. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/LICENSE +0 -0
  36. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/frontend/dist/labtasker-icon.png +0 -0
  37. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/scripts/check_package.py +0 -0
  38. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/scripts/check_versions.py +0 -0
  39. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/__main__.py +0 -0
  40. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/cli.py +0 -0
  41. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/config.py +0 -0
  42. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/local.py +0 -0
  43. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/operations.py +0 -0
  44. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/py.typed +0 -0
  45. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/security.py +0 -0
  46. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/src/labtasker_webui/sessions.py +0 -0
  47. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/packaging_smoke.py +0 -0
  48. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_app.py +0 -0
  49. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_config.py +0 -0
  50. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_custom_columns.py +0 -0
  51. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_local.py +0 -0
  52. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_operations.py +0 -0
  53. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_profile.py +0 -0
  54. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_real_server.py +0 -0
  55. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_release_versions.py +0 -0
  56. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_sessions.py +0 -0
  57. {labtasker_webui-0.1.1 → labtasker_webui-0.2.0}/tests/test_upstream.py +0 -0
@@ -37,6 +37,20 @@ LABTASKER_REAL_SERVER_URL=http://127.0.0.1:8000 uv run pytest -m integration tes
37
37
  Set `LABTASKER_REAL_SERVER_TOKEN` through an existing secure mechanism if needed; never
38
38
  paste it into committed scripts or captured shell output.
39
39
 
40
+ To check a sibling Labtasker source checkout, run the isolated BFF contract test:
41
+
42
+ ```sh
43
+ uv run --with ../labtasker/packages/labtasker-server pytest -q -s -m integration tests/test_upstream_source.py
44
+ uv run --with-editable ../labtasker/packages/labtasker-server --with-editable ../labtasker/packages/labtasker-client pytest -q -s -m integration tests/test_upstream_source.py
45
+ ```
46
+
47
+ These commands use temporary dependency overlays without changing the lockfile. The
48
+ first checks the locked Client against the source Server; the second uses both source
49
+ packages in editable mode. The test creates only a temporary database and synthetic Tasks/Workers,
50
+ using in-process ASGI transport without connecting to a running instance. It covers
51
+ pagination, filters, counts, observations, error forwarding and Task actions. The
52
+ normal suite excludes it; without an installed Server it skips.
53
+
40
54
  ## Interaction review matrix
41
55
 
42
56
  | Area | Cases to verify |
@@ -44,7 +58,7 @@ paste it into committed scripts or captured shell output.
44
58
  | Layout | 1440×900 desktop, 900×600 short window, 390×700 narrow window; no document-level horizontal overflow |
45
59
  | Popups | Every edge; resize while open; many options; long names; internal scrolling; Escape, outside click and Tab |
46
60
  | Keyboard | Arrow keys/Home/End follow visible active option; Enter applies; IME Enter does not submit prematurely |
47
- | Filters | Dropdowns/presets immediate; text blur/Enter; clear; invalid input and correction; counts match applied selectors |
61
+ | Filters | Dropdowns/presets immediate; text blur/Enter; clear; invalid input and correction; status cards respect applied name/expression but ignore the Status selector; list totals include Status |
48
62
  | Navigation | Queue → filter → drawer → back/forward; URL and visible state agree |
49
63
  | Selection | Empty/partial/all checkbox; sorting retains selection; filtering clears selection; append keeps existing selection |
50
64
  | Columns | Independent resize; double-click fit; drag order; missing JSON paths blank; path casing preserved; reload restoration |
@@ -40,7 +40,7 @@
40
40
  - Preserve breadcrumbs and the compact, information-dense layout. Do not reintroduce a duplicate queue heading or large decorative spacing.
41
41
  - Queue layout and named views are scoped by connection identity **and** queue. Never reintroduce a global columns fallback.
42
42
  - Dropdowns and presets apply immediately. Text filters apply on Enter or leaving the input group; Apply is a fallback. Respect IME composition.
43
- - Counts describe the same applied selectors as the list. Sorting preserves selection; changing the filter range clears it.
43
+ - Status card counts use applied Task name and filter expressions, ignoring the Status selector; list totals also include the selected Status. Sorting preserves selection; changing the filter range clears it.
44
44
  - Browser history restores queue, applied filters and drawer consistently. Partial selection uses the native checkbox `indeterminate` property.
45
45
  - Resizing changes only the chosen column. Double-click fits content. Reordering preserves paths and uses a drop line, not a shaded target row.
46
46
  - Every popup must fit the viewport, support scrolling and Escape/outside dismissal, and remain usable with keyboard navigation. Check Safari/WebKit focus behavior, not only Chromium.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: labtasker-webui
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: A focused web interface for Labtasker v2
5
5
  Project-URL: Homepage, https://github.com/luocfprime/labtasker-webui
6
6
  Project-URL: Repository, https://github.com/luocfprime/labtasker-webui
@@ -11,6 +11,7 @@ Requires-Python: >=3.11
11
11
  Requires-Dist: fastapi<1,>=0.115
12
12
  Requires-Dist: httpx[socks]<1,>=0.27
13
13
  Requires-Dist: labtasker-client<3,>=2.1
14
+ Requires-Dist: packaging<27,>=24
14
15
  Requires-Dist: uvicorn<1,>=0.34
15
16
  Provides-Extra: local
16
17
  Requires-Dist: labtasker-client<3,>=2.1; extra == 'local'
@@ -28,7 +29,11 @@ workspace, with reusable views for different experiments.
28
29
  The key features are:
29
30
 
30
31
  - **Queue progress at a glance:** Track pending, running, succeeded, failed, and
31
- cancelled Tasks. Status counts follow the same filters as the Task list.
32
+ cancelled Tasks. Status counts follow the applied Task name and advanced filter, across all statuses; the Status selector narrows only the Task list and its total.
33
+ - **Routes and Workers:** Collapse route navigation when you need more table space.
34
+ Inspect Idle/Busy Worker counts and last-seen reports; include inactive routes when
35
+ reviewing historical work. These features require Server 2.2 or later; Worker
36
+ reports require Workers that support observations.
32
37
  - **Flexible result exploration:** Filter Task fields and nested values, or add
33
38
  custom columns such as `args.test_num` and `result.succ_rate`. Resize, reorder,
34
39
  and double-click columns to fit their contents.
@@ -68,6 +73,11 @@ Choose a connection type on the connection page:
68
73
  `.` refers to the WebUI process's working directory. Local attachment uses the
69
74
  project's Unix socket and requires POSIX and a loopback bind.
70
75
 
76
+ If a business response reports a Server older than the installed Labtasker Client,
77
+ WebUI displays a dismissible upgrade warning. It adds no version-check request
78
+ and does not block browsing or actions. Servers that omit their version do not
79
+ trigger the warning. Reloading or reconnecting resets dismissal.
80
+
71
81
  Open a Queue, then filter its Tasks:
72
82
 
73
83
  ```python
@@ -175,3 +185,13 @@ and installation of the built package without Node.js.
175
185
  ## License
176
186
 
177
187
  [Apache-2.0](https://github.com/luocfprime/labtasker-webui/blob/main/LICENSE), matching Labtasker.
188
+
189
+ ### Search Task names
190
+
191
+ The Task name input supports case-insensitive subsequence search: `tr ev` or
192
+ `ev tr` finds `train_model_eval`. Every whitespace-separated word must match.
193
+ Press Enter or leave the input to apply; clearing it removes the name restriction.
194
+ For a strict name match, use `name == "train_model_eval"` in Advanced filter.
195
+ The Server applies the same search to the Task list and counts across the Queue,
196
+ with the existing sorting preserved. This requires a Server supporting
197
+ `name_fuzzy`; saved Task name inputs also use fuzzy matching.
@@ -10,7 +10,11 @@ workspace, with reusable views for different experiments.
10
10
  The key features are:
11
11
 
12
12
  - **Queue progress at a glance:** Track pending, running, succeeded, failed, and
13
- cancelled Tasks. Status counts follow the same filters as the Task list.
13
+ cancelled Tasks. Status counts follow the applied Task name and advanced filter, across all statuses; the Status selector narrows only the Task list and its total.
14
+ - **Routes and Workers:** Collapse route navigation when you need more table space.
15
+ Inspect Idle/Busy Worker counts and last-seen reports; include inactive routes when
16
+ reviewing historical work. These features require Server 2.2 or later; Worker
17
+ reports require Workers that support observations.
14
18
  - **Flexible result exploration:** Filter Task fields and nested values, or add
15
19
  custom columns such as `args.test_num` and `result.succ_rate`. Resize, reorder,
16
20
  and double-click columns to fit their contents.
@@ -50,6 +54,11 @@ Choose a connection type on the connection page:
50
54
  `.` refers to the WebUI process's working directory. Local attachment uses the
51
55
  project's Unix socket and requires POSIX and a loopback bind.
52
56
 
57
+ If a business response reports a Server older than the installed Labtasker Client,
58
+ WebUI displays a dismissible upgrade warning. It adds no version-check request
59
+ and does not block browsing or actions. Servers that omit their version do not
60
+ trigger the warning. Reloading or reconnecting resets dismissal.
61
+
53
62
  Open a Queue, then filter its Tasks:
54
63
 
55
64
  ```python
@@ -157,3 +166,13 @@ and installation of the built package without Node.js.
157
166
  ## License
158
167
 
159
168
  [Apache-2.0](https://github.com/luocfprime/labtasker-webui/blob/main/LICENSE), matching Labtasker.
169
+
170
+ ### Search Task names
171
+
172
+ The Task name input supports case-insensitive subsequence search: `tr ev` or
173
+ `ev tr` finds `train_model_eval`. Every whitespace-separated word must match.
174
+ Press Enter or leave the input to apply; clearing it removes the name restriction.
175
+ For a strict name match, use `name == "train_model_eval"` in Advanced filter.
176
+ The Server applies the same search to the Task list and counts across the Queue,
177
+ with the existing sorting preserved. This requires a Server supporting
178
+ `name_fuzzy`; saved Task name inputs also use fuzzy matching.
@@ -0,0 +1,245 @@
1
+ # WebUI specification
2
+
3
+ ```text
4
+ Browser (React, Query, Table)
5
+ -> same-origin /api/webui/* (FastAPI BFF)
6
+ -> HTTP Labtasker v2 Server, or existing project's Unix socket
7
+ ```
8
+
9
+ The BFF owns upstream credentials, session cookies, origin validation and destructive
10
+ operation snapshots. The UI observes Tasks and supports cancel, requeue and selected-ID
11
+ deletion; it does not submit/edit Tasks. Local attachment discovers and uses the existing
12
+ socket without managing the Labtasker process or opening its database.
13
+
14
+ ## Server version warnings
15
+
16
+ The BFF observes `Labtasker-Server-Version` on ordinary upstream `/api/`
17
+ responses, including errors and empty successes, for both HTTP and local
18
+ connections. Existing connection verification stays unchanged; version warnings
19
+ add no upstream requests. Health/schema responses are not version observations.
20
+
21
+ On a BFF response that observed an upstream business response, it sends
22
+ `Labtasker-Client-Version` (the installed `labtasker-client` version),
23
+ `Labtasker-Server-Version` (normalized PEP 440 version, or an empty value when
24
+ unknown), and `Labtasker-Server-Upgrade-Recommended` (`true` or `false`). Missing,
25
+ invalid, or longer-than-128-character upstream versions are unknown. Comparison
26
+ uses PEP 440 ordering, including patch and prerelease differences; the WebUI's
27
+ independent package version is not compared to the Server. Version observations
28
+ are request-local and must not leak across sessions or credentials. No tokens
29
+ are added to these headers; upstream payloads and errors remain unchanged.
30
+
31
+ The browser displays a compact, nonblocking, dismissible warning above the
32
+ workspace when the Server is older. It recommends upgrading to the Client version
33
+ or later without claiming that a particular operation is incompatible. Repeated
34
+ responses for a dismissed version pair do not redisplay it. A different older
35
+ version pair can warn again; an equal, newer, or unknown observation clears the
36
+ visible warning. Responses without an upstream observation leave it unchanged.
37
+ Observations and dismissal are memory-only and reset on reload/reconnection.
38
+ Neither credentials nor version observations are written to the profile.
39
+
40
+ ## State
41
+
42
+ | State | Owner and persistence |
43
+ | --- | --- |
44
+ | Connection URL/local project | Backend profile in WebUI working directory |
45
+ | Bearer token | Backend only; separate owner-only `webui-token` file |
46
+ | Queue, applied selectors, drawer Task ID | URL/history plus React state |
47
+ | Current working column layout | Connection + queue scope; browser and profile |
48
+ | Named data view | Explicit snapshot scoped to connection + queue |
49
+ | Task selection | Current workspace memory; exact Task IDs |
50
+ | Pending profile write | Browser recovery record until the backend acknowledges saving |
51
+ | Task data and counts | Query cache keyed by connection lifecycle, queue and applied selectors |
52
+
53
+ A profile contains a map of UI settings; it is not itself a named data view. Views capture
54
+ filters, sort order, visible/custom columns, order and widths. Layout edits do not mutate
55
+ a named view until Save. The backend UI-key allowlist must remain consistent with frontend
56
+ persistence keys; internal browser recovery keys must never enter profile API payloads.
57
+ Saved-view change detection compares setting values rather than object key order.
58
+ Older views without a route field are equivalent to an empty route selection, so
59
+ applying or resetting them does not falsely report unsaved changes.
60
+
61
+ Backend profile writes use atomic replacement and restrictive permissions. Failed writes
62
+ must not be reported as persisted by a subsequent API read. Browser pending writes are
63
+ retained across reload and merged before restoring older disk settings. Successful writes
64
+ acknowledge only values actually sent, preserving newer edits queued during the request.
65
+ Saves time out after 10 seconds and remain recoverable. Payloads above 60 KiB use normal
66
+ fetch instead of the browser-limited keepalive transport; interrupted writes stay in the
67
+ browser recovery record.
68
+
69
+ Successful login clears query caches and reloads connection status before rebuilding
70
+ the workspace. A new session must never expose the previous connection's cached Tasks,
71
+ including when reauthenticating with another Server or token.
72
+
73
+ ## Rendering and interaction
74
+
75
+ The table uses cursor loading plus row virtualization. Status card counts cover all Tasks
76
+ matching the applied Task name and advanced filter, ignoring the Status selector.
77
+ Explicit status conditions inside the advanced filter remain effective. Selecting a
78
+ Status changes the highlighted card, Task list and list total without narrowing the
79
+ other cards. List totals include all applied selectors, not just loaded rows.
80
+ Scrolling older rows pauses list polling to avoid reordering
81
+ what the user is reading. Refresh explicitly returns to the top and refreshes data/counts.
82
+ Task selection survives sorting, including browser Back/Forward through sort changes.
83
+ Applying or resetting a saved view also preserves selection when only sorting or
84
+ column layout changes.
85
+ Changing the filter range clears selection, including through browser history.
86
+ Resizing uses per-column widths and a filler for remaining space. JSON paths are read-only
87
+ lookups; missing fields are blank.
88
+
89
+ The Task name input uses the upstream `name_fuzzy` selector: case-insensitive
90
+ Unicode subsequences, split on whitespace, with every word required and word
91
+ order unrestricted. Empty or whitespace-only searches add no restriction.
92
+ Punctuation is literal; no fzf extended operators or relevance sorting are added.
93
+ Text applies on Enter or blur, respecting IME composition. Exact lookup remains
94
+ available as `name == "..."` in Advanced filter. The URL and saved-view `name`
95
+ field store this input; previously saved name inputs now use fuzzy matching.
96
+
97
+ The BFF forwards `name_fuzzy` on list, count, and deletion-snapshot requests to
98
+ the Server. It does not filter loaded Tasks in the browser. Status cards ignore
99
+ the Status dropdown but retain name search and advanced filter; list totals use
100
+ all applied selectors. The existing selected-ID deletion UI is unchanged.
101
+ The snapshot endpoint requires at least one effective selector; whitespace-only
102
+ fuzzy input alone is insufficient. The upstream Server must support `name_fuzzy`;
103
+ there is no browser-only matching fallback.
104
+
105
+ Advanced filter help provides ten built-in examples covering routes, status, priority,
106
+ attempts, errors and custom fields. Route examples use exact-name array membership
107
+ (`"gpu-a100" in routes` and `"gpu-a100" not in routes`); combine checks with
108
+ `or` for any route or `and` for all. Selecting an example applies it immediately
109
+ alongside the status and Task name selectors.
110
+
111
+ View actions closes when keyboard focus leaves the view controls or moves to the
112
+ Data view picker, so its menu cannot remain open behind that picker. Shift+Tab from
113
+ the first menu item closes the menu and returns focus to the View actions trigger.
114
+ Shared popup positioning clamps to the viewport and chooses above/below placement.
115
+ Escape dismisses a selector from both its trigger and its optional action button,
116
+ returning focus to the trigger. Tab and Shift+Tab move between the trigger and its
117
+ action; Tab from the action leaves and dismisses the menu.
118
+ Selector letter navigation ignores Ctrl, Meta and Alt combinations so browser
119
+ shortcuts keep their normal behavior.
120
+ Keep focus inside menus during internal interactions; Safari can emit a blur with no
121
+ related target before a pointer click completes. Permanent request errors such as invalid
122
+ filters should appear immediately; only transient failures should retry.
123
+ Task action errors and pending indicators belong to the selected Task. Switching Tasks
124
+ resets those indicators without cancelling the previous action; its eventual response
125
+ invalidates the original Task cache, not the newly selected Task. Pending actions remain
126
+ tracked per Task across switching away and back, so returning cannot submit a duplicate.
127
+ Outside interactions dismiss the drawer by synchronously removing its Task from the
128
+ current history entry, allowing a clicked filter or navigation control to update history
129
+ without racing a Back operation. Focus stays with the outside control. The close button
130
+ and Escape retain normal drawer history navigation and restore the originating Task focus.
131
+
132
+ ## Build boundary
133
+
134
+ Vite produces `frontend/dist`. Hatch includes those assets in the wheel and sdist; the
135
+ installed wheel serves them without Node.js. A successful TypeScript build alone does not
136
+ prove packaging works. See [release verification](../../.agents/sops/releasing.md) for the separate artifact test.
137
+
138
+ ## Batch deletion recovery
139
+
140
+ Starting, retrying failed Tasks and stopping a batch each disable conflicting actions
141
+ while their request is pending. A failed progress read offers Retry status without
142
+ submitting another deletion, and allows returning to the list with an explicit notice
143
+ that the operation may still run. Stop failures remain visible. Closing the dialog
144
+ stops its polling; it does not cancel an operation already accepted by the backend.
145
+
146
+ The bounded operation store evicts completed records only. When all slots are active,
147
+ new operations receive a retryable capacity error; running operations remain queryable
148
+ and stoppable until completion.
149
+
150
+ ## Routes and Worker observations
151
+
152
+ Observation request failures appear as bottom-right notifications, outside the Routes
153
+ layout. Identical messages share one notification listing the affected observations;
154
+ Retry retries all affected active requests. Dismiss (or Escape while focused) keeps
155
+ that message quiet for the current Queue workspace, including refreshes and tab
156
+ switches. Successful requests clear their notification. Unavailable counts and Worker
157
+ observations remain marked in place after dismissal; Refresh remains available.
158
+ Corner notifications share a vertical stack with settings-save failures and transient
159
+ feedback, so recovery controls do not overlap. Notification actions leave the Task
160
+ drawer and its URL open. Modal dialogs remain above the notification stack.
161
+ Each new transient operation message receives a fresh five-second display duration;
162
+ an older timer cannot hide it early. Long column paths wrap within the viewport.
163
+ A notification stays visible while its Retry is pending. Pending retries belong to
164
+ active request identities: changing the Worker filter or tab hides inactive requests
165
+ and cannot disable a new filter's Retry, even when the error text matches. Escape
166
+ from a focused notification dismisses that notification without closing the Task
167
+ drawer; Escape from the drawer still closes the drawer. Worker append failures use
168
+ only the list's Retry loading control, which retries the failed cursor instead of
169
+ refreshing already-loaded pages.
170
+
171
+ Each Queue has Tasks and Workers tabs and a collapsible Routes sidebar. The sidebar
172
+ combines grouped pending/running Task routes with active Worker routes. Routes with
173
+ only terminal Tasks and no active Workers appear when Include inactive routes is on.
174
+ All group pages must load before absence is treated as zero. Unsupported or failed
175
+ observation requests remain explicit; they never imply that there are zero Workers.
176
+ A route is labeled Inactive only when both Task and Worker observations are available.
177
+ If Task observations fail, a known absence of Workers is labeled No active Workers
178
+ without inferring current Task demand from stale counts.
179
+ Existing Task browsing remains available on Servers without grouped counts.
180
+
181
+ Selecting a route intersects the Task filter with membership in `routes`, including
182
+ status counts, and filters Workers by `route`. Route and tab navigation use browser
183
+ history; named views include the selected route. Sidebar preferences belong to the
184
+ connection and Queue. Task summary controls use colored numbers followed by status
185
+ words on one line; they retain their status-filter toggle behavior.
186
+ Selecting the current tab or Worker status does not add a duplicate history entry
187
+ when the resulting URL is unchanged.
188
+
189
+ Worker state counts use grouped observations, independently of the paginated Worker
190
+ list. Observations describe reports, not Task ownership or execution guarantees.
191
+ Normal rows show last seen. Only after more than two 60-second reporting cycles
192
+ without a report does the row show delayed-update and expiry information. Expiry
193
+ uses the Server's `expires_at`; UI polling does not define the reporting interval.
194
+ Delayed-update and expiry messages wrap within their cell so narrow columns do not
195
+ hide the remaining time.
196
+ Failed list refreshes suppress expiry warnings and expose update/retry information.
197
+ Worker IDs, routes and times retain full-value hover tooltips; associated Tasks open
198
+ the existing detail drawer.
199
+ Switching between associated Task links keeps the drawer open. Explicitly closing it
200
+ restores focus to the most recently opened Worker Task link.
201
+
202
+ Change opens connection settings without discarding the current workspace. Back to
203
+ workspace restores it; a successful connection change clears the query cache.
204
+ Back to workspace is disabled while a connection change is pending. If the change
205
+ fails, returning to the previous workspace becomes available again.
206
+
207
+ The compact Task summary begins with All, the sum across the five mutually exclusive
208
+ statuses under the applied name, expression and route filters. Selecting All clears
209
+ only the Status selector. Task and Worker summary controls use a quiet rounded
210
+ selection fill. Worker Idle counts are green and Busy counts are blue. Worker status
211
+ selection uses the same styled, keyboard-accessible control as Task filters.
212
+
213
+ The workspace uses a white surface, medium-weight linked Task names, colored status
214
+ labels and row separators, without nested toolbar/table frames. Route collapse has
215
+ an explicit button and a 140 ms layout transition, disabled for reduced motion.
216
+ Route dots in the sidebar and Task/Worker tables describe current route observations:
217
+ blue for Busy Workers, green for Idle Workers, amber for pending/running Tasks without
218
+ active Workers, gray for inactive routes, and a hollow gray dot when counts are unknown.
219
+ Busy takes precedence over Idle when both are present. A route dot does not describe
220
+ the individual Task's status; each Task keeps its own separate status label.
221
+
222
+ The Routes divider supports pointer dragging and Left/Right keyboard adjustments.
223
+ Width is stored per connection and Queue, including across collapse and reload.
224
+ The sidebar is bounded to 160–480 px and at most 40% of the viewport. Dragging has
225
+ no layout animation; collapse keeps its short transition. On narrow screens the
226
+ Routes section stacks above content and its horizontal resize handle is hidden.
227
+
228
+ Task-name search has a 240 px preferred width and expands to its grid cell on narrow
229
+ screens. The Routes toggle stays beside the breadcrumb in both sidebar states. The sidebar
230
+ starts directly with All routes, aligned with the 36 px Task/Worker tab row; there
231
+ is no separate sidebar title or collapse button in the tab row. Selected status
232
+ summaries use a pale version of their status color with matching label text; All uses
233
+ neutral charcoal and a pale gray background. Typography uses 13 px controls, 12 px summary labels and 24 px count numerals.
234
+
235
+ Queue overview cards use a compact layout capped at 460 px, with the Queue name,
236
+ total Task count, colored status counts, and a thin proportional status distribution
237
+ bar. Status controls retain navigation to the selected status and wrap on narrow
238
+ screens. They have padded hover targets and offset keyboard focus outlines. The
239
+ cards show completed/total Tasks and completion percentage below the bar, and compact
240
+ Worker and Route summaries in the footer. Status numbers use five aligned columns.
241
+ Route counts are distinct routes, classified Busy before Idle before Waiting; Waiting
242
+ means pending/running Task demand without active Workers. Inactive routes are omitted. Worker counts come from paginated Worker
243
+ groups, refreshed every 15 seconds; loading or unavailable observations never display
244
+ as zero. Completion includes succeeded, failed and cancelled Tasks. Failure rate and
245
+ recent Task details are omitted; individual Tasks remain available inside the Queue.
@@ -0,0 +1,14 @@
1
+ # v0.2.0
2
+
3
+ - Add Routes navigation and idle/busy Worker observations, with grouped Queue progress counts. These features require Server 2.2 or later and observation-capable Workers.
4
+ - Add case-insensitive fuzzy Task name search through the Server.
5
+ - Add dismissible warnings when the connected Server is older than the installed Client.
6
+ - Change transient errors to corner notifications with duplicate suppression, dismissal and independent retry recovery.
7
+ - Fix status counts to preserve the applied name and filter when switching Task status.
8
+ - Fix Task drawer navigation, browser history and focus when switching between Tasks or interacting with notifications.
9
+ - Fix keyboard navigation and dismissal for dropdowns and saved-view menus, including WebKit.
10
+ - Fix selection preservation during sorting and saved-view comparison, Worker pagination recovery and long notification wrapping.
11
+
12
+ Validated against Labtasker 2.2.0 using both Client 2.1.0 and Client 2.2.0. No connection or saved-view migration is required.
13
+
14
+ Full Changelog: https://github.com/luocfprime/labtasker-webui/compare/v0.1.1...v0.2.0