Combined timesheet
Export monthly report
Add manual time
Upload mobile-provider call log (PDF)
Uploads are extracted and retained for review. A provider-specific parser is added after a redacted sample statement is available.
Days
{% for day in days %}{{ day.date.strftime('%a %d %b %Y') }}
accepted {{ format_seconds(day.accepted) }} · suggested {{ format_seconds(day.suggested) }}{% if day.commits %} · {{ day.commits|length }} commit{{ 's' if day.commits|length != 1 }}{% endif %} {% if day.suggested %}{% endif %}Show {{ day.entries|length }} entr{{ 'y' if day.entries|length == 1 else 'ies' }}
| Start | End | Source | Task / project | Duration | Status | Actions |
|---|---|---|---|---|---|---|
| {{ entry.start_at.astimezone(display_tz).strftime('%H:%M') }} | {{ entry.end_at.astimezone(display_tz).strftime('%H:%M') }} | {{ entry.source }}{% if entry.kind == 'zed_inferred' %} inferred{% if overlaps_accepted(entry) %}; overlaps accepted time (not acceptable){% endif %}{% endif %} | {{ entry.task or '—' }}{% if entry.project_slug %} {{ entry.project_slug }}{% endif %} | {{ format_seconds(entry.duration_seconds) }} | {{ entry.status }} | {% if entry.status == 'suggested' and not overlaps_accepted(entry) %}{% endif %}{% if entry.status != 'rejected' %}{% endif %}Edit |
No tracked entries this day.
{% endif %} {% if day.commits %}Git commits ({{ day.commits|length }})
| Time | Project | Author | Commit |
|---|---|---|---|
| {{ commit.occurred_at.astimezone(display_tz).strftime('%H:%M') }} | {{ commit.project_slug }} | {{ commit.payload.get('author', '') }} | {{ (commit.payload.get('sha', '') or '')[:7] }} {{ commit.payload.get('subject', '') }} |
No entries yet. Sync a tracker or add manual time.
{% endfor %}