docs: switch job list view control to a toggle button
The plan now uses a button that flips its own text and icon (Compact + ListIcon / Detailed + ViewFullScreenIcon), mirroring the existing stopAllButton idiom, instead of a "View" dropdown. It sits beside the folder filter on the same row via a border layout, so the sidebar header keeps its current height and the toolbar row is untouched. The label helpers become nextJobListView and viewToggleText, with tests and the verification steps updated to match. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,15 @@ persisted in `gosentry.json`, so it survives a restart like `Config.Theme` does.
|
|||||||
|
|
||||||
## Design decisions
|
## Design decisions
|
||||||
|
|
||||||
- **Control lives in the Jobs sidebar header** — a "View" dropdown beside the
|
- **Control lives in the Jobs sidebar header** — a toggle button on the same row
|
||||||
existing "Folder" filter. Switching is one click, next to what it affects.
|
as the existing "Folder" filter, to its right. Switching is one click, next to
|
||||||
|
what it affects. Fyne 2.7.4 has no dedicated toggle widget, so the button
|
||||||
|
flips its own text and icon on tap, exactly like `stopAllButton`
|
||||||
|
("Disable auto" / "Enable auto") already does in `src/ui/jobs_view.go`. Like
|
||||||
|
that button it is labelled with the *action*, not the current state:
|
||||||
|
`Compact` + `theme.ListIcon()` while detailed, `Detailed` +
|
||||||
|
`theme.ViewFullScreenIcon()` while compact. The toolbar row (New job / Edit /
|
||||||
|
Run now / Pause / Delete) is left untouched.
|
||||||
- **Compact row = name + status** on a single line. Same height as one label,
|
- **Compact row = name + status** on a single line. Same height as one label,
|
||||||
so per-job health stays visible at a glance.
|
so per-job health stays visible at a glance.
|
||||||
- **One list, one row template.** `widget.List` caches the row template's
|
- **One list, one row template.** `widget.List` caches the row template's
|
||||||
@@ -71,33 +78,40 @@ reasoning.
|
|||||||
`app.StatusText`) and **re-apply visibility on every update**: a full
|
`app.StatusText`) and **re-apply visibility on every update**: a full
|
||||||
`Refresh` reuses the already-visible row objects, which were created under the
|
`Refresh` reuses the already-visible row objects, which were created under the
|
||||||
old mode, so visibility cannot be left to `CreateItem` alone.
|
old mode, so visibility cannot be left to `CreateItem` alone.
|
||||||
- **View dropdown**: `widget.NewSelect([]string{viewLabelDetailed,
|
- **View toggle button**: `viewButton := widget.NewButtonWithIcon(…)` built with
|
||||||
viewLabelCompact}, …)`. Its handler maps label → `domain.JobListView`, returns
|
the text/icon for the current mode. Its `OnTapped` flips the mode
|
||||||
early when unchanged, updates `compactList`, persists via
|
(`nextJobListView`), persists via `svc.SetJobListView` — on error
|
||||||
`svc.SetJobListView` (on error `dialog.ShowError` and revert the select, per
|
`dialog.ShowError` and roll the local mode back without touching the button,
|
||||||
the error rule in `docs/STANDARDS.md`), then calls `list.Refresh()`. The
|
per the error rule in `docs/STANDARDS.md` — then applies the new
|
||||||
selection and the details panel are untouched by the switch.
|
`SetText`/`SetIcon` and calls `list.Refresh()`. This mirrors `stopAllButton`'s
|
||||||
- **Header layout**: replace the current `"Folder"` caption + `folderSelect`
|
flip-and-revert handler in the same file. The list selection and the details
|
||||||
pair in `sidebarHeader` with
|
panel are untouched by the switch.
|
||||||
`container.NewGridWithColumns(2, <Folder caption + select>, <View caption +
|
- **Header layout**: keep the `"Folder"` caption and `folderSelect` exactly as
|
||||||
select>)`, so the second dropdown costs no extra header height and the list
|
they are, and put the button beside the select on the same row —
|
||||||
keeps the same room. The 400px `minJobsSidebarWidth` comfortably fits two
|
`container.NewBorder(nil, nil, nil, viewButton, folderSelect)`. The border
|
||||||
short selects.
|
layout gives the button its `MinSize` on the right and lets the select fill
|
||||||
|
the rest, so the header gains no height and the toolbar row is not touched.
|
||||||
|
|
||||||
### 4. `src/ui/jobs_view_helpers.go` — label mapping
|
### 4. `src/ui/jobs_view_helpers.go` — button state helpers
|
||||||
|
|
||||||
`viewLabelDetailed`/`viewLabelCompact` consts plus pure
|
Two pure helpers so the on-disk strings never reach the user and the button's
|
||||||
`viewLabel(domain.JobListView) string` and
|
wording is testable without a running GUI:
|
||||||
`viewFromLabel(string) domain.JobListView`, mirroring
|
|
||||||
`themeLabel`/`themeFromLabel` (`src/ui/settings_view.go:370`) so the on-disk
|
- `nextJobListView(current domain.JobListView) domain.JobListView` — flips the
|
||||||
strings never reach the user.
|
mode, treating anything that is not `compact` as detailed (via `IsCompact`).
|
||||||
|
- `viewToggleText(current domain.JobListView) string` — the action label:
|
||||||
|
`"Compact"` while detailed, `"Detailed"` while compact.
|
||||||
|
|
||||||
|
The icon choice stays inline at the button, next to `SetText`/`SetIcon`, so the
|
||||||
|
helpers file keeps its "no widget imports" character.
|
||||||
|
|
||||||
### 5. Tests
|
### 5. Tests
|
||||||
|
|
||||||
- `src/domain/config_test.go` (new): `JobListView.IsCompact` for `"compact"`,
|
- `src/domain/config_test.go` (new): `JobListView.IsCompact` for `"compact"`,
|
||||||
`"detailed"`, `""`, and a junk value.
|
`"detailed"`, `""`, and a junk value.
|
||||||
- `src/ui/jobs_view_test.go`: `viewLabel`/`viewFromLabel` round-trip, and
|
- `src/ui/jobs_view_test.go`: `nextJobListView` flips both ways and maps an
|
||||||
unknown/empty label → detailed.
|
empty/unknown value to compact (since such a value reads as detailed), and
|
||||||
|
`viewToggleText` returns the action label for each mode.
|
||||||
- `src/app/operations_test.go`: `TestSetJobListViewPersistsToConfigFile`
|
- `src/app/operations_test.go`: `TestSetJobListViewPersistsToConfigFile`
|
||||||
modelled on `TestSetGlobalPausePersistsToConfigFile`
|
modelled on `TestSetGlobalPausePersistsToConfigFile`
|
||||||
(`src/app/operations_test.go:553`) — switch to compact, unmarshal
|
(`src/app/operations_test.go:553`) — switch to compact, unmarshal
|
||||||
@@ -125,9 +139,11 @@ export PATH="/c/msys64/ucrt64/bin:$PATH"; export CGO_ENABLED=1; go build ./... &
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. Run the app (`go run ./cmd/gosentry`) with several jobs configured and check:
|
2. Run the app (`go run ./cmd/gosentry`) with several jobs configured and check:
|
||||||
- Default launch is Detailed and looks exactly as before.
|
- Default launch is Detailed and looks exactly as before; the button reads
|
||||||
- Switching to Compact collapses every row to one line, name left / status
|
"Compact" and sits to the right of the folder filter without making the
|
||||||
right, and many more jobs fit without scrolling.
|
header taller.
|
||||||
|
- Tapping it collapses every row to one line, name left / status right, many
|
||||||
|
more jobs fit without scrolling, and the button now reads "Detailed".
|
||||||
- Selection and the details panel keep working after switching, in both
|
- Selection and the details panel keep working after switching, in both
|
||||||
directions, including with a folder filter active and with an empty list.
|
directions, including with a folder filter active and with an empty list.
|
||||||
- A running job's status still updates live in compact rows.
|
- A running job's status still updates live in compact rows.
|
||||||
|
|||||||
Reference in New Issue
Block a user