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:
		
							parent
							
								
									1ebb30e41b
								
							
						
					
					
						commit
						4e912a61c8
					
				
					 5 changed files with 77 additions and 33 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue