mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 19:38:23 +00:00 
			
		
		
		
	Improve Stopwatch behavior (#18930)
- Don't send empty stopwatch over and over again, only send once. - Stop interval to update stopwatch's timer when there is no more stopwatch.
This commit is contained in:
		| @@ -66,6 +66,38 @@ func getStopwatch(ctx context.Context, userID, issueID int64) (sw *Stopwatch, ex | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // UserIDCount is a simple coalition of UserID and Count | ||||
| type UserStopwatch struct { | ||||
| 	UserID      int64 | ||||
| 	StopWatches []*Stopwatch | ||||
| } | ||||
|  | ||||
| // GetUIDsAndNotificationCounts between the two provided times | ||||
| func GetUIDsAndStopwatch() ([]*UserStopwatch, error) { | ||||
| 	sws := []*Stopwatch{} | ||||
| 	if err := db.GetEngine(db.DefaultContext).Find(&sws); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(sws) == 0 { | ||||
| 		return []*UserStopwatch{}, nil | ||||
| 	} | ||||
|  | ||||
| 	lastUserID := int64(-1) | ||||
| 	res := []*UserStopwatch{} | ||||
| 	for _, sw := range sws { | ||||
| 		if lastUserID == sw.UserID { | ||||
| 			lastUserStopwatch := res[len(res)-1] | ||||
| 			lastUserStopwatch.StopWatches = append(lastUserStopwatch.StopWatches, sw) | ||||
| 		} else { | ||||
| 			res = append(res, &UserStopwatch{ | ||||
| 				UserID:      sw.UserID, | ||||
| 				StopWatches: []*Stopwatch{sw}, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
| // GetUserStopwatches return list of all stopwatches of a user | ||||
| func GetUserStopwatches(userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { | ||||
| 	sws := make([]*Stopwatch, 0, 8) | ||||
|   | ||||
| @@ -9,7 +9,9 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/convert" | ||||
| 	"code.gitea.io/gitea/modules/graceful" | ||||
| 	"code.gitea.io/gitea/modules/json" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/process" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| @@ -80,6 +82,31 @@ loop: | ||||
| 				}) | ||||
| 			} | ||||
| 			then = now | ||||
|  | ||||
| 			if setting.Service.EnableTimetracking { | ||||
| 				usersStopwatches, err := models.GetUIDsAndStopwatch() | ||||
| 				if err != nil { | ||||
| 					log.Error("Unable to get GetUIDsAndStopwatch: %v", err) | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
| 				for _, userStopwatches := range usersStopwatches { | ||||
| 					apiSWs, err := convert.ToStopWatches(userStopwatches.StopWatches) | ||||
| 					if err != nil { | ||||
| 						log.Error("Unable to APIFormat stopwatches: %v", err) | ||||
| 						continue | ||||
| 					} | ||||
| 					dataBs, err := json.Marshal(apiSWs) | ||||
| 					if err != nil { | ||||
| 						log.Error("Unable to marshal stopwatches: %v", err) | ||||
| 						continue | ||||
| 					} | ||||
| 					m.SendMessage(userStopwatches.UserID, &Event{ | ||||
| 						Name: "stopwatches", | ||||
| 						Data: string(dataBs), | ||||
| 					}) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	m.UnregisterAll() | ||||
|   | ||||
| @@ -8,15 +8,10 @@ import ( | ||||
| 	"net/http" | ||||
| 	"time" | ||||
|  | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/convert" | ||||
| 	"code.gitea.io/gitea/modules/eventsource" | ||||
| 	"code.gitea.io/gitea/modules/graceful" | ||||
| 	"code.gitea.io/gitea/modules/json" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/routers/web/auth" | ||||
| ) | ||||
|  | ||||
| @@ -71,8 +66,6 @@ func Events(ctx *context.Context) { | ||||
|  | ||||
| 	timer := time.NewTicker(30 * time.Second) | ||||
|  | ||||
| 	stopwatchTimer := time.NewTicker(setting.UI.Notification.MinTimeout) | ||||
|  | ||||
| loop: | ||||
| 	for { | ||||
| 		select { | ||||
| @@ -93,32 +86,6 @@ loop: | ||||
| 		case <-shutdownCtx.Done(): | ||||
| 			go unregister() | ||||
| 			break loop | ||||
| 		case <-stopwatchTimer.C: | ||||
| 			sws, err := models.GetUserStopwatches(ctx.Doer.ID, db.ListOptions{}) | ||||
| 			if err != nil { | ||||
| 				log.Error("Unable to GetUserStopwatches: %v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			apiSWs, err := convert.ToStopWatches(sws) | ||||
| 			if err != nil { | ||||
| 				log.Error("Unable to APIFormat stopwatches: %v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			dataBs, err := json.Marshal(apiSWs) | ||||
| 			if err != nil { | ||||
| 				log.Error("Unable to marshal stopwatches: %v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			_, err = (&eventsource.Event{ | ||||
| 				Name: "stopwatches", | ||||
| 				Data: string(dataBs), | ||||
| 			}).WriteTo(ctx.Resp) | ||||
| 			if err != nil { | ||||
| 				log.Error("Unable to write to EventStream for user %s: %v", ctx.Doer.Name, err) | ||||
| 				go unregister() | ||||
| 				break loop | ||||
| 			} | ||||
| 			ctx.Resp.Flush() | ||||
| 		case event, ok := <-messageChan: | ||||
| 			if !ok { | ||||
| 				break loop | ||||
|   | ||||
| @@ -9,7 +9,9 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/eventsource" | ||||
| ) | ||||
|  | ||||
| // IssueStopwatch creates or stops a stopwatch for the given issue. | ||||
| @@ -59,6 +61,18 @@ func CancelStopwatch(c *context.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	stopwatches, err := models.GetUserStopwatches(c.Doer.ID, db.ListOptions{}) | ||||
| 	if err != nil { | ||||
| 		c.ServerError("GetUserStopwatches", err) | ||||
| 		return | ||||
| 	} | ||||
| 	if len(stopwatches) == 0 { | ||||
| 		eventsource.GetManager().SendMessage(c.Doer.ID, &eventsource.Event{ | ||||
| 			Name: "stopwatches", | ||||
| 			Data: "{}", | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	url := issue.HTMLURL() | ||||
| 	c.Redirect(url, http.StatusSeeOther) | ||||
| } | ||||
|   | ||||
| @@ -127,6 +127,10 @@ function updateStopwatchData(data) { | ||||
|   const watch = data[0]; | ||||
|   const btnEl = $('.active-stopwatch-trigger'); | ||||
|   if (!watch) { | ||||
|     if (updateTimeInterval) { | ||||
|       clearInterval(updateTimeInterval); | ||||
|       updateTimeInterval = null; | ||||
|     } | ||||
|     btnEl.addClass('hidden'); | ||||
|   } else { | ||||
|     const {repo_owner_name, repo_name, issue_index, seconds} = watch; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user