Repository navigation
feat(tasks): rework the Jira board view and rank priority by severity - #41
Merged
Merged
Conversation
Returning to the Jira board always showed a loading screen, even right after leaving it, and the board forgot every choice made on it. Three causes, all in the board view's own state: - The overview and the sprint/backlog pages were refetched from scratch on every mount, because the Tasks view unmounts when you switch to a workspace. - The sprint/backlog tab, the Me/All filter, and the filter query lived only in component state, so nothing survived that unmount. - The provider filter chrome is hidden while the board is shown, which left the board with no filter box at all. Fixes: - Keep the last board snapshot in a module cache keyed by site/board (30 minute TTL, three boards) and seed the hooks from it synchronously, so a cached board paints on the first render. The refetch then runs silently behind it, reading back the pages that were already loaded so a paged board cannot mix fresh page one with stale later pages. Refresh still shows the spinner, and switching sprint drops the cached page rather than pairing the new sprint with the old one's issues. - Persist the board/list mode, sprint/backlog tab, Me/All filter, and filter text per device in local storage, mirroring the Linear issue-view preferences. They stay out of taskResumeState: that schema is strict behind a field-level catch, so a host that predates a key rejects the whole payload and drops the GitHub and Jira resume state with it. - Give the board its own filter box, narrowing the loaded issues client-side by key, summary, assignee, status, type, or label. - Open on the viewer's own work (Me) rather than the whole board filter. When the board's site has no resolvable viewer account, show everything instead of an empty board behind a disabled button. - Drop the Team filter and its Team field / Team value settings; the board filter is now Me/All. The Team field was the only consumer of the custom-field listing, so jira:listCustomFields, jira.listCustomFields, the preload and runtime clients, and the main-process query all go with it, and the generated RPC params catalog is regenerated.
A Jira issue's priority was plain text in the same muted grey as every other field, so a blocker read exactly like a trivial task in a dense list and was easy to skim past on a board. - Give each priority a severity chip: a coloured bubble plus the tier name, so the hue is never the only signal. - Blocker and Critical share the red chip; Major is orange. Everything below (medium, normal, low, minor, lowest, trivial, and any custom scheme) stays muted, because a renamed priority scheme must not be mislabelled. - A blocker additionally washes its whole task surface — row or board card — and keeps that wash on hover and while selected, since a chip alone does not stand out enough on a board. The tiers are matched by name against the standard Jira vocabularies (blocker/highest, critical, major/high). Two new tokens, --severity-blocker and --severity-major, carry the ramp in both themes; Major no longer borrows --status-warning, which stays free for its own needs-attention role.
nplez1
force-pushed
the
nplez1/Remove-Team
branch
from
September 29, 2026 09:56
9cc92cd to
c5a5f54
Compare
nplez1
added a commit
that referenced
this pull request
Sep 29, 2026
…#41) * feat(tasks): cache the Jira board and remember its view state Returning to the Jira board always showed a loading screen, even right after leaving it, and the board forgot every choice made on it. Three causes, all in the board view's own state: - The overview and the sprint/backlog pages were refetched from scratch on every mount, because the Tasks view unmounts when you switch to a workspace. - The sprint/backlog tab, the Me/All filter, and the filter query lived only in component state, so nothing survived that unmount. - The provider filter chrome is hidden while the board is shown, which left the board with no filter box at all. Fixes: - Keep the last board snapshot in a module cache keyed by site/board (30 minute TTL, three boards) and seed the hooks from it synchronously, so a cached board paints on the first render. The refetch then runs silently behind it, reading back the pages that were already loaded so a paged board cannot mix fresh page one with stale later pages. Refresh still shows the spinner, and switching sprint drops the cached page rather than pairing the new sprint with the old one's issues. - Persist the board/list mode, sprint/backlog tab, Me/All filter, and filter text per device in local storage, mirroring the Linear issue-view preferences. They stay out of taskResumeState: that schema is strict behind a field-level catch, so a host that predates a key rejects the whole payload and drops the GitHub and Jira resume state with it. - Give the board its own filter box, narrowing the loaded issues client-side by key, summary, assignee, status, type, or label. - Open on the viewer's own work (Me) rather than the whole board filter. When the board's site has no resolvable viewer account, show everything instead of an empty board behind a disabled button. - Drop the Team filter and its Team field / Team value settings; the board filter is now Me/All. The Team field was the only consumer of the custom-field listing, so jira:listCustomFields, jira.listCustomFields, the preload and runtime clients, and the main-process query all go with it, and the generated RPC params catalog is regenerated. * feat(tasks): rank Jira priority by severity and wash blockers A Jira issue's priority was plain text in the same muted grey as every other field, so a blocker read exactly like a trivial task in a dense list and was easy to skim past on a board. - Give each priority a severity chip: a coloured bubble plus the tier name, so the hue is never the only signal. - Blocker and Critical share the red chip; Major is orange. Everything below (medium, normal, low, minor, lowest, trivial, and any custom scheme) stays muted, because a renamed priority scheme must not be mislabelled. - A blocker additionally washes its whole task surface — row or board card — and keeps that wash on hover and while selected, since a chip alone does not stand out enough on a board. The tiers are matched by name against the standard Jira vocabularies (blocker/highest, critical, major/high). Two new tokens, --severity-blocker and --severity-major, carry the ramp in both themes; Major no longer borrows --status-warning, which stays free for its own needs-attention role.
nplez1
added a commit
that referenced
this pull request
Oct 1, 2026
…#41) * feat(tasks): cache the Jira board and remember its view state Returning to the Jira board always showed a loading screen, even right after leaving it, and the board forgot every choice made on it. Three causes, all in the board view's own state: - The overview and the sprint/backlog pages were refetched from scratch on every mount, because the Tasks view unmounts when you switch to a workspace. - The sprint/backlog tab, the Me/All filter, and the filter query lived only in component state, so nothing survived that unmount. - The provider filter chrome is hidden while the board is shown, which left the board with no filter box at all. Fixes: - Keep the last board snapshot in a module cache keyed by site/board (30 minute TTL, three boards) and seed the hooks from it synchronously, so a cached board paints on the first render. The refetch then runs silently behind it, reading back the pages that were already loaded so a paged board cannot mix fresh page one with stale later pages. Refresh still shows the spinner, and switching sprint drops the cached page rather than pairing the new sprint with the old one's issues. - Persist the board/list mode, sprint/backlog tab, Me/All filter, and filter text per device in local storage, mirroring the Linear issue-view preferences. They stay out of taskResumeState: that schema is strict behind a field-level catch, so a host that predates a key rejects the whole payload and drops the GitHub and Jira resume state with it. - Give the board its own filter box, narrowing the loaded issues client-side by key, summary, assignee, status, type, or label. - Open on the viewer's own work (Me) rather than the whole board filter. When the board's site has no resolvable viewer account, show everything instead of an empty board behind a disabled button. - Drop the Team filter and its Team field / Team value settings; the board filter is now Me/All. The Team field was the only consumer of the custom-field listing, so jira:listCustomFields, jira.listCustomFields, the preload and runtime clients, and the main-process query all go with it, and the generated RPC params catalog is regenerated. * feat(tasks): rank Jira priority by severity and wash blockers A Jira issue's priority was plain text in the same muted grey as every other field, so a blocker read exactly like a trivial task in a dense list and was easy to skim past on a board. - Give each priority a severity chip: a coloured bubble plus the tier name, so the hue is never the only signal. - Blocker and Critical share the red chip; Major is orange. Everything below (medium, normal, low, minor, lowest, trivial, and any custom scheme) stays muted, because a renamed priority scheme must not be mislabelled. - A blocker additionally washes its whole task surface — row or board card — and keeps that wash on hover and while selected, since a chip alone does not stand out enough on a board. The tiers are matched by name against the standard Jira vocabularies (blocker/highest, critical, major/high). Two new tokens, --severity-blocker and --severity-major, carry the ramp in both themes; Major no longer borrows --status-warning, which stays free for its own needs-attention role.
nplez1
added a commit
that referenced
this pull request
Oct 6, 2026
…#41) * feat(tasks): cache the Jira board and remember its view state Returning to the Jira board always showed a loading screen, even right after leaving it, and the board forgot every choice made on it. Three causes, all in the board view's own state: - The overview and the sprint/backlog pages were refetched from scratch on every mount, because the Tasks view unmounts when you switch to a workspace. - The sprint/backlog tab, the Me/All filter, and the filter query lived only in component state, so nothing survived that unmount. - The provider filter chrome is hidden while the board is shown, which left the board with no filter box at all. Fixes: - Keep the last board snapshot in a module cache keyed by site/board (30 minute TTL, three boards) and seed the hooks from it synchronously, so a cached board paints on the first render. The refetch then runs silently behind it, reading back the pages that were already loaded so a paged board cannot mix fresh page one with stale later pages. Refresh still shows the spinner, and switching sprint drops the cached page rather than pairing the new sprint with the old one's issues. - Persist the board/list mode, sprint/backlog tab, Me/All filter, and filter text per device in local storage, mirroring the Linear issue-view preferences. They stay out of taskResumeState: that schema is strict behind a field-level catch, so a host that predates a key rejects the whole payload and drops the GitHub and Jira resume state with it. - Give the board its own filter box, narrowing the loaded issues client-side by key, summary, assignee, status, type, or label. - Open on the viewer's own work (Me) rather than the whole board filter. When the board's site has no resolvable viewer account, show everything instead of an empty board behind a disabled button. - Drop the Team filter and its Team field / Team value settings; the board filter is now Me/All. The Team field was the only consumer of the custom-field listing, so jira:listCustomFields, jira.listCustomFields, the preload and runtime clients, and the main-process query all go with it, and the generated RPC params catalog is regenerated. * feat(tasks): rank Jira priority by severity and wash blockers A Jira issue's priority was plain text in the same muted grey as every other field, so a blocker read exactly like a trivial task in a dense list and was easy to skim past on a board. - Give each priority a severity chip: a coloured bubble plus the tier name, so the hue is never the only signal. - Blocker and Critical share the red chip; Major is orange. Everything below (medium, normal, low, minor, lowest, trivial, and any custom scheme) stays muted, because a renamed priority scheme must not be mislabelled. - A blocker additionally washes its whole task surface — row or board card — and keeps that wash on hover and while selected, since a chip alone does not stand out enough on a board. The tiers are matched by name against the standard Jira vocabularies (blocker/highest, critical, major/high). Two new tokens, --severity-blocker and --severity-major, carry the ramp in both themes; Major no longer borrows --status-warning, which stays free for its own needs-attention role.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
The Jira board in Tasks reloaded from scratch every time you came back to it, and it forgot everything you had set up. It also had a "Team" filter that needed two extra settings to work and wasn't being used. This makes the board come back instantly, refresh quietly behind the scenes, remember your choices, and gives it a search box. It also makes urgent work obvious at a glance: a Blocker tints its whole row red, a Critical gets a red chip, and a Major gets an orange one.
What Changed
Board view
Priority (severity)
Mechanism
siteId:boardId(30 minute TTL, three boards) holding the overview and the sprint/backlog pages. The hooks seed from it synchronously, so a cached board paints on the first render and the refetch runs silently behind it.localStoragefor the board view, mirroringlinear-issue-view-storage.ts.--severity-blocker,--severity-major).jira:listCustomFields,jira.listCustomFields, the preload and runtime clients, and the main-process query. The generated RPC params catalog is regenerated.Why
Caching. The Tasks view unmounts when you switch to a workspace, so every return paid for the full board read again. The alternatives were to keep the Tasks view mounted (holds an entire hidden view and its subscriptions alive, and still loses everything on a reload) or to persist board data to disk (serves stale data across restarts, while a Jira board's scope is owned server-side and can change at any time). An in-memory session cache plus a silent revalidate keeps the fast path fast without inventing a stale-data contract.
Where the view preferences live. Not in
taskResumeState. That schema is.strict()behind a field-level.catch, so a host that predates a key rejects the whole payload and drops the GitHub and Jira resume state with it. Per-device view preferences already have a precedent for exactly this reason inlinear-issue-view-storage.ts, so these follow it.Removing the Team filter. It required a per-site custom field to be picked and an exact value typed, and the value match was fragile across option and Jira-team field types. With Me and All covering the real use, the settings cost more than the filter earned.
The severity ramp. Blocker and Critical deliberately share the red chip, with the surface wash as the only difference, rather than a four-hue ramp: red/orange/amber/grey put Critical and Major too close together at a glance, and a solid red chip on a red-washed row read as one undifferentiated red block.
Linked Issue
Fixes #
No issue exists for this; this is internal follow-up work on the Jira board view.
Visual Proof
Light and dark, issue list and board cards. Every tier is rendered, so the ramp is visible rather than just the Blocker. The wash applies to the whole row/card.
Before — priority is plain muted text, identical for every tier, and no row or card is tinted:
After — Blocker washes its whole row and card, Critical shares the red chip, Major is orange, everything below stays muted:
Both images were rendered from the real component classes against the app's real
main.css(compiled with the repo's Tailwind), not from a mockup. They show the priority treatment only; the caching and remembered-view changes have no static visual.Testing
Not manually tested in the app — verifying the board end to end needs a live Jira connection with a scrum board and a
Critical-named priority, which this environment does not have. The screenshots above were rendered from the real classes; the tokens were checked for presence in both themes rather than eyeballed in the running app.Automated coverage added:
task-page-jira-priority-tone.test.ts— tier mapping (including case/whitespace and custom schemes), and that Blocker and Critical produce an identical chip tone while only Blocker returns a surface wash, so a future edit cannot quietly diverge them.task-page-jira-grouping.test.ts— renders the issue list with a Blocker, Critical, Major, and unranked issue; asserts the Blocker row is washed, the Critical row is not washed despite the red chip, and each chip reports itsdata-severity.task-page/Jira/Board.test.tsx— Blocker card wash, cached board renders without a loading state and still revalidates, a settings rerun does not re-show a loader, and the selected sprint survives a remount without mixing sprint pages.task-page-jira-board-cache.test.ts,jira-board-view-storage.test.ts,jira-board-view-preferences.test.ts— TTL/LRU/merge behaviour, storage round-trip and corrupt-payload fallback, and dropping the retiredteamfilter value.Commands run locally:
Full
pnpm lint, the wholepnpm test, andpnpm buildwere not run locally — CI will cover them.AI Disclosure
The implementation was written with an AI coding assistant (pi) working in this worktree, under review at each step. The verification above is what was actually executed.
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
localStorage; nothing path-, shell-, or shortcut-specific is touched.taskResumeStateis deliberately untouched, so there is no new wire surface and noui.setschema change; the only RPC change is the removal ofjira.listCustomFields. Mobile has no consumer of it (verified by grep), so a paired client is unaffected apart from that method no longer existing — an old client that still showed the Team-field picker would see the field list fail, which is consistent with the feature being removed.teamFieldIdboard-issue parameter is non-breaking in both directions, because that schema is a plainz.objectthat strips unknown keys. Stored settings that still containjiraTeamFieldId/jiraTeamValueare ignored rather than rejected; settings are merged over defaults in main, with no strict schema.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)