Skip to content

feature: converts timers from local to API based#65

Draft
marlonmarcello wants to merge 1 commit into
mainfrom
feature/teamwork/tw-api-timers
Draft

feature: converts timers from local to API based#65
marlonmarcello wants to merge 1 commit into
mainfrom
feature/teamwork/tw-api-timers

Conversation

@marlonmarcello

@marlonmarcello marlonmarcello commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

Refactors teamwork timers from local to API based.

Type of Change

  • Feature
  • Bug fix
  • Refactor
  • Documentation
  • Tooling / CI / release

Local Verification

  • bun run fmt
  • bun run lint
  • bun run check
  • bun run build

Release Impact

  • No release impact
  • Changeset added in .changeset/
  • Updates CLI behavior
  • Updates install/update behavior
  • Updates build/release packaging
  • Breaking change

@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: df2e895

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
wtc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Teamwork timer functionality from a local-cache (“local timers”) implementation to Teamwork’s native (server-side) timer API, updating both the TUI and CLI flows accordingly.

Changes:

  • Replaced local timer persistence + submission workflows with Teamwork native timer list/start/stop/delete operations.
  • Updated TUI task tabs and the dedicated timers tab to display and control server-side timers.
  • Updated CLI teamwork timer subcommands to align with the new API-backed timer model and removed local-only commands.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
src/tui/pages/teamwork/timers-tab.tsx Switches timers tab to API-backed timers and updates keybindings/actions.
src/tui/pages/teamwork/project-tab.tsx Updates task tab timer props/refresh to use API-backed timers.
src/tui/pages/teamwork/my-work-tab.tsx Updates task tab timer props/refresh to use API-backed timers.
src/tui/hooks/use-task-timer.tsx Refactors shared timer hook to call Teamwork timer API (start/stop/list).
src/tui/hooks/use-branch-workflow.tsx Starts API-backed timer when creating branches (was local).
src/tui/components/teamwork/task-list.tsx Uses API timer types + elapsed calculation for task timer badges.
src/cli/commands/timers.ts Refactors CLI timer operations to use API-backed timers and updates formatting/output.
src/cli/commands/teamwork-command.ts Updates CLI subcommands for timers (notably delete replacing prior commands).
src/cli/commands/task-workflow.ts Starts API-backed timer from CLI workflow (was local).
src/api/teamwork/timers/local.ts Deletes the local timer storage/submission implementation.
src/api/teamwork/timers/api.ts Adds Teamwork native timer API client + elapsed/duration formatting helpers.
src/api/teamwork/timers.ts Removes the prior Teamwork timers/time-entry submission API module.
src/api/cache/consts.ts Removes cache key/descriptor for the local timers file.
plans/PLAN.md Updates roadmap note to reflect the new API-backed timer approach.
.changeset/smooth-doors-rest.md Adds a changeset for the timers refactor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/** Stops a running timer by ID. */
export async function stopTimer(timerId: number): Promise<TeamworkTimer> {
try {
const data = (await fetchTeamworkApiJson(`/timers/${timerId}.json`, {
Comment on lines +119 to +123
export function getTimerElapsedMs(timer: TeamworkTimer, now: Date): number {
if (!timer.lastStartedAt) return 0;
const start = new Date(timer.lastStartedAt).getTime();
return Math.max(0, now.getTime() - start);
}
Comment on lines +61 to +66
const body: Record<string, unknown> = {
timer: { taskId },
};
if (description) {
(body.timer as Record<string, unknown>).description = description;
}
): number | null {
if (!timers.length) return null;

const currentIndex = currentId ? timers.findIndex((timer) => timer.id === currentId) : -1;
{(timer) => (
<ListItem
title={timer.taskName}
title={timer.taskName ?? `Task #${timer.taskId}`}
Comment on lines 65 to 69
const stopSelectedTimer = async () => {
const timer = selectedTimer();
if (!timer) {
setMessage("No local timer selected.");
setMessage("No timer selected.");
return;
Comment on lines +82 to 87
const deleteSelectedTimer = () => {
const timer = selectedTimer();
if (!timer) {
setMessage("No local timer selected.");
setMessage("No timer selected.");
return;
}
Comment on lines 49 to 51
const refreshTimers = async () => {
setLocalTimers(await loadLocalTimers());
setTwTimers(await getMyTimers());
};
Comment on lines +22 to 24
const refreshTimers = async () => {
setTimers(await getMyTimers());
};
Comment on lines +43 to +46
const qs = searchParams.toString();
const path = qs ? `/me/timers.json?${qs}` : "/me/timers.json";
const data = (await fetchTeamworkApiJson(path)) as { timers: TeamworkTimer[] };
return data.timers ?? [];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants