Custom Reports
Build any chart you want from your time data. Drag-drop widgets, eight chart types, save as a view, schedule email delivery.
The six built-in report tabs (Summary, Detailed, Weekly, Profitability, Workload, Utilization) cover the questions most teams ask. The Custom Report Builder at /time/reports/builder is for everything else — pivot member-billable hours by tag, donut your top clients by revenue, line-chart this quarter's billable trend per project. Anything you can group by + count.
Screenshot needed — /time/reports/builder showing the filter row, the Add widget button, two configured charts side-by-side (a stacked bar and a donut), and a Save report input.
Where to find it
- From
/time/reportstoolbar → Custom builder button - Direct URL:
/time/reports/builder - A saved custom report on the Saved views popover routes back here automatically (saved views with
widgetsin their payload are recognised as custom reports)
How a widget is configured
Each widget answers four questions:
| Question | Field | Example |
|---|---|---|
| What chart? | chartType | Bar, Stacked bar, Grouped bar, Donut, Line, Multi-line, Table, Pivot table |
| What goes on the primary axis? | primaryGroupBy | Project, Member, Tag, Day, Week, Month, Billable |
| What goes on the secondary axis? (stacked / grouped / multi-line / pivot only) | secondaryGroupBy | Same options as primary, must differ |
| What number to plot? | metric | Hours, Billable hours, Revenue |
Plus one knob: Top N rows (default 10) — caps the primary axis to the highest values so the chart stays readable on dense data.
Eight chart types at a glance
| Chart type | Best for | Needs secondary? |
|---|---|---|
| Bar | "Hours per project" | No |
| Stacked bar | "Hours per project, billable vs non-billable" | Yes |
| Grouped bar | "Hours per member, side-by-side per project" | Yes |
| Donut | "% of revenue by client" | No |
| Line | "Daily billable trend" | No |
| Multi-line | "Daily hours per project" | Yes |
| Table | Same data as Bar but sortable / dense | No |
| Pivot table | A full member × week matrix | Yes |
Time-axis groupings (Day / Week / Month) are sorted ascending; categorical groupings sort by descending hours.
Building a report
- Open
/time/reports/builder. You start with one default widget ("Hours by project"). It populates immediately so you see what works look like. - Set the filter row at the top (date range, members, projects, tags). Filters apply to every widget on the report.
- Drag widgets to reorder — handles on the left edge of each card.
- Click Add widget to compose another. The dialog walks you through chart type → group-by → secondary (if needed) → metric → Top N.
- Hover any widget to edit (pencil) or delete (trash).
- Type a report name in the toolbar, click Save report.
Saved custom reports show up alongside your other saved views on the /time/reports toolbar's Saved views popover. They're tagged "scheduled" if you've also set up email delivery.
Saving and sharing
Custom reports persist as rows in the cross-cutting views table with a widgets field on the payload (forward-compatible — older saved views without widgets continue to render their named tab as before).
| Action | Where |
|---|---|
| Save a new custom report | Toolbar Save report |
| Switch between your custom reports | Toolbar dropdown labelled — My custom reports — |
| Open a custom report directly | /time/reports/builder?viewId=<view-id> |
Custom reports are per-user private by default. Mark a saved view as shared (uncheck Private when saving) to surface it for the whole workspace.
Scheduling email delivery
Any saved custom report can be emailed on a recurring schedule. The flow piggy-backs on the same scheduling backbone as the built-in tabs:
- Open the Saved views popover from the reports toolbar.
- Click the Clock icon on the saved custom report.
- Pick frequency (daily / weekly Monday / monthly 1st), enter recipient emails, Schedule.
- Manage all schedules at
/time/reports/schedules— pause, resume, delete.
The cron at 06:20 UTC daily evaluates every enabled schedule, decides which ones fire today, and emails a digest with the report's KPIs + top-5 projects + top-10 entries plus a link to the live report. Per-recipient idempotency prevents duplicate sends if the cron retries.
See Reports → Scheduled email delivery for the full flow.
What it doesn't do (yet)
- Pin to sidebar — Toggl-style "promote a saved report into the workspace nav" is on the roadmap. Today, custom reports are only reachable from the Saved views popover.
- Cross-module reports — widgets only aggregate
time_entries. Joining time + finance + projects in a single chart is out of scope; build cross-module dashboards on/dashboardinstead. - Calculated fields — no formula columns yet (no "Hours × 1.2", no "this period vs. last period"). The metric is one of
hours,billable_hours,billable_amount.
What's under the hood
Each widget loads through TimeCustomReportService.rollup(workspaceId, filters, primary, secondary?). The service runs one query against time_entries (excluding status='rejected'), filters server-side, and returns a normalised shape:
{ primary: [{key,label}],
secondary: [{key,label}] | [],
cells: { primaryKey: { secondaryKey: { hours, billable_hours, billable_amount } } },
currency }Every chart renderer (ChartRenderer in src/modules/time/components/reports/builder/chart-renderer.tsx) consumes this shape — flattening, pivoting, or rendering as a table according to the widget's chartType. No new dependency was introduced for the builder: Recharts powers the charts, @dnd-kit/sortable powers the reorder, the existing views table stores the config.
Tag-rolled-up widgets divide each entry's hours equally across that entry's tags, so totals don't double-count when an entry has multiple tags.
Next steps
- Reports — the six built-in tabs that cover most questions
- Settings → Audit log — see who edited what entries
- Integrations — pull report data over the public API
Time Reports
Six tabs over the same dataset — Summary, Detailed, Weekly pivot, Profitability, Workload, Utilization. Plus the Custom Report Builder, saved views, scheduled email, and PDF / CSV export.
Time Integrations
Where Time Tracking shows up across the rest of Workestra, plus webhooks, AI tools, and the public REST API.