From e970a756d22d1421935d12b2379830e7be5d63ee Mon Sep 17 00:00:00 2001 From: workjs1124 Date: Mon, 23 Jun 2025 15:12:28 +0900 Subject: [PATCH 1/5] Signed-off-by: workjs1124 fix(issue): Replace stopwatch toggle with explicit start/stop actions The stopwatch toggle mechanism caused state desynchronization issues when used across multiple browser tabs, leading to a "stop" action incorrectly starting the timer again. This commit replaces the single toggle endpoint with two explicit endpoints: `/start` and `/stop`. This ensures that the user's intent is always clear and prevents unexpected behavior, resolving the state inconsistency bug. --- options/locale/locale_en-US.ini | 1 + routers/web/repo/issue_stopwatch.go | 40 ++++++++++++++----- routers/web/web.go | 3 +- templates/base/head_navbar.tmpl | 2 +- .../issue/sidebar/stopwatch_timetracker.tmpl | 4 +- tests/integration/timetracking_test.go | 18 +++++---- web_src/js/features/stopwatch.ts | 2 +- 7 files changed, 47 insertions(+), 23 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 0efc9d04c25e4..8c3becf21312b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1726,6 +1726,7 @@ issues.remove_time_estimate_at = removed time estimate %s issues.time_estimate_invalid = Time estimate format is invalid issues.start_tracking_history = started working %s issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed +issues.tracker_already_stopped = The timer for this issue is already stopped issues.tracking_already_started = `You have already started time tracking on another issue!` issues.stop_tracking = Stop Timer issues.stop_tracking_history = worked for %[1]s %[2]s diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go index 5a8d203771900..a582af1eaeb2a 100644 --- a/routers/web/repo/issue_stopwatch.go +++ b/routers/web/repo/issue_stopwatch.go @@ -10,31 +10,49 @@ import ( "code.gitea.io/gitea/services/context" ) -// IssueStopwatch creates or stops a stopwatch for the given issue. -func IssueStopwatch(c *context.Context) { +// IssueStartStopwatch creates a stopwatch for the given issue. +func IssueStartStopwatch(c *context.Context) { issue := GetActionIssue(c) if c.Written() { return } - var showSuccessMessage bool + if !c.Repo.CanUseTimetracker(c, issue, c.Doer) { + c.NotFound(nil) + return + } - if !issues_model.StopwatchExists(c, c.Doer.ID, issue.ID) { - showSuccessMessage = true + if err := issues_model.CreateIssueStopwatch(c, c.Doer, issue); err != nil { + c.ServerError("CreateIssueStopwatch", err) + return } - if !c.Repo.CanUseTimetracker(c, issue, c.Doer) { - c.NotFound(nil) + c.Flash.Success(c.Tr("repo.issues.tracker_auto_close")) + + c.JSONRedirect("") +} + +// IssueStopStopwatch stops a stopwatch for the given issue. +func IssueStopStopwatch(c *context.Context) { + issue := GetActionIssue(c) + if c.Written() { return } - if err := issues_model.CreateOrStopIssueStopwatch(c, c.Doer, issue); err != nil { - c.ServerError("CreateOrStopIssueStopwatch", err) + if !c.Repo.CanUseTimetracker(c, issue, c.Doer) { + c.NotFound(nil) return } - if showSuccessMessage { - c.Flash.Success(c.Tr("repo.issues.tracker_auto_close")) + wasRunning := issues_model.StopwatchExists(c, c.Doer.ID, issue.ID) + + if wasRunning { + if err := issues_model.FinishIssueStopwatch(c, c.Doer, issue); err != nil { + c.ServerError("FinishIssueStopwatch", err) + return + } + } else { + c.Flash.Warning(c.Tr("repo.issues.tracker_already_stopped")) } c.JSONRedirect("") diff --git a/routers/web/web.go b/routers/web/web.go index 4b5d68b260f6b..66a5a9be5e81a 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1253,7 +1253,8 @@ func registerWebRoutes(m *web.Router) { m.Post("/add", web.Bind(forms.AddTimeManuallyForm{}), repo.AddTimeManually) m.Post("/{timeid}/delete", repo.DeleteTime) m.Group("/stopwatch", func() { - m.Post("/toggle", repo.IssueStopwatch) + m.Post("/start", repo.IssueStartStopwatch) + m.Post("/stop", repo.IssueStopStopwatch) m.Post("/cancel", repo.CancelStopwatch) }) }) diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 35e14d38d3b10..dacc51887338e 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -197,7 +197,7 @@ {{$activeStopwatch.RepoSlug}}#{{$activeStopwatch.IssueIndex}}
-
+ {{.CsrfTokenHtml}}