[ every user-visible change ]
Changelog
- fixed
Clear recovery when access grants go stale
If the per-user access grant is missing or stale, the gadget now explains exactly what happened and offers a Grant access button plus a link to Atlassian’s Connected apps page — instead of a dead-end error asking you to refresh forever.
- changed
A visual identity that respects your Jira
The gadget adopts the Claused design language — structured monospace for labels, keys, and numbers, a restrained accent, bordered badges — while surfaces and text keep following your Jira theme, light or dark. Narrow tiles now degrade gracefully instead of hiding issue keys.
- added
Drill-down: every number explains itself
Issue keys in the tree are now links straight into Jira, and every “unestimated” badge is a button: click it and the tree filters to exactly the branches with unestimated work — open them, estimate them, done. Trust the number or inspect it; both are one click.
- added
Expand all, collapse all, and expanded-by-default
Header controls expand or collapse the whole tree at any depth, and a settings checkbox makes the gadget open fully expanded. Every level pages in batches of 100, so even a fully expanded 30,000-issue tree stays fast.
- added
Hourly freshness, and faster for dashboards in use
An hourly incremental sync picks up changed issues, and a dashboard that someone actually opens kicks its own refresh when data is older than an hour — freshness follows attention. The daily full re-sync remains the correctness floor for deletions and cross-project moves. The footer always shows the exact “data as of” timestamp.
- added
JQL filter on precomputed rollups
Narrow a gadget to exactly the issues you care about with a JQL expression — without giving up instant renders: the filter applies on top of the precomputed snapshot. Filtered gadgets are labeled in their header and capture their own daily trend history.
- changed
Nothing hidden: unestimated issues are one click away
Flat issues without a value used to be hidden behind a footer counter, which made an “unestimated” badge count invisible rows. They now collapse into a “No value set” container instead — the badge always points at rows you can open. Issue keys stopped truncating on narrow tiles.
- added
Open work only mode
A per-gadget toggle excludes Done-category issues from every rollup, so totals reflect remaining work instead of everything ever logged. Closedness is judged by status category — the one status attribute Jira does not let teams customize — so it means the same thing on every instance. Open children of a closed epic float up rather than disappear.
- changed
Cross-project orphans grouped, not flooding
Issues whose parents live outside the selected projects used to surface as a flat flood — over a thousand rows drowning the real epics in one test portfolio. They now collapse into a “No parent in view” container at the end of their project group, aggregated correctly and one click away.
- added
Done column: progress at every level
Wide tiles gain a Done column showing what share of each subtree’s issues is completed — the classic done-versus-total view, computed from status categories and available at every level of the hierarchy.
- added
Per-project summary rows
With two or more projects configured, each gets its own summary row with true aggregates — including a median computed from the project’s full value distribution, which cannot be assembled from sub-totals. Collapse everything and the gadget becomes a one-glance portfolio overview.
- changed
3x faster renders on large portfolios
The snapshot read now extracts only the configured field in the database instead of shipping and parsing full field data, and reads are paged so very large portfolios stay under platform response limits. Measured on a 31,230-issue portfolio: ~1.2-1.6 s server-side, down from ~4 s.
- changed
Atomic snapshot generations
Every background sync now writes under its own snapshot generation and publishes atomically: while a re-sync is in flight, readers keep seeing the previous complete snapshot — never a half-written one. A sync that dies mid-flight recovers on its own.
- fixed
The gadget owns its tile
The gadget now fills exactly the height Jira gives it: configuration header and freshness footer stay pinned, only the table scrolls, scrolling no longer leaks into the dashboard page, and full-screen mode uses the full screen.
- added
Time-tracking rollups
Roll up time fields the same way as story points: original estimate, time spent, and remaining estimate are now selectable, with values displayed in hours. “How much work is logged under this epic?” is one gadget away.
- added
Trends: your rollups over time
The background sync now captures a daily history point for every tracked project and field — the full aggregate set, in both “all issues” and “open work only” variants. A Trend toggle in the gadget draws per-project lines: watch remaining story points burn down across a quarter. History is retained bounded forever: daily points for 90 days, then weekly, then monthly.
- added
Background precompute: instant rollups at any size
The core of the app: a background pipeline keeps a snapshot of every watched project inside your Jira, and the gadget reads precomputed data instead of fetching thousands of issues at render time. A 31,000-issue project renders its full rollup tree in about a second — where render-time gadgets hit Jira’s 25-second invocation wall.
- fixed
Survives deleted projects, renamed keys, and removed fields
Deleted projects are dropped instead of retried forever; renamed project keys keep matching their gadgets; numeric fields deleted from Jira are pruned against the live field list instead of showing confident empty values; projects nobody has rendered for 30 days stop being synced.
- changed
Viewer permission gate on every read
The gadget now checks the viewer’s Browse Projects permission on every interactive read. A dashboard shared with someone who cannot see a project shows them nothing from it — a hidden-projects note says why. Configuration is read server-side from the gadget context, so a crafted request cannot substitute it.