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 | 	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 | // GetUserStopwatches return list of all stopwatches of a user | ||||||
| func GetUserStopwatches(userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { | func GetUserStopwatches(userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { | ||||||
| 	sws := make([]*Stopwatch, 0, 8) | 	sws := make([]*Stopwatch, 0, 8) | ||||||
|   | |||||||
| @@ -9,7 +9,9 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/modules/convert" | ||||||
| 	"code.gitea.io/gitea/modules/graceful" | 	"code.gitea.io/gitea/modules/graceful" | ||||||
|  | 	"code.gitea.io/gitea/modules/json" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/process" | 	"code.gitea.io/gitea/modules/process" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| @@ -80,6 +82,31 @@ loop: | |||||||
| 				}) | 				}) | ||||||
| 			} | 			} | ||||||
| 			then = now | 			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() | 	m.UnregisterAll() | ||||||
|   | |||||||
| @@ -8,15 +8,10 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" |  | ||||||
| 	"code.gitea.io/gitea/models/db" |  | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/convert" |  | ||||||
| 	"code.gitea.io/gitea/modules/eventsource" | 	"code.gitea.io/gitea/modules/eventsource" | ||||||
| 	"code.gitea.io/gitea/modules/graceful" | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/json" |  | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" |  | ||||||
| 	"code.gitea.io/gitea/routers/web/auth" | 	"code.gitea.io/gitea/routers/web/auth" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -71,8 +66,6 @@ func Events(ctx *context.Context) { | |||||||
|  |  | ||||||
| 	timer := time.NewTicker(30 * time.Second) | 	timer := time.NewTicker(30 * time.Second) | ||||||
|  |  | ||||||
| 	stopwatchTimer := time.NewTicker(setting.UI.Notification.MinTimeout) |  | ||||||
|  |  | ||||||
| loop: | loop: | ||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
| @@ -93,32 +86,6 @@ loop: | |||||||
| 		case <-shutdownCtx.Done(): | 		case <-shutdownCtx.Done(): | ||||||
| 			go unregister() | 			go unregister() | ||||||
| 			break loop | 			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: | 		case event, ok := <-messageChan: | ||||||
| 			if !ok { | 			if !ok { | ||||||
| 				break loop | 				break loop | ||||||
|   | |||||||
| @@ -9,7 +9,9 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
|  | 	"code.gitea.io/gitea/models/db" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
|  | 	"code.gitea.io/gitea/modules/eventsource" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // IssueStopwatch creates or stops a stopwatch for the given issue. | // IssueStopwatch creates or stops a stopwatch for the given issue. | ||||||
| @@ -59,6 +61,18 @@ func CancelStopwatch(c *context.Context) { | |||||||
| 		return | 		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() | 	url := issue.HTMLURL() | ||||||
| 	c.Redirect(url, http.StatusSeeOther) | 	c.Redirect(url, http.StatusSeeOther) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -127,6 +127,10 @@ function updateStopwatchData(data) { | |||||||
|   const watch = data[0]; |   const watch = data[0]; | ||||||
|   const btnEl = $('.active-stopwatch-trigger'); |   const btnEl = $('.active-stopwatch-trigger'); | ||||||
|   if (!watch) { |   if (!watch) { | ||||||
|  |     if (updateTimeInterval) { | ||||||
|  |       clearInterval(updateTimeInterval); | ||||||
|  |       updateTimeInterval = null; | ||||||
|  |     } | ||||||
|     btnEl.addClass('hidden'); |     btnEl.addClass('hidden'); | ||||||
|   } else { |   } else { | ||||||
|     const {repo_owner_name, repo_name, issue_index, seconds} = watch; |     const {repo_owner_name, repo_name, issue_index, seconds} = watch; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user