mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Redesign the time tracker side bar, and add "time estimate" support (in "1d 2m" format) Closes #23112 --------- Co-authored-by: stuzer05 <stuzer05@gmail.com> Co-authored-by: Yarden Shoham <hrsi88@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
		
			
				
	
	
		
			86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2024 Gitea. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package util
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"regexp"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
)
 | 
						|
 | 
						|
type timeStrGlobalVarsType struct {
 | 
						|
	units []struct {
 | 
						|
		name string
 | 
						|
		num  int64
 | 
						|
	}
 | 
						|
	re *regexp.Regexp
 | 
						|
}
 | 
						|
 | 
						|
// When tracking working time, only hour/minute/second units are accurate and could be used.
 | 
						|
// For other units like "day", it depends on "how many working hours in a day": 6 or 7 or 8?
 | 
						|
// So at the moment, we only support hour/minute/second units.
 | 
						|
// In the future, it could be some configurable options to help users
 | 
						|
// to convert the working time to different units.
 | 
						|
 | 
						|
var timeStrGlobalVars = sync.OnceValue[*timeStrGlobalVarsType](func() *timeStrGlobalVarsType {
 | 
						|
	v := &timeStrGlobalVarsType{}
 | 
						|
	v.re = regexp.MustCompile(`(?i)(\d+)\s*([hms])`)
 | 
						|
	v.units = []struct {
 | 
						|
		name string
 | 
						|
		num  int64
 | 
						|
	}{
 | 
						|
		{"h", 60 * 60},
 | 
						|
		{"m", 60},
 | 
						|
		{"s", 1},
 | 
						|
	}
 | 
						|
	return v
 | 
						|
})
 | 
						|
 | 
						|
func TimeEstimateParse(timeStr string) (int64, error) {
 | 
						|
	if timeStr == "" {
 | 
						|
		return 0, nil
 | 
						|
	}
 | 
						|
	var total int64
 | 
						|
	matches := timeStrGlobalVars().re.FindAllStringSubmatchIndex(timeStr, -1)
 | 
						|
	if len(matches) == 0 {
 | 
						|
		return 0, fmt.Errorf("invalid time string: %s", timeStr)
 | 
						|
	}
 | 
						|
	if matches[0][0] != 0 || matches[len(matches)-1][1] != len(timeStr) {
 | 
						|
		return 0, fmt.Errorf("invalid time string: %s", timeStr)
 | 
						|
	}
 | 
						|
	for _, match := range matches {
 | 
						|
		amount, err := strconv.ParseInt(timeStr[match[2]:match[3]], 10, 64)
 | 
						|
		if err != nil {
 | 
						|
			return 0, fmt.Errorf("invalid time string: %v", err)
 | 
						|
		}
 | 
						|
		unit := timeStr[match[4]:match[5]]
 | 
						|
		found := false
 | 
						|
		for _, u := range timeStrGlobalVars().units {
 | 
						|
			if strings.ToLower(unit) == u.name {
 | 
						|
				total += amount * u.num
 | 
						|
				found = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !found {
 | 
						|
			return 0, fmt.Errorf("invalid time unit: %s", unit)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return total, nil
 | 
						|
}
 | 
						|
 | 
						|
func TimeEstimateString(amount int64) string {
 | 
						|
	var timeParts []string
 | 
						|
	for _, u := range timeStrGlobalVars().units {
 | 
						|
		if amount >= u.num {
 | 
						|
			num := amount / u.num
 | 
						|
			amount %= u.num
 | 
						|
			timeParts = append(timeParts, fmt.Sprintf("%d%s", num, u.name))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return strings.Join(timeParts, " ")
 | 
						|
}
 |