diff --git a/.dockerignore b/.dockerignore
index b299c7313d05d..b696e1603cca7 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -95,6 +95,9 @@ cpu.out
/.air
/.go-licenses
+# Files and folders that were previously generated
+/public/assets/img/webpack
+
# Snapcraft
snap/.snapcraft/
parts/
diff --git a/.gitattributes b/.gitattributes
index 467b8a47b5d6d..9fb4a4e83dd71 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
* text=auto eol=lf
*.tmpl linguist-language=Handlebars
+*.pb.go linguist-generated
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
diff --git a/.gitignore b/.gitignore
index 501fef7dcf888..46c8b9b49c9af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,9 @@ cpu.out
/.air
/.go-licenses
+# Files and folders that were previously generated
+/public/assets/img/webpack
+
# Snapcraft
/gitea_a*.txt
snap/.snapcraft/
diff --git a/.golangci.yml b/.golangci.yml
index 5be2cefe44b7d..27fee20f75ae6 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -86,6 +86,8 @@ linters-settings:
desc: do not use the internal package, use AddXxx function instead
- pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead
+ - pkg: gitea.com/go-chi/cache
+ desc: do not use the go-chi cache package, use gitea's cache system
issues:
max-issues-per-linter: 0
diff --git a/Makefile b/Makefile
index ee9c90e8d9721..594f13ead8acf 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ COMMA := ,
XGO_VERSION := go-1.22.x
-AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0
+AIR_PACKAGE ?= github.com/cosmtrek/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2
@@ -33,9 +33,9 @@ GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
-GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
-GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.3
-ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.26
+GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
+GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
+ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -295,7 +295,7 @@ clean:
.PHONY: fmt
fmt:
- GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
+ @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@# whitespace before it
diff --git a/build/code-batch-process.go b/build/code-batch-process.go
index b3ee3994207dc..cc2ab680268c9 100644
--- a/build/code-batch-process.go
+++ b/build/code-batch-process.go
@@ -69,6 +69,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
+ co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
@@ -203,17 +204,6 @@ Example:
`, "file-batch-exec")
}
-func getGoVersion() string {
- goModFile, err := os.ReadFile("go.mod")
- if err != nil {
- log.Fatalf(`Faild to read "go.mod": %v`, err)
- os.Exit(1)
- }
- goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
- goModVersionLine := goModVersionRegex.Find(goModFile)
- return string(goModVersionLine[3:])
-}
-
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
@@ -278,7 +268,8 @@ func main() {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
- cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...)))
+ cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
+ cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index 9d53fffc78695..bc1bcaef63210 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -137,6 +137,11 @@ func (app *OAuth2Application) TableName() string {
// ContainsRedirectURI checks if redirectURI is allowed for app
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
+ // OAuth2 requires the redirect URI to be an exact match, no dynamic parts are allowed.
+ // https://stackoverflow.com/questions/55524480/should-dynamic-query-parameters-be-present-in-the-redirection-uri-for-an-oauth2
+ // https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3
+ // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
+ // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1
contains := func(s string) bool {
s = strings.TrimSuffix(strings.ToLower(s), "/")
for _, u := range app.RedirectURIs {
diff --git a/models/git/branch.go b/models/git/branch.go
index fa0781fed1d57..2979dff3d211e 100644
--- a/models/git/branch.go
+++ b/models/git/branch.go
@@ -297,6 +297,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
sess := db.GetEngine(ctx)
+ // check whether from branch exist
var branch Branch
exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch)
if err != nil {
@@ -308,6 +309,24 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
}
}
+ // check whether to branch exist or is_deleted
+ var dstBranch Branch
+ exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch)
+ if err != nil {
+ return err
+ }
+ if exist {
+ if !dstBranch.IsDeleted {
+ return ErrBranchAlreadyExists{
+ BranchName: to,
+ }
+ }
+
+ if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil {
+ return err
+ }
+ }
+
// 1. update branch in database
if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{
Name: to,
@@ -362,12 +381,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
- // 5. do git action
- if err = gitAction(ctx, isDefault); err != nil {
- return err
- }
-
- // 6. insert renamed branch record
+ // 5. insert renamed branch record
renamedBranch := &RenamedBranch{
RepoID: repo.ID,
From: from,
@@ -378,6 +392,11 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
+ // 6. do git action
+ if err = gitAction(ctx, isDefault); err != nil {
+ return err
+ }
+
return committer.Commit()
}
diff --git a/modules/cache/cache.go b/modules/cache/cache.go
index 09afc8b7f7364..2ca77bdb29f37 100644
--- a/modules/cache/cache.go
+++ b/modules/cache/cache.go
@@ -4,149 +4,75 @@
package cache
import (
- "fmt"
"strconv"
+ "time"
"code.gitea.io/gitea/modules/setting"
-
- mc "gitea.com/go-chi/cache"
-
- _ "gitea.com/go-chi/cache/memcache" // memcache plugin for cache
)
-var conn mc.Cache
-
-func newCache(cacheConfig setting.Cache) (mc.Cache, error) {
- return mc.NewCacher(mc.Options{
- Adapter: cacheConfig.Adapter,
- AdapterConfig: cacheConfig.Conn,
- Interval: cacheConfig.Interval,
- })
-}
+var defaultCache StringCache
// Init start cache service
func Init() error {
- var err error
-
- if conn == nil {
- if conn, err = newCache(setting.CacheService.Cache); err != nil {
+ if defaultCache == nil {
+ c, err := NewStringCache(setting.CacheService.Cache)
+ if err != nil {
return err
}
- if err = conn.Ping(); err != nil {
+ for i := 0; i < 10; i++ {
+ if err = c.Ping(); err == nil {
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ if err != nil {
return err
}
+ defaultCache = c
}
-
- return err
+ return nil
}
// GetCache returns the currently configured cache
-func GetCache() mc.Cache {
- return conn
+func GetCache() StringCache {
+ return defaultCache
}
// GetString returns the key value from cache with callback when no key exists in cache
func GetString(key string, getFunc func() (string, error)) (string, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
+ if defaultCache == nil || setting.CacheService.TTL == 0 {
return getFunc()
}
-
- cached := conn.Get(key)
-
- if cached == nil {
+ cached, exist := defaultCache.Get(key)
+ if !exist {
value, err := getFunc()
if err != nil {
return value, err
}
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
- }
-
- if value, ok := cached.(string); ok {
- return value, nil
- }
-
- if stringer, ok := cached.(fmt.Stringer); ok {
- return stringer.String(), nil
- }
-
- return fmt.Sprintf("%s", cached), nil
-}
-
-// GetInt returns key value from cache with callback when no key exists in cache
-func GetInt(key string, getFunc func() (int, error)) (int, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
- return getFunc()
- }
-
- cached := conn.Get(key)
-
- if cached == nil {
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
- }
-
- switch v := cached.(type) {
- case int:
- return v, nil
- case string:
- value, err := strconv.Atoi(v)
- if err != nil {
- return 0, err
- }
- return value, nil
- default:
- value, err := getFunc()
- if err != nil {
- return value, err
- }
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
+ return value, defaultCache.Put(key, value, setting.CacheService.TTLSeconds())
}
+ return cached, nil
}
// GetInt64 returns key value from cache with callback when no key exists in cache
func GetInt64(key string, getFunc func() (int64, error)) (int64, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
- return getFunc()
- }
-
- cached := conn.Get(key)
-
- if cached == nil {
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
+ s, err := GetString(key, func() (string, error) {
+ v, err := getFunc()
+ return strconv.FormatInt(v, 10), err
+ })
+ if err != nil {
+ return 0, err
}
-
- switch v := conn.Get(key).(type) {
- case int64:
- return v, nil
- case string:
- value, err := strconv.ParseInt(v, 10, 64)
- if err != nil {
- return 0, err
- }
- return value, nil
- default:
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
+ if s == "" {
+ return 0, nil
}
+ return strconv.ParseInt(s, 10, 64)
}
// Remove key from cache
func Remove(key string) {
- if conn == nil {
+ if defaultCache == nil {
return
}
- _ = conn.Delete(key)
+ _ = defaultCache.Delete(key)
}
diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go
index 6c358b0a78a4d..c5b52a2086ceb 100644
--- a/modules/cache/cache_redis.go
+++ b/modules/cache/cache_redis.go
@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/nosql"
- "gitea.com/go-chi/cache"
+ "gitea.com/go-chi/cache" //nolint:depguard
"github.com/redis/go-redis/v9"
)
diff --git a/modules/cache/cache_test.go b/modules/cache/cache_test.go
index 3f6504092462a..0c68cc26ee546 100644
--- a/modules/cache/cache_test.go
+++ b/modules/cache/cache_test.go
@@ -14,7 +14,7 @@ import (
)
func createTestCache() {
- conn, _ = newCache(setting.Cache{
+ defaultCache, _ = NewStringCache(setting.Cache{
Adapter: "memory",
TTL: time.Minute,
})
@@ -25,7 +25,7 @@ func TestNewContext(t *testing.T) {
assert.NoError(t, Init())
setting.CacheService.Cache = setting.Cache{Adapter: "redis", Conn: "some random string"}
- con, err := newCache(setting.Cache{
+ con, err := NewStringCache(setting.Cache{
Adapter: "rand",
Conn: "false conf",
Interval: 100,
@@ -76,42 +76,6 @@ func TestGetString(t *testing.T) {
Remove("key")
}
-func TestGetInt(t *testing.T) {
- createTestCache()
-
- data, err := GetInt("key", func() (int, error) {
- return 0, fmt.Errorf("some error")
- })
- assert.Error(t, err)
- assert.Equal(t, 0, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 0, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 0, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 100, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 0, data)
- Remove("key")
-
- data, err = GetInt("key", func() (int, error) {
- return 100, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 100, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 0, fmt.Errorf("some error")
- })
- assert.NoError(t, err)
- assert.Equal(t, 100, data)
- Remove("key")
-}
-
func TestGetInt64(t *testing.T) {
createTestCache()
diff --git a/modules/cache/cache_twoqueue.go b/modules/cache/cache_twoqueue.go
index f9de2563ec72c..1eda2debc43aa 100644
--- a/modules/cache/cache_twoqueue.go
+++ b/modules/cache/cache_twoqueue.go
@@ -10,7 +10,7 @@ import (
"code.gitea.io/gitea/modules/json"
- mc "gitea.com/go-chi/cache"
+ mc "gitea.com/go-chi/cache" //nolint:depguard
lru "github.com/hashicorp/golang-lru/v2"
)
diff --git a/modules/cache/string_cache.go b/modules/cache/string_cache.go
new file mode 100644
index 0000000000000..4f659616f501e
--- /dev/null
+++ b/modules/cache/string_cache.go
@@ -0,0 +1,120 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package cache
+
+import (
+ "errors"
+ "strings"
+
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+
+ chi_cache "gitea.com/go-chi/cache" //nolint:depguard
+)
+
+type GetJSONError struct {
+ err error
+ cachedError string // Golang error can't be stored in cache, only the string message could be stored
+}
+
+func (e *GetJSONError) ToError() error {
+ if e.err != nil {
+ return e.err
+ }
+ return errors.New("cached error: " + e.cachedError)
+}
+
+type StringCache interface {
+ Ping() error
+
+ Get(key string) (string, bool)
+ Put(key, value string, ttl int64) error
+ Delete(key string) error
+ IsExist(key string) bool
+
+ PutJSON(key string, v any, ttl int64) error
+ GetJSON(key string, ptr any) (exist bool, err *GetJSONError)
+
+ ChiCache() chi_cache.Cache
+}
+
+type stringCache struct {
+ chiCache chi_cache.Cache
+}
+
+func NewStringCache(cacheConfig setting.Cache) (StringCache, error) {
+ adapter := util.IfZero(cacheConfig.Adapter, "memory")
+ interval := util.IfZero(cacheConfig.Interval, 60)
+ cc, err := chi_cache.NewCacher(chi_cache.Options{
+ Adapter: adapter,
+ AdapterConfig: cacheConfig.Conn,
+ Interval: interval,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &stringCache{chiCache: cc}, nil
+}
+
+func (sc *stringCache) Ping() error {
+ return sc.chiCache.Ping()
+}
+
+func (sc *stringCache) Get(key string) (string, bool) {
+ v := sc.chiCache.Get(key)
+ if v == nil {
+ return "", false
+ }
+ s, ok := v.(string)
+ return s, ok
+}
+
+func (sc *stringCache) Put(key, value string, ttl int64) error {
+ return sc.chiCache.Put(key, value, ttl)
+}
+
+func (sc *stringCache) Delete(key string) error {
+ return sc.chiCache.Delete(key)
+}
+
+func (sc *stringCache) IsExist(key string) bool {
+ return sc.chiCache.IsExist(key)
+}
+
+const cachedErrorPrefix = ":"
+
+func (sc *stringCache) PutJSON(key string, v any, ttl int64) error {
+ var s string
+ switch v := v.(type) {
+ case error:
+ s = cachedErrorPrefix + v.Error()
+ default:
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+ s = util.UnsafeBytesToString(b)
+ }
+ return sc.chiCache.Put(key, s, ttl)
+}
+
+func (sc *stringCache) GetJSON(key string, ptr any) (exist bool, getErr *GetJSONError) {
+ s, ok := sc.Get(key)
+ if !ok || s == "" {
+ return false, nil
+ }
+ s, isCachedError := strings.CutPrefix(s, cachedErrorPrefix)
+ if isCachedError {
+ return true, &GetJSONError{cachedError: s}
+ }
+ if err := json.Unmarshal(util.UnsafeStringToBytes(s), ptr); err != nil {
+ return false, &GetJSONError{err: err}
+ }
+ return true, nil
+}
+
+func (sc *stringCache) ChiCache() chi_cache.Cache {
+ return sc.chiCache
+}
diff --git a/modules/git/grep.go b/modules/git/grep.go
index a6c486112a5f6..e7d238e586aa4 100644
--- a/modules/git/grep.go
+++ b/modules/git/grep.go
@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"os"
+ "slices"
"strconv"
"strings"
@@ -27,6 +28,7 @@ type GrepOptions struct {
MaxResultLimit int
ContextLineNumber int
IsFuzzy bool
+ MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated
}
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
@@ -71,10 +73,20 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
defer stdoutReader.Close()
isInBlock := false
- scanner := bufio.NewScanner(stdoutReader)
+ rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024))
var res *GrepResult
- for scanner.Scan() {
- line := scanner.Text()
+ for {
+ lineBytes, isPrefix, err := rd.ReadLine()
+ if isPrefix {
+ lineBytes = slices.Clone(lineBytes)
+ for isPrefix && err == nil {
+ _, isPrefix, err = rd.ReadLine()
+ }
+ }
+ if len(lineBytes) == 0 && err != nil {
+ break
+ }
+ line := string(lineBytes) // the memory of lineBytes is mutable
if !isInBlock {
if _ /* ref */, filename, ok := strings.Cut(line, ":"); ok {
isInBlock = true
@@ -100,7 +112,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
res.LineCodes = append(res.LineCodes, lineCode)
}
}
- return scanner.Err()
+ return nil
},
})
// git grep exits by cancel (killed), usually it is caused by the limit of results
diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go
index b5fa437c53f8c..7f4ded478f571 100644
--- a/modules/git/grep_test.go
+++ b/modules/git/grep_test.go
@@ -41,6 +41,16 @@ func TestGrepSearch(t *testing.T) {
},
}, res)
+ res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1, MaxLineLength: 39})
+ assert.NoError(t, err)
+ assert.Equal(t, []*GrepResult{
+ {
+ Filename: "java-hello/main.java",
+ LineNumbers: []int{3},
+ LineCodes: []string{" public static void main(String[] arg"},
+ },
+ }, res)
+
res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{})
assert.NoError(t, err)
assert.Len(t, res, 0)
diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go
index 5b62b90b27958..cf9c10d7b468e 100644
--- a/modules/git/last_commit_cache.go
+++ b/modules/git/last_commit_cache.go
@@ -7,18 +7,11 @@ import (
"crypto/sha256"
"fmt"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
-// Cache represents a caching interface
-type Cache interface {
- // Put puts value into cache with key and expire time.
- Put(key string, val any, timeout int64) error
- // Get gets cached value by given key.
- Get(key string) any
-}
-
func getCacheKey(repoPath, commitID, entryPath string) string {
hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath)))
return fmt.Sprintf("last_commit:%x", hashBytes)
@@ -30,11 +23,11 @@ type LastCommitCache struct {
ttl func() int64
repo *Repository
commitCache map[string]*Commit
- cache Cache
+ cache cache.StringCache
}
// NewLastCommitCache creates a new last commit cache for repo
-func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache {
+func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache cache.StringCache) *LastCommitCache {
if cache == nil {
return nil
}
@@ -65,7 +58,7 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
return nil, nil
}
- commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string)
+ commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath))
if !ok || commitID == "" {
return nil, nil
}
diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go
index 6688e78cd1812..b120a0edf6b94 100644
--- a/modules/optional/serialization.go
+++ b/modules/optional/serialization.go
@@ -35,7 +35,7 @@ func (o *Option[T]) UnmarshalYAML(value *yaml.Node) error {
return nil
}
-func (o Option[T]) MarshalYAML() (interface{}, error) {
+func (o Option[T]) MarshalYAML() (any, error) {
if !o.Has() {
return nil, nil
}
diff --git a/modules/session/store.go b/modules/session/store.go
index 4fa4d2848f1b8..2f7ab7760b597 100644
--- a/modules/session/store.go
+++ b/modules/session/store.go
@@ -6,6 +6,9 @@ package session
import (
"net/http"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/web/middleware"
+
"gitea.com/go-chi/session"
)
@@ -18,6 +21,10 @@ type Store interface {
// RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
+ // Ensure that a cookie with a trailing slash does not take precedence over
+ // the cookie written by the middleware.
+ middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
+
s, err := session.RegenerateSession(resp, req)
return s, err
}
diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go
index 6c1b4ab240e34..774385483b4c6 100644
--- a/modules/templates/util_misc.go
+++ b/modules/templates/util_misc.go
@@ -142,35 +142,39 @@ type remoteAddress struct {
Password string
}
-func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress {
- a := remoteAddress{}
-
- remoteURL := m.OriginalURL
- if ignoreOriginalURL || remoteURL == "" {
- var err error
- remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
- if err != nil {
- log.Error("GetRemoteURL %v", err)
- return a
- }
+func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
+ ret := remoteAddress{}
+ remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
+ if err != nil {
+ log.Error("GetRemoteURL %v", err)
+ return ret
}
u, err := giturl.Parse(remoteURL)
if err != nil {
log.Error("giturl.Parse %v", err)
- return a
+ return ret
}
if u.Scheme != "ssh" && u.Scheme != "file" {
if u.User != nil {
- a.Username = u.User.Username()
- a.Password, _ = u.User.Password()
+ ret.Username = u.User.Username()
+ ret.Password, _ = u.User.Password()
}
- u.User = nil
}
- a.Address = u.String()
- return a
+ // The URL stored in the git repo could contain authentication,
+ // erase it, or it will be shown in the UI.
+ u.User = nil
+ ret.Address = u.String()
+ // Why not use m.OriginalURL to set ret.Address?
+ // It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository.
+ // However, the old code has already stored authentication in m.OriginalURL when updating mirror settings.
+ // That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased.
+ // Instead of doing this, why not directly use the authentication-erased URL from the Git repository?
+ // It should be the same as long as there are no bugs.
+
+ return ret
}
func FilenameIsImage(filename string) bool {
diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go
index 0b53965f25805..659422aee7989 100644
--- a/modules/templates/util_render.go
+++ b/modules/templates/util_render.go
@@ -216,15 +216,16 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n
return output
}
-func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string) template.HTML {
+func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML {
+ isPullRequest := issue != nil && issue.IsPull
+ baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues"))
htmlCode := ``
for _, label := range labels {
// Protect against nil value in labels - shouldn't happen but would cause a panic if so
if label == nil {
continue
}
- htmlCode += fmt.Sprintf("%s ",
- repoLink, label.ID, RenderLabel(ctx, locale, label))
+ htmlCode += fmt.Sprintf(`%s`, baseLink, label.ID, RenderLabel(ctx, locale, label))
}
htmlCode += ""
return template.HTML(htmlCode)
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 15aee8912d1ec..47c5da6485c37 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -7,17 +7,21 @@ import (
"context"
"html/template"
"os"
+ "strings"
"testing"
+ "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/translation"
"github.com/stretchr/testify/assert"
)
-const testInput = ` space @mention-user
+func testInput() string {
+ s := ` space @mention-user
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
@@ -36,8 +40,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
#123
- space
+ space
`
+ return strings.ReplaceAll(s, "", " ")
+}
var testMetas = map[string]string{
"user": "user13",
@@ -121,23 +127,23 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
#123
space`
- assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
+ assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput(), testMetas))
}
func TestRenderCommitMessage(t *testing.T) {
expected := `space @mention-user `
- assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas))
+ assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput(), testMetas))
}
func TestRenderCommitMessageLinkSubject(t *testing.T) {
expected := `space @mention-user`
- assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas))
+ assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput(), "https://example.com/link", testMetas))
}
func TestRenderIssueTitle(t *testing.T) {
- expected := ` space @mention-user
+ expected := ` space @mention-user
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
@@ -156,9 +162,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
#123
- space
+ space
`
- assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
+ expected = strings.ReplaceAll(expected, "", " ")
+ assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput(), testMetas))
}
func TestRenderMarkdownToHtml(t *testing.T) {
@@ -183,5 +190,20 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
#123
space
`
- assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput))
+ assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput()))
+}
+
+func TestRenderLabels(t *testing.T) {
+ ctx := context.Background()
+ locale := &translation.MockLocale{}
+
+ label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
+ issue := &issues.Issue{}
+ expected := `/owner/repo/issues?labels=123`
+ assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected)
+
+ label = &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
+ issue = &issues.Issue{IsPull: true}
+ expected = `/owner/repo/pulls?labels=123`
+ assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected)
}
diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go
index 621640895b95f..0bed7267930cd 100644
--- a/modules/web/middleware/cookie.go
+++ b/modules/web/middleware/cookie.go
@@ -45,10 +45,32 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
SameSite: setting.SessionConfig.SameSite,
}
resp.Header().Add("Set-Cookie", cookie.String())
- if maxAge < 0 {
- // There was a bug in "setting.SessionConfig.CookiePath" code, the old default value of it was empty "".
- // So we have to delete the cookie on path="" again, because some old code leaves cookies on path="".
- cookie.Path = strings.TrimSuffix(setting.SessionConfig.CookiePath, "/")
- resp.Header().Add("Set-Cookie", cookie.String())
+ // Previous versions would use a cookie path with a trailing /.
+ // These are more specific than cookies without a trailing /, so
+ // we need to delete these if they exist.
+ DeleteLegacySiteCookie(resp, name)
+}
+
+// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie
+// path with a trailing /, which would unintentionally override the cookie.
+func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
+ if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
+ // If the cookie path ends with /, no legacy cookies will take
+ // precedence, so do nothing. The exception is that cookies with no
+ // path could override other cookies, but it's complicated and we don't
+ // currently handle that.
+ return
}
+
+ cookie := &http.Cookie{
+ Name: name,
+ Value: "",
+ MaxAge: -1,
+ Path: setting.SessionConfig.CookiePath + "/",
+ Domain: setting.SessionConfig.Domain,
+ Secure: setting.SessionConfig.Secure,
+ HttpOnly: true,
+ SameSite: setting.SessionConfig.SameSite,
+ }
+ resp.Header().Add("Set-Cookie", cookie.String())
}
diff --git a/package-lock.json b/package-lock.json
index 3459e8add405e..29341330dd30c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,7 +21,7 @@
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.0.1",
"clippie": "4.0.7",
- "css-loader": "7.0.0",
+ "css-loader": "7.1.1",
"dayjs": "1.11.10",
"dropzone": "6.0.0-beta.2",
"easymde": "2.18.0",
@@ -44,9 +44,9 @@
"postcss-nesting": "12.1.1",
"pretty-ms": "9.0.0",
"sortablejs": "1.15.2",
- "swagger-ui-dist": "5.13.0",
+ "swagger-ui-dist": "5.15.1",
"tailwindcss": "3.4.3",
- "temporal-polyfill": "0.2.3",
+ "temporal-polyfill": "0.2.4",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@@ -56,7 +56,7 @@
"vanilla-colorful": "0.7.2",
"vue": "3.4.21",
"vue-bar-graph": "2.0.0",
- "vue-chartjs": "5.3.0",
+ "vue-chartjs": "5.3.1",
"vue-loader": "17.4.2",
"vue3-calendar-heatmap": "2.0.5",
"webpack": "5.91.0",
@@ -64,8 +64,8 @@
"wrap-ansi": "9.0.0"
},
"devDependencies": {
- "@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.42.1",
+ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
+ "@playwright/test": "1.43.1",
"@stoplight/spectral-cli": "6.11.1",
"@stylistic/eslint-plugin-js": "1.7.0",
"@stylistic/stylelint-plugin": "2.1.1",
@@ -77,15 +77,15 @@
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.4.0",
+ "eslint-plugin-regexp": "2.5.0",
"eslint-plugin-sonarjs": "0.25.1",
"eslint-plugin-unicorn": "52.0.0",
"eslint-plugin-vitest": "0.4.1",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.24.0",
+ "eslint-plugin-vue": "9.24.1",
"eslint-plugin-vue-scoped-css": "2.8.0",
- "eslint-plugin-wc": "2.0.4",
- "happy-dom": "14.5.0",
+ "eslint-plugin-wc": "2.1.0",
+ "happy-dom": "14.7.1",
"markdownlint-cli": "0.39.0",
"postcss-html": "1.6.0",
"stylelint": "16.3.1",
@@ -93,9 +93,9 @@
"stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0",
- "updates": "16.0.0",
+ "updates": "16.0.1",
"vite-string-plugin": "1.1.5",
- "vitest": "1.4.0"
+ "vitest": "1.5.0"
},
"engines": {
"node": ">= 18.0.0"
@@ -865,9 +865,9 @@
}
},
"node_modules/@eslint-community/eslint-plugin-eslint-comments": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.1.0.tgz",
- "integrity": "sha512-B2mwipifrBS5E00vN8vME68laPMZ0h3sNGOEDj5g9iUN9k5EU99Omq0Nc325eKNoFFDnDtiHp3DqIjO+1bstag==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.3.0.tgz",
+ "integrity": "sha512-6e93KtgsndNkvwCCa07LOQJSwzzLLxwrFll3+huyFoiiQXWG0KBcmo0Q1bVgYQQDLfWOOZl2VPBsXqZL6vHIBQ==",
"dev": true,
"dependencies": {
"escape-string-regexp": "^4.0.0",
@@ -877,7 +877,7 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/@eslint-community/eslint-utils": {
@@ -1344,12 +1344,12 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
- "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz",
+ "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==",
"dev": true,
"dependencies": {
- "playwright": "1.42.1"
+ "playwright": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -1420,9 +1420,9 @@
"dev": true
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz",
- "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz",
+ "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==",
"cpu": [
"arm"
],
@@ -1433,9 +1433,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz",
- "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz",
+ "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==",
"cpu": [
"arm64"
],
@@ -1446,9 +1446,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz",
- "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz",
+ "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==",
"cpu": [
"arm64"
],
@@ -1459,9 +1459,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz",
- "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz",
+ "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==",
"cpu": [
"x64"
],
@@ -1472,9 +1472,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz",
- "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz",
+ "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==",
"cpu": [
"arm"
],
@@ -1485,9 +1485,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz",
- "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz",
+ "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==",
"cpu": [
"arm64"
],
@@ -1498,9 +1498,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz",
- "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz",
+ "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==",
"cpu": [
"arm64"
],
@@ -1511,11 +1511,11 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz",
- "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz",
+ "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==",
"cpu": [
- "ppc64le"
+ "ppc64"
],
"dev": true,
"optional": true,
@@ -1524,9 +1524,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz",
- "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz",
+ "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==",
"cpu": [
"riscv64"
],
@@ -1537,9 +1537,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz",
- "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz",
+ "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==",
"cpu": [
"s390x"
],
@@ -1550,9 +1550,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz",
- "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz",
+ "integrity": "sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==",
"cpu": [
"x64"
],
@@ -1563,9 +1563,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz",
- "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.2.tgz",
+ "integrity": "sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==",
"cpu": [
"x64"
],
@@ -1576,9 +1576,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz",
- "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz",
+ "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==",
"cpu": [
"arm64"
],
@@ -1589,9 +1589,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz",
- "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz",
+ "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==",
"cpu": [
"ia32"
],
@@ -1602,9 +1602,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz",
- "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz",
+ "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==",
"cpu": [
"x64"
],
@@ -2217,9 +2217,9 @@
}
},
"node_modules/@types/eslint": {
- "version": "8.56.7",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz",
- "integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==",
+ "version": "8.56.9",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz",
+ "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==",
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -2269,9 +2269,9 @@
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@types/node": {
- "version": "20.12.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
- "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
+ "version": "20.12.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
+ "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dependencies": {
"undici-types": "~5.26.4"
}
@@ -2314,22 +2314,22 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz",
- "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
+ "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
"dev": true,
"dependencies": {
- "@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/type-utils": "7.5.0",
- "@typescript-eslint/utils": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/type-utils": "7.6.0",
+ "@typescript-eslint/utils": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
- "ignore": "^5.2.4",
+ "ignore": "^5.3.1",
"natural-compare": "^1.4.0",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2349,15 +2349,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz",
- "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
+ "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/typescript-estree": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2377,13 +2377,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz",
- "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
+ "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0"
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2394,15 +2394,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz",
- "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
+ "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "7.5.0",
- "@typescript-eslint/utils": "7.5.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "@typescript-eslint/utils": "7.6.0",
"debug": "^4.3.4",
- "ts-api-utils": "^1.0.1"
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2421,9 +2421,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz",
- "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
+ "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
"dev": true,
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2434,19 +2434,19 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz",
- "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
+ "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/visitor-keys": "7.5.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2461,34 +2461,19 @@
}
}
},
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/@typescript-eslint/utils": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz",
- "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
+ "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@types/json-schema": "^7.0.12",
- "@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "7.5.0",
- "@typescript-eslint/types": "7.5.0",
- "@typescript-eslint/typescript-estree": "7.5.0",
- "semver": "^7.5.4"
+ "@types/json-schema": "^7.0.15",
+ "@types/semver": "^7.5.8",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "semver": "^7.6.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2502,13 +2487,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.5.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz",
- "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
+ "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.5.0",
- "eslint-visitor-keys": "^3.4.1"
+ "@typescript-eslint/types": "7.6.0",
+ "eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2538,13 +2523,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
- "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz",
+ "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"chai": "^4.3.10"
},
"funding": {
@@ -2552,12 +2537,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
- "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz",
+ "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.4.0",
+ "@vitest/utils": "1.5.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -2593,9 +2578,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
- "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz",
+ "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -2619,9 +2604,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
- "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz",
+ "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -2631,9 +2616,9 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
- "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz",
+ "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@@ -3566,9 +3551,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001605",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz",
- "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==",
+ "version": "1.0.30001609",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz",
+ "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==",
"funding": [
{
"type": "opencollective",
@@ -3960,9 +3945,9 @@
}
},
"node_modules/css-loader": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.0.0.tgz",
- "integrity": "sha512-WrO4FVoamxt5zY9CauZjoJgXRi/LZKIk+Ta7YvpSGr5r/eMYPNp5/T9ODlMe4/1rF5DYlycG1avhV4g3A/tiAw==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz",
+ "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==",
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.33",
@@ -4812,9 +4797,9 @@
}
},
"node_modules/dompurify": {
- "version": "3.0.11",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.11.tgz",
- "integrity": "sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg=="
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz",
+ "integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA=="
},
"node_modules/domutils": {
"version": "3.1.0",
@@ -4857,9 +4842,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.4.727",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.727.tgz",
- "integrity": "sha512-brpv4KTeC4g0Fx2FeIKytLd4UGn1zBQq5Lauy7zEWT9oqkaj5mgsxblEZIAOf1HHLlXxzr6adGViiBy5Z39/CA=="
+ "version": "1.4.736",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz",
+ "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q=="
},
"node_modules/elkjs": {
"version": "0.9.2",
@@ -4911,9 +4896,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.11.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz",
- "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==",
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz",
+ "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==",
"bin": {
"envinfo": "dist/cli.js"
},
@@ -5689,9 +5674,9 @@
}
},
"node_modules/eslint-plugin-regexp": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.4.0.tgz",
- "integrity": "sha512-OL2S6VPjQhs9s/NclQ0qattVq1J0GU8ox70/HIVy5Dxw+qbbdd7KQkyucsez2clEQjvdtDe12DTnPphFFUyXFg==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.5.0.tgz",
+ "integrity": "sha512-I7vKcP0o75WS5SHiVNXN+Eshq49sbrweMQIuqSL3AId9AwDe9Dhbfug65vw64LxmOd4v+yf5l5Xt41y9puiq0g==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
@@ -5785,9 +5770,9 @@
"dev": true
},
"node_modules/eslint-plugin-vue": {
- "version": "9.24.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz",
- "integrity": "sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw==",
+ "version": "9.24.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz",
+ "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
@@ -5803,7 +5788,7 @@
"node": "^14.17.0 || >=16.0.0"
},
"peerDependencies": {
- "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0"
+ "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/eslint-plugin-vue-scoped-css": {
@@ -5833,9 +5818,9 @@
}
},
"node_modules/eslint-plugin-wc": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.0.4.tgz",
- "integrity": "sha512-ORu7MBv0hXIvq894EJad70m+AvHGbmrDdKT6lcgtCVVhEbuIAyxg0ilfqqqHOmsh8PfcUBeEae3y7CElKvm1KQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.1.0.tgz",
+ "integrity": "sha512-s/BGOtmpgQ2yifR6EC1OM9t0DwYLgg4ZAL07Kw4eXvBb5TYaPafI+65tswvnZvhH8FqcjERLbBZPPvYsvinkfg==",
"dev": true,
"dependencies": {
"is-valid-element-name": "^1.0.0",
@@ -6594,9 +6579,9 @@
}
},
"node_modules/happy-dom": {
- "version": "14.5.0",
- "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.5.0.tgz",
- "integrity": "sha512-KvOtCq7eamc7cjihM0F1wj6FptuXzooc3Typa7Vgu6ns2uKGXC4BIFlK80SdH2w8zcW0gtxpBVI/sUqbYtljDA==",
+ "version": "14.7.1",
+ "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.7.1.tgz",
+ "integrity": "sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==",
"dev": true,
"dependencies": {
"entities": "^4.5.0",
@@ -9381,12 +9366,12 @@
"dev": true
},
"node_modules/playwright": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
- "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
+ "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
"dev": true,
"dependencies": {
- "playwright-core": "1.42.1"
+ "playwright-core": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -9399,9 +9384,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
- "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
+ "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -11241,9 +11226,9 @@
}
},
"node_modules/swagger-ui-dist": {
- "version": "5.13.0",
- "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.13.0.tgz",
- "integrity": "sha512-uaWhh6j18IIs5tOX0arvIBnVINAzpTXaQXkr7qAk8zoupegJVg0UU/5+S/FgsgVCnzVsJ9d7QLjIxkswEeTg0Q=="
+ "version": "5.15.1",
+ "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.15.1.tgz",
+ "integrity": "sha512-Et/WY0NFdKj8sUBOyEx5P3VybsvGl7bo/y9JvgQ22TkH1a/KscQ0ZiQST2YeJ3cwCrIjYTbHbt165fkku0y1Ig=="
},
"node_modules/sync-fetch": {
"version": "0.4.5",
@@ -11379,17 +11364,17 @@
}
},
"node_modules/temporal-polyfill": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.3.tgz",
- "integrity": "sha512-7ZJRc7wq/1XjrOQYkkNpgo2qfE9XLrUU8D/DS+LAC/T0bYqZ46rW6dow0sOTXTPZS4bwer8bD/0OyuKQBfA3yw==",
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.4.tgz",
+ "integrity": "sha512-WA5p0CjQTkMjF9m8sP4wSYgpqI8m2d4q7wPUyaJOWhy4bI9mReLb2yGvTV4qf/DPMTe6H6M/Dig5KmTMB7ev6Q==",
"dependencies": {
- "temporal-spec": "^0.2.0"
+ "temporal-spec": "^0.2.4"
}
},
"node_modules/temporal-spec": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.0.tgz",
- "integrity": "sha512-r1AT0XdEp8TMQ13FLvOt8mOtAxDQsRt2QU5rSWCA7YfshddU651Y1NHVrceLANvixKdf9fYO8B/S9fXHodB7HQ=="
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.4.tgz",
+ "integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ=="
},
"node_modules/terser": {
"version": "5.30.3",
@@ -11749,9 +11734,9 @@
}
},
"node_modules/typescript": {
- "version": "5.4.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz",
- "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==",
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"devOptional": true,
"peer": true,
"bin": {
@@ -11855,9 +11840,9 @@
}
},
"node_modules/updates": {
- "version": "16.0.0",
- "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.0.tgz",
- "integrity": "sha512-Ra3QUu/rfbSCsG83zNNvoRQt0FVT3qULBSALYTlwTDX6oyz7R5GQAYwqJoIG/RDjYAXpwr3usrInoyHHTP6cag==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.1.tgz",
+ "integrity": "sha512-If3NQKzGcA3aVgz2VyOXqQ+4uqYjPUPqh2PeZPtD+OKT4CTmxRYqoyFO+T3nwfccy4SiWy5AabWrBXXhVQ89Aw==",
"dev": true,
"bin": {
"updates": "dist/updates.js"
@@ -12003,9 +11988,9 @@
}
},
"node_modules/vite-node": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
- "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz",
+ "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -12051,9 +12036,9 @@
}
},
"node_modules/vite/node_modules/rollup": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz",
- "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.2.tgz",
+ "integrity": "sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
@@ -12066,35 +12051,35 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.14.0",
- "@rollup/rollup-android-arm64": "4.14.0",
- "@rollup/rollup-darwin-arm64": "4.14.0",
- "@rollup/rollup-darwin-x64": "4.14.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.14.0",
- "@rollup/rollup-linux-arm64-gnu": "4.14.0",
- "@rollup/rollup-linux-arm64-musl": "4.14.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.14.0",
- "@rollup/rollup-linux-s390x-gnu": "4.14.0",
- "@rollup/rollup-linux-x64-gnu": "4.14.0",
- "@rollup/rollup-linux-x64-musl": "4.14.0",
- "@rollup/rollup-win32-arm64-msvc": "4.14.0",
- "@rollup/rollup-win32-ia32-msvc": "4.14.0",
- "@rollup/rollup-win32-x64-msvc": "4.14.0",
+ "@rollup/rollup-android-arm-eabi": "4.14.2",
+ "@rollup/rollup-android-arm64": "4.14.2",
+ "@rollup/rollup-darwin-arm64": "4.14.2",
+ "@rollup/rollup-darwin-x64": "4.14.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.14.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.14.2",
+ "@rollup/rollup-linux-arm64-musl": "4.14.2",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.14.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.14.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.14.2",
+ "@rollup/rollup-linux-x64-gnu": "4.14.2",
+ "@rollup/rollup-linux-x64-musl": "4.14.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.14.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.14.2",
+ "@rollup/rollup-win32-x64-msvc": "4.14.2",
"fsevents": "~2.3.2"
}
},
"node_modules/vitest": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
- "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz",
+ "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.4.0",
- "@vitest/runner": "1.4.0",
- "@vitest/snapshot": "1.4.0",
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/expect": "1.5.0",
+ "@vitest/runner": "1.5.0",
+ "@vitest/snapshot": "1.5.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -12106,9 +12091,9 @@
"std-env": "^3.5.0",
"strip-literal": "^2.0.0",
"tinybench": "^2.5.1",
- "tinypool": "^0.8.2",
+ "tinypool": "^0.8.3",
"vite": "^5.0.0",
- "vite-node": "1.4.0",
+ "vite-node": "1.5.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -12123,8 +12108,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.4.0",
- "@vitest/ui": "1.4.0",
+ "@vitest/browser": "1.5.0",
+ "@vitest/ui": "1.5.0",
"happy-dom": "*",
"jsdom": "*"
},
@@ -12191,9 +12176,9 @@
}
},
"node_modules/vue-chartjs": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.0.tgz",
- "integrity": "sha512-8XqX0JU8vFZ+WA2/knz4z3ThClduni2Nm0BMe2u0mXgTfd9pXrmJ07QBI+WAij5P/aPmPMX54HCE1seWL37ZdQ==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.1.tgz",
+ "integrity": "sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==",
"peerDependencies": {
"chart.js": "^4.1.1",
"vue": "^3.0.0-0 || ^2.7.0"
diff --git a/package.json b/package.json
index f58c3b4d8f22e..ff1ae4d49e6a6 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.0.1",
"clippie": "4.0.7",
- "css-loader": "7.0.0",
+ "css-loader": "7.1.1",
"dayjs": "1.11.10",
"dropzone": "6.0.0-beta.2",
"easymde": "2.18.0",
@@ -43,9 +43,9 @@
"postcss-nesting": "12.1.1",
"pretty-ms": "9.0.0",
"sortablejs": "1.15.2",
- "swagger-ui-dist": "5.13.0",
+ "swagger-ui-dist": "5.15.1",
"tailwindcss": "3.4.3",
- "temporal-polyfill": "0.2.3",
+ "temporal-polyfill": "0.2.4",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@@ -55,7 +55,7 @@
"vanilla-colorful": "0.7.2",
"vue": "3.4.21",
"vue-bar-graph": "2.0.0",
- "vue-chartjs": "5.3.0",
+ "vue-chartjs": "5.3.1",
"vue-loader": "17.4.2",
"vue3-calendar-heatmap": "2.0.5",
"webpack": "5.91.0",
@@ -63,8 +63,8 @@
"wrap-ansi": "9.0.0"
},
"devDependencies": {
- "@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.42.1",
+ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
+ "@playwright/test": "1.43.1",
"@stoplight/spectral-cli": "6.11.1",
"@stylistic/eslint-plugin-js": "1.7.0",
"@stylistic/stylelint-plugin": "2.1.1",
@@ -76,15 +76,15 @@
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.4.0",
+ "eslint-plugin-regexp": "2.5.0",
"eslint-plugin-sonarjs": "0.25.1",
"eslint-plugin-unicorn": "52.0.0",
"eslint-plugin-vitest": "0.4.1",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.24.0",
+ "eslint-plugin-vue": "9.24.1",
"eslint-plugin-vue-scoped-css": "2.8.0",
- "eslint-plugin-wc": "2.0.4",
- "happy-dom": "14.5.0",
+ "eslint-plugin-wc": "2.1.0",
+ "happy-dom": "14.7.1",
"markdownlint-cli": "0.39.0",
"postcss-html": "1.6.0",
"stylelint": "16.3.1",
@@ -92,9 +92,9 @@
"stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0",
- "updates": "16.0.0",
+ "updates": "16.0.1",
"vite-string-plugin": "1.1.5",
- "vitest": "1.4.0"
+ "vitest": "1.5.0"
},
"browserslist": [
"defaults"
diff --git a/poetry.lock b/poetry.lock
index 951a0fa7a885e..1533ddc5ec19c 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -113,13 +113,13 @@ six = ">=1.13.0"
[[package]]
name = "json5"
-version = "0.9.24"
+version = "0.9.25"
description = "A Python implementation of the JSON5 data format."
optional = false
python-versions = ">=3.8"
files = [
- {file = "json5-0.9.24-py3-none-any.whl", hash = "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13"},
- {file = "json5-0.9.24.tar.gz", hash = "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8"},
+ {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"},
+ {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"},
]
[[package]]
diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go
index 3bd80de5c18e3..597372478260d 100644
--- a/routers/api/v1/misc/nodeinfo.go
+++ b/routers/api/v1/misc/nodeinfo.go
@@ -29,9 +29,7 @@ func NodeInfo(ctx *context.APIContext) {
nodeInfoUsage := structs.NodeInfoUsage{}
if setting.Federation.ShareUserStatistics {
- var cached bool
- nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage)
-
+ cached, _ := ctx.Cache.GetJSON(cacheKeyNodeInfoUsage, &nodeInfoUsage)
if !cached {
usersTotal := int(user_model.CountUsers(ctx, nil))
now := time.Now()
@@ -53,7 +51,7 @@ func NodeInfo(ctx *context.APIContext) {
LocalComments: int(allComments),
}
- if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
+ if err := ctx.Cache.PutJSON(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
ctx.InternalServerError(err)
return
}
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 596a370d2e551..d439b11cf926f 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"net/http"
- "net/url"
"strconv"
"strings"
@@ -195,14 +194,15 @@ func NewProjectPost(ctx *context.Context) {
// ChangeProjectStatus updates the status of a project between "open" and "close"
func ChangeProjectStatus(ctx *context.Context) {
- toClose := false
+ var toClose bool
switch ctx.Params(":action") {
case "open":
toClose = false
case "close":
toClose = true
default:
- ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects")
+ ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects")
+ return
}
id := ctx.ParamsInt64(":id")
@@ -210,7 +210,7 @@ func ChangeProjectStatus(ctx *context.Context) {
ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return
}
- ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action")))
+ ctx.JSONRedirect(fmt.Sprintf("%s/-/projects/%d", ctx.ContextUser.HomeLink(), id))
}
// DeleteProject delete a project
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index a2db1fc770a5b..9b765e89e877f 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"net/http"
- "net/url"
"strings"
"code.gitea.io/gitea/models/db"
@@ -181,14 +180,10 @@ func ChangeProjectStatus(ctx *context.Context) {
id := ctx.ParamsInt64(":id")
if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", err)
- } else {
- ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err)
- }
+ ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return
}
- ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action")))
+ ctx.JSONRedirect(fmt.Sprintf("%s/projects/%d", ctx.Repo.RepoLink, id))
}
// DeleteProject delete a project
diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go
index b30dc3b0614f2..4bab3f897a20a 100644
--- a/routers/web/repo/setting/protected_branch.go
+++ b/routers/web/repo/setting/protected_branch.go
@@ -313,7 +313,13 @@ func RenameBranchPost(ctx *context.Context) {
msg, err := repository.RenameBranch(ctx, ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
if err != nil {
- ctx.ServerError("RenameBranch", err)
+ switch {
+ case git_model.IsErrBranchAlreadyExists(err):
+ ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.To))
+ ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ default:
+ ctx.ServerError("RenameBranch", err)
+ }
return
}
diff --git a/services/actions/auth_test.go b/services/actions/auth_test.go
index f73ae8ae4c36a..12db2bae565da 100644
--- a/services/actions/auth_test.go
+++ b/services/actions/auth_test.go
@@ -20,7 +20,7 @@ func TestCreateAuthorizationToken(t *testing.T) {
assert.Nil(t, err)
assert.NotEqual(t, "", token)
claims := jwt.MapClaims{}
- _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
+ _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (any, error) {
return setting.GetGeneralTokenSigningSecret(), nil
})
assert.Nil(t, err)
diff --git a/services/auth/source/oauth2/store.go b/services/auth/source/oauth2/store.go
index 394bf99463594..90fa965602a74 100644
--- a/services/auth/source/oauth2/store.go
+++ b/services/auth/source/oauth2/store.go
@@ -9,6 +9,7 @@ import (
"net/http"
"code.gitea.io/gitea/modules/log"
+ session_module "code.gitea.io/gitea/modules/session"
chiSession "gitea.com/go-chi/session"
"github.com/gorilla/sessions"
@@ -65,7 +66,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s
chiStore := chiSession.GetSession(r)
if session.IsNew {
- _, _ = chiSession.RegenerateSession(w, r)
+ _, _ = session_module.RegenerateSession(w, r)
session.IsNew = false
}
diff --git a/services/context/api.go b/services/context/api.go
index b18a206b5e28a..c684add297d13 100644
--- a/services/context/api.go
+++ b/services/context/api.go
@@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- mc "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
@@ -21,15 +21,13 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
web_types "code.gitea.io/gitea/modules/web/types"
-
- "gitea.com/go-chi/cache"
)
// APIContext is a specific context for API service
type APIContext struct {
*Base
- Cache cache.Cache
+ Cache cache.StringCache
Doer *user_model.User // current signed-in user
IsSigned bool
@@ -217,7 +215,7 @@ func APIContexter() func(http.Handler) http.Handler {
base, baseCleanUp := NewBaseContext(w, req)
ctx := &APIContext{
Base: base,
- Cache: mc.GetCache(),
+ Cache: cache.GetCache(),
Repo: &Repository{PullRequest: &PullRequest{}},
Org: &APIOrganization{},
}
diff --git a/services/context/captcha.go b/services/context/captcha.go
index fa8d779f56550..41afe0e7d25a6 100644
--- a/services/context/captcha.go
+++ b/services/context/captcha.go
@@ -30,7 +30,7 @@ func GetImageCaptcha() *captcha.Captcha {
cpt = captcha.NewCaptcha(captcha.Options{
SubURL: setting.AppSubURL,
})
- cpt.Store = cache.GetCache()
+ cpt.Store = cache.GetCache().ChiCache()
})
return cpt
}
diff --git a/services/context/context.go b/services/context/context.go
index 4b318f7e338ff..7ab48afb73de7 100644
--- a/services/context/context.go
+++ b/services/context/context.go
@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- mc "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/setting"
@@ -27,7 +27,6 @@ import (
"code.gitea.io/gitea/modules/web/middleware"
web_types "code.gitea.io/gitea/modules/web/types"
- "gitea.com/go-chi/cache"
"gitea.com/go-chi/session"
)
@@ -46,7 +45,7 @@ type Context struct {
Render Render
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
- Cache cache.Cache
+ Cache cache.StringCache
Csrf CSRFProtector
Flash *middleware.Flash
Session session.Store
@@ -111,7 +110,7 @@ func NewWebContext(base *Base, render Render, session session.Store) *Context {
Render: render,
Session: session,
- Cache: mc.GetCache(),
+ Cache: cache.GetCache(),
Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
Repo: &Repository{PullRequest: &PullRequest{}},
Org: &Organization{},
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 2a38d4ba55d3a..fa23986c54eae 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -13,6 +13,7 @@ import (
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
+ giturl "code.gitea.io/gitea/modules/git/url"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
@@ -30,10 +31,15 @@ const gitShortEmptySha = "0000000"
// UpdateAddress writes new address to Git repository and database
func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error {
+ u, err := giturl.Parse(addr)
+ if err != nil {
+ return fmt.Errorf("invalid addr: %v", err)
+ }
+
remoteName := m.GetRemoteName()
repoPath := m.GetRepository(ctx).RepoPath()
// Remove old remote
- _, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err = git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@@ -70,7 +76,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
}
}
- m.Repo.OriginalURL = addr
+ // erase authentication before storing in database
+ u.User = nil
+ m.Repo.OriginalURL = u.String()
return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url")
}
@@ -449,19 +457,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return false
}
- var gitRepo *git.Repository
- if len(results) == 0 {
- log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo)
- } else {
- log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
- gitRepo, err = gitrepo.OpenRepository(ctx, m.Repo)
- if err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
- return false
- }
- defer gitRepo.Close()
+ gitRepo, err := gitrepo.OpenRepository(ctx, m.Repo)
+ if err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
+ return false
+ }
+ defer gitRepo.Close()
+ log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
+ if len(results) > 0 {
if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok {
+ log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err)
return false
}
}
@@ -534,16 +540,24 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
}
log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo)
- // Get latest commit date and update to current repository updated time
- commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
+ isEmpty, err := gitRepo.IsEmpty()
if err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
+ log.Error("SyncMirrors [repo: %-v]: unable to check empty git repo: %v", m.Repo, err)
return false
}
+ if !isEmpty {
+ // Get latest commit date and update to current repository updated time
+ commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
+ if err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
+ return false
+ }
+
+ if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
+ return false
+ }
- if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
- return false
}
log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo)
diff --git a/services/repository/branch.go b/services/repository/branch.go
index 229ac54f307d8..d74e5819a1c45 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -26,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
notify_service "code.gitea.io/gitea/services/notify"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -119,17 +120,15 @@ func getDivergenceCacheKey(repoID int64, branchName string) string {
// getDivergenceFromCache gets the divergence from cache
func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) {
- data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName))
+ data, ok := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName))
res := git.DivergeObject{
Ahead: -1,
Behind: -1,
}
- s, ok := data.([]byte)
- if !ok || len(s) == 0 {
+ if !ok || data == "" {
return &res, false
}
-
- if err := json.Unmarshal(s, &res); err != nil {
+ if err := json.Unmarshal(util.UnsafeStringToBytes(data), &res); err != nil {
log.Error("json.UnMarshal failed: %v", err)
return &res, false
}
@@ -141,7 +140,7 @@ func putDivergenceFromCache(repoID int64, branchName string, divergence *git.Div
if err != nil {
return err
}
- return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60)
+ return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), util.UnsafeBytesToString(bs), 30*24*60*60)
}
func DelDivergenceFromCache(repoID int64, branchName string) error {
diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go
index 167a5330ddc49..8a62a603d4609 100644
--- a/services/repository/commitstatus/commitstatus.go
+++ b/services/repository/commitstatus/commitstatus.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/services/automerge"
@@ -26,12 +27,41 @@ func getCacheKey(repoID int64, brancheName string) string {
return fmt.Sprintf("commit_status:%x", hashBytes)
}
-func updateCommitStatusCache(ctx context.Context, repoID int64, branchName string, status api.CommitStatusState) error {
+type commitStatusCacheValue struct {
+ State string `json:"state"`
+ TargetURL string `json:"target_url"`
+}
+
+func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue {
+ c := cache.GetCache()
+ statusStr, ok := c.Get(getCacheKey(repoID, branchName))
+ if ok && statusStr != "" {
+ var cv commitStatusCacheValue
+ err := json.Unmarshal([]byte(statusStr), &cv)
+ if err == nil && cv.State != "" {
+ return &cv
+ }
+ if err != nil {
+ log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err)
+ }
+ }
+ return nil
+}
+
+func updateCommitStatusCache(repoID int64, branchName string, state api.CommitStatusState, targetURL string) error {
c := cache.GetCache()
- return c.Put(getCacheKey(repoID, branchName), string(status), 3*24*60)
+ bs, err := json.Marshal(commitStatusCacheValue{
+ State: state.String(),
+ TargetURL: targetURL,
+ })
+ if err != nil {
+ log.Warn("updateCommitStatusCache: json.Marshal failed: %v", err)
+ return nil
+ }
+ return c.Put(getCacheKey(repoID, branchName), string(bs), 3*24*60)
}
-func deleteCommitStatusCache(ctx context.Context, repoID int64, branchName string) error {
+func deleteCommitStatusCache(repoID int64, branchName string) error {
c := cache.GetCache()
return c.Delete(getCacheKey(repoID, branchName))
}
@@ -81,7 +111,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
}
if commit.ID.String() == defaultBranchCommit.ID.String() { // since one commit status updated, the combined commit status should be invalid
- if err := deleteCommitStatusCache(ctx, repo.ID, repo.DefaultBranch); err != nil {
+ if err := deleteCommitStatusCache(repo.ID, repo.DefaultBranch); err != nil {
log.Error("deleteCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
}
@@ -98,12 +128,12 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
// FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache
func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) {
results := make([]*git_model.CommitStatus, len(repos))
- c := cache.GetCache()
-
for i, repo := range repos {
- status, ok := c.Get(getCacheKey(repo.ID, repo.DefaultBranch)).(string)
- if ok && status != "" {
- results[i] = &git_model.CommitStatus{State: api.CommitStatusState(status)}
+ if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
+ results[i] = &git_model.CommitStatus{
+ State: api.CommitStatusState(cv.State),
+ TargetURL: cv.TargetURL,
+ }
}
}
@@ -139,7 +169,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep
return repoSHA.RepoID == repo.ID
})
if results[i].State != "" {
- if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil {
+ if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
}
@@ -158,7 +188,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep
if results[i] == nil {
results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID])
if results[i].State != "" {
- if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil {
+ if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
}
diff --git a/services/repository/contributors_graph.go b/services/repository/contributors_graph.go
index 7c9f535ae01a6..b0d6de99ca902 100644
--- a/services/repository/contributors_graph.go
+++ b/services/repository/contributors_graph.go
@@ -17,13 +17,12 @@ import (
"code.gitea.io/gitea/models/avatars"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
-
- "gitea.com/go-chi/cache"
)
const (
@@ -79,13 +78,13 @@ func findLastSundayBeforeDate(dateStr string) (string, error) {
}
// GetContributorStats returns contributors stats for git commits for given revision or default branch
-func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) {
+func GetContributorStats(ctx context.Context, cache cache.StringCache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) {
// as GetContributorStats is resource intensive we cache the result
cacheKey := fmt.Sprintf(contributorStatsCacheKey, repo.FullName(), revision)
if !cache.IsExist(cacheKey) {
genReady := make(chan struct{})
- // dont start multible async generations
+ // dont start multiple async generations
_, run := generateLock.Load(cacheKey)
if run {
return nil, ErrAwaitGeneration
@@ -104,15 +103,11 @@ func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_mode
}
}
// TODO: renew timeout of cache cache.UpdateTimeout(cacheKey, contributorStatsCacheTimeout)
-
- switch v := cache.Get(cacheKey).(type) {
- case error:
- return nil, v
- case map[string]*ContributorData:
- return v, nil
- default:
- return nil, fmt.Errorf("unexpected type in cache detected")
+ var res map[string]*ContributorData
+ if _, cacheErr := cache.GetJSON(cacheKey, &res); cacheErr != nil {
+ return nil, fmt.Errorf("cached error: %w", cacheErr.ToError())
}
+ return res, nil
}
// getExtendedCommitStats return the list of *ExtendedCommitStats for the given revision
@@ -205,13 +200,12 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int
return extendedCommitStats, nil
}
-func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey string, repo *repo_model.Repository, revision string) {
+func generateContributorStats(genDone chan struct{}, cache cache.StringCache, cacheKey string, repo *repo_model.Repository, revision string) {
ctx := graceful.GetManager().HammerContext()
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
- err := fmt.Errorf("OpenRepository: %w", err)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("OpenRepository: %w", err), contributorStatsCacheTimeout)
return
}
defer closer.Close()
@@ -221,13 +215,11 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey
}
extendedCommitStats, err := getExtendedCommitStats(gitRepo, revision)
if err != nil {
- err := fmt.Errorf("ExtendedCommitStats: %w", err)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("ExtendedCommitStats: %w", err), contributorStatsCacheTimeout)
return
}
if len(extendedCommitStats) == 0 {
- err := fmt.Errorf("no commit stats returned for revision '%s'", revision)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("no commit stats returned for revision '%s'", revision), contributorStatsCacheTimeout)
return
}
@@ -309,7 +301,7 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey
total.TotalCommits++
}
- _ = cache.Put(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout)
generateLock.Delete(cacheKey)
if genDone != nil {
genDone <- struct{}{}
diff --git a/services/repository/contributors_graph_test.go b/services/repository/contributors_graph_test.go
index 3801a5eee4bfe..f22c115276ee3 100644
--- a/services/repository/contributors_graph_test.go
+++ b/services/repository/contributors_graph_test.go
@@ -10,9 +10,9 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
- "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/setting"
- "gitea.com/go-chi/cache"
"github.com/stretchr/testify/assert"
)
@@ -20,20 +20,18 @@ func TestRepository_ContributorsGraph(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
assert.NoError(t, repo.LoadOwner(db.DefaultContext))
- mockCache, err := cache.NewCacher(cache.Options{
- Adapter: "memory",
- Interval: 24 * 60,
- })
+ mockCache, err := cache.NewStringCache(setting.Cache{})
assert.NoError(t, err)
generateContributorStats(nil, mockCache, "key", repo, "404ref")
- err, isErr := mockCache.Get("key").(error)
- assert.True(t, isErr)
- assert.ErrorAs(t, err, &git.ErrNotExist{})
+ var data map[string]*ContributorData
+ _, getErr := mockCache.GetJSON("key", &data)
+ assert.NotNil(t, getErr)
+ assert.ErrorContains(t, getErr.ToError(), "object does not exist")
generateContributorStats(nil, mockCache, "key2", repo, "master")
- data, isData := mockCache.Get("key2").(map[string]*ContributorData)
- assert.True(t, isData)
+ exist, _ := mockCache.GetJSON("key2", &data)
+ assert.True(t, exist)
var keys []string
for k := range data {
keys = append(keys, k)
diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl
index 5ea003e5ec12d..33d8a2f9632df 100644
--- a/templates/admin/notice.tmpl
+++ b/templates/admin/notice.tmpl
@@ -62,10 +62,7 @@
{{template "admin/layout_footer" .}}
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl
index f65dc6ee90c85..d900d23c4711e 100644
--- a/templates/repo/issue/view_content/comments.tmpl
+++ b/templates/repo/issue/view_content/comments.tmpl
@@ -173,11 +173,11 @@
{{template "shared/user/authorlink" .Poster}}
{{if and .AddedLabels (not .RemovedLabels)}}
- {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) $createdStr}}
+ {{ctx.Locale.TrN (len .AddedLabels) "repo.issues.add_label" "repo.issues.add_labels" (RenderLabels ctx ctx.Locale .AddedLabels $.RepoLink .Issue) $createdStr}}
{{else if and (not .AddedLabels) .RemovedLabels}}
- {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}}
+ {{ctx.Locale.TrN (len .RemovedLabels) "repo.issues.remove_label" "repo.issues.remove_labels" (RenderLabels ctx ctx.Locale .RemovedLabels $.RepoLink .Issue) $createdStr}}
{{else}}
- {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels $.Context ctx.Locale .AddedLabels $.RepoLink) (RenderLabels $.Context ctx.Locale .RemovedLabels $.RepoLink) $createdStr}}
+ {{ctx.Locale.Tr "repo.issues.add_remove_labels" (RenderLabels ctx ctx.Locale .AddedLabels $.RepoLink .Issue) (RenderLabels ctx ctx.Locale .RemovedLabels $.RepoLink .Issue) $createdStr}}
{{end}}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index b8fa4759b1326..df6ccbf6bc2fb 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -156,7 +156,7 @@
- {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}}
+ {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName}}
diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go
index 703fc243a4d3e..13f6cf204b539 100644
--- a/tests/integration/rename_branch_test.go
+++ b/tests/integration/rename_branch_test.go
@@ -5,17 +5,23 @@ package integration
import (
"net/http"
+ "net/url"
"testing"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
+ gitea_context "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestRenameBranch(t *testing.T) {
+ onGiteaRun(t, testRenameBranch)
+}
+
+func testRenameBranch(t *testing.T, u *url.URL) {
defer tests.PrepareTestEnv(t)()
unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: 1, Name: "master"})
@@ -26,20 +32,19 @@ func TestRenameBranch(t *testing.T) {
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
- postData := map[string]string{
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
"_csrf": htmlDoc.GetCSRF(),
"from": "master",
"to": "main",
- }
- req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", postData)
+ })
session.MakeRequest(t, req, http.StatusSeeOther)
// check new branch link
- req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/main/README.md", postData)
+ req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/main/README.md", nil)
session.MakeRequest(t, req, http.StatusOK)
// check old branch link
- req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/master/README.md", postData)
+ req = NewRequestWithValues(t, "GET", "/user2/repo1/src/branch/master/README.md", nil)
resp = session.MakeRequest(t, req, http.StatusSeeOther)
location := resp.Header().Get("Location")
assert.Equal(t, "/user2/repo1/src/branch/main/README.md", location)
@@ -47,4 +52,69 @@ func TestRenameBranch(t *testing.T) {
// check db
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
assert.Equal(t, "main", repo1.DefaultBranch)
+
+ // create branch1
+ csrf := GetCSRF(t, session, "/user2/repo1/src/branch/main")
+
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/main", map[string]string{
+ "_csrf": csrf,
+ "new_branch_name": "branch1",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ branch1 := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"})
+ assert.Equal(t, "branch1", branch1.Name)
+
+ // create branch2
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/main", map[string]string{
+ "_csrf": csrf,
+ "new_branch_name": "branch2",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ branch2 := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
+ assert.Equal(t, "branch2", branch2.Name)
+
+ // rename branch2 to branch1
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "from": "branch2",
+ "to": "branch1",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+ flashCookie := session.GetCookie(gitea_context.CookieNameFlash)
+ assert.NotNil(t, flashCookie)
+ assert.Contains(t, flashCookie.Value, "error")
+
+ branch2 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
+ assert.Equal(t, "branch2", branch2.Name)
+ branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"})
+ assert.Equal(t, "branch1", branch1.Name)
+
+ // delete branch1
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/delete", map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "name": "branch1",
+ })
+ session.MakeRequest(t, req, http.StatusOK)
+ branch2 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
+ assert.Equal(t, "branch2", branch2.Name)
+ branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"})
+ assert.True(t, branch1.IsDeleted) // virtual deletion
+
+ // rename branch2 to branch1 again
+ req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/rename_branch", map[string]string{
+ "_csrf": htmlDoc.GetCSRF(),
+ "from": "branch2",
+ "to": "branch1",
+ })
+ session.MakeRequest(t, req, http.StatusSeeOther)
+
+ flashCookie = session.GetCookie(gitea_context.CookieNameFlash)
+ assert.NotNil(t, flashCookie)
+ assert.Contains(t, flashCookie.Value, "success")
+
+ unittest.AssertNotExistsBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch2"})
+ branch1 = unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo1.ID, Name: "branch1"})
+ assert.Equal(t, "branch1", branch1.Name)
}
diff --git a/updates.config.js b/updates.config.js
index 11908dea8e5b5..bd072fe6cbdab 100644
--- a/updates.config.js
+++ b/updates.config.js
@@ -1,6 +1,8 @@
export default {
exclude: [
'@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled
+ 'eslint', // need to migrate to eslint flat config first
'eslint-plugin-array-func', // need to migrate to eslint flat config first
+ 'eslint-plugin-vitest', // need to migrate to eslint flat config first
],
};
diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js
index f388b1122ec5e..b35502d52f9fa 100644
--- a/web_src/js/features/admin/common.js
+++ b/web_src/js/features/admin/common.js
@@ -207,13 +207,13 @@ export function initAdminCommon() {
// Notice
if (document.querySelector('.admin.notice')) {
- const $detailModal = document.getElementById('detail-modal');
+ const detailModal = document.getElementById('detail-modal');
// Attach view detail modals
$('.view-detail').on('click', function () {
- $detailModal.find('.content pre').text($(this).parents('tr').find('.notice-description').text());
- $detailModal.find('.sub.header').text(this.closest('tr')?.querySelector('relative-time')?.getAttribute('title'));
- $detailModal.modal('show');
+ const description = this.closest('tr').querySelector('.notice-description').textContent;
+ detailModal.querySelector('.content pre').textContent = description;
+ $(detailModal).modal('show');
return false;
});
diff --git a/web_src/js/features/repo-graph.js b/web_src/js/features/repo-graph.js
index a5b61bff54d9d..0086b92021bd8 100644
--- a/web_src/js/features/repo-graph.js
+++ b/web_src/js/features/repo-graph.js
@@ -1,14 +1,16 @@
import $ from 'jquery';
+import {hideElem, showElem} from '../utils/dom.js';
import {GET} from '../modules/fetch.js';
export function initRepoGraphGit() {
const graphContainer = document.getElementById('git-graph-container');
if (!graphContainer) return;
- $('#flow-color-monochrome').on('click', () => {
- $('#flow-color-monochrome').addClass('active');
- $('#flow-color-colored').removeClass('active');
- $('#git-graph-container').removeClass('colored').addClass('monochrome');
+ document.getElementById('flow-color-monochrome')?.addEventListener('click', () => {
+ document.getElementById('flow-color-monochrome').classList.add('active');
+ document.getElementById('flow-color-colored')?.classList.remove('active');
+ graphContainer.classList.remove('colored');
+ graphContainer.classList.add('monochrome');
const params = new URLSearchParams(window.location.search);
params.set('mode', 'monochrome');
const queryString = params.toString();
@@ -17,29 +19,31 @@ export function initRepoGraphGit() {
} else {
window.history.replaceState({}, '', window.location.pathname);
}
- $('.pagination a').each((_, that) => {
- const href = that.getAttribute('href');
- if (!href) return;
+ for (const link of document.querySelectorAll('.pagination a')) {
+ const href = link.getAttribute('href');
+ if (!href) continue;
const url = new URL(href, window.location);
const params = url.searchParams;
params.set('mode', 'monochrome');
url.search = `?${params.toString()}`;
- that.setAttribute('href', url.href);
- });
+ link.setAttribute('href', url.href);
+ }
});
- $('#flow-color-colored').on('click', () => {
- $('#flow-color-colored').addClass('active');
- $('#flow-color-monochrome').removeClass('active');
- $('#git-graph-container').addClass('colored').removeClass('monochrome');
- $('.pagination a').each((_, that) => {
- const href = that.getAttribute('href');
- if (!href) return;
+
+ document.getElementById('flow-color-colored')?.addEventListener('click', () => {
+ document.getElementById('flow-color-colored').classList.add('active');
+ document.getElementById('flow-color-monochrome')?.classList.remove('active');
+ graphContainer.classList.add('colored');
+ graphContainer.classList.remove('monochrome');
+ for (const link of document.querySelectorAll('.pagination a')) {
+ const href = link.getAttribute('href');
+ if (!href) continue;
const url = new URL(href, window.location);
const params = url.searchParams;
params.delete('mode');
url.search = `?${params.toString()}`;
- that.setAttribute('href', url.href);
- });
+ link.setAttribute('href', url.href);
+ }
const params = new URLSearchParams(window.location.search);
params.delete('mode');
const queryString = params.toString();
@@ -56,20 +60,21 @@ export function initRepoGraphGit() {
const ajaxUrl = new URL(url);
ajaxUrl.searchParams.set('div-only', 'true');
window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname);
- $('#pagination').empty();
- $('#rel-container').addClass('tw-hidden');
- $('#rev-container').addClass('tw-hidden');
- $('#loading-indicator').removeClass('tw-hidden');
+ document.getElementById('pagination').innerHTML = '';
+ hideElem('#rel-container');
+ hideElem('#rev-container');
+ showElem('#loading-indicator');
(async () => {
const response = await GET(String(ajaxUrl));
const html = await response.text();
- const $div = $(html);
- $('#pagination').html($div.find('#pagination').html());
- $('#rel-container').html($div.find('#rel-container').html());
- $('#rev-container').html($div.find('#rev-container').html());
- $('#loading-indicator').addClass('tw-hidden');
- $('#rel-container').removeClass('tw-hidden');
- $('#rev-container').removeClass('tw-hidden');
+ const div = document.createElement('div');
+ div.innerHTML = html;
+ document.getElementById('pagination').innerHTML = div.getElementById('pagination').innerHTML;
+ document.getElementById('rel-container').innerHTML = div.getElementById('rel-container').innerHTML;
+ document.getElementById('rev-container').innerHTML = div.getElementById('rev-container').innerHTML;
+ hideElem('#loading-indicator');
+ showElem('#rel-container');
+ showElem('#rev-container');
})();
};
const dropdownSelected = params.getAll('branch');
@@ -77,8 +82,9 @@ export function initRepoGraphGit() {
dropdownSelected.splice(0, 0, '...flow-hide-pr-refs');
}
- $('#flow-select-refs-dropdown').dropdown('set selected', dropdownSelected);
- $('#flow-select-refs-dropdown').dropdown({
+ const flowSelectRefsDropdown = document.getElementById('flow-select-refs-dropdown');
+ $(flowSelectRefsDropdown).dropdown('set selected', dropdownSelected);
+ $(flowSelectRefsDropdown).dropdown({
clearable: true,
fullTextSeach: 'exact',
onRemove(toRemove) {
@@ -104,36 +110,46 @@ export function initRepoGraphGit() {
updateGraph();
},
});
- $('#git-graph-container').on('mouseenter', '#rev-list li', (e) => {
- const flow = $(e.currentTarget).data('flow');
- if (flow === 0) return;
- $(`#flow-${flow}`).addClass('highlight');
- $(e.currentTarget).addClass('hover');
- $(`#rev-list li[data-flow='${flow}']`).addClass('highlight');
- });
- $('#git-graph-container').on('mouseleave', '#rev-list li', (e) => {
- const flow = $(e.currentTarget).data('flow');
- if (flow === 0) return;
- $(`#flow-${flow}`).removeClass('highlight');
- $(e.currentTarget).removeClass('hover');
- $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight');
- });
- $('#git-graph-container').on('mouseenter', '#rel-container .flow-group', (e) => {
- $(e.currentTarget).addClass('highlight');
- const flow = $(e.currentTarget).data('flow');
- $(`#rev-list li[data-flow='${flow}']`).addClass('highlight');
- });
- $('#git-graph-container').on('mouseleave', '#rel-container .flow-group', (e) => {
- $(e.currentTarget).removeClass('highlight');
- const flow = $(e.currentTarget).data('flow');
- $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight');
- });
- $('#git-graph-container').on('mouseenter', '#rel-container .flow-commit', (e) => {
- const rev = $(e.currentTarget).data('rev');
- $(`#rev-list li#commit-${rev}`).addClass('hover');
+
+ graphContainer.addEventListener('mouseenter', (e) => {
+ if (e.target.matches('#rev-list li')) {
+ const flow = e.target.getAttribute('data-flow');
+ if (flow === '0') return;
+ document.getElementById(`flow-${flow}`)?.classList.add('highlight');
+ e.target.classList.add('hover');
+ for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
+ item.classList.add('highlight');
+ }
+ } else if (e.target.matches('#rel-container .flow-group')) {
+ e.target.classList.add('highlight');
+ const flow = e.target.getAttribute('data-flow');
+ for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
+ item.classList.add('highlight');
+ }
+ } else if (e.target.matches('#rel-container .flow-commit')) {
+ const rev = e.target.getAttribute('data-rev');
+ document.querySelector(`#rev-list li#commit-${rev}`)?.classList.add('hover');
+ }
});
- $('#git-graph-container').on('mouseleave', '#rel-container .flow-commit', (e) => {
- const rev = $(e.currentTarget).data('rev');
- $(`#rev-list li#commit-${rev}`).removeClass('hover');
+
+ graphContainer.addEventListener('mouseleave', (e) => {
+ if (e.target.matches('#rev-list li')) {
+ const flow = e.target.getAttribute('data-flow');
+ if (flow === '0') return;
+ document.getElementById(`flow-${flow}`)?.classList.remove('highlight');
+ e.target.classList.remove('hover');
+ for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
+ item.classList.remove('highlight');
+ }
+ } else if (e.target.matches('#rel-container .flow-group')) {
+ e.target.classList.remove('highlight');
+ const flow = e.target.getAttribute('data-flow');
+ for (const item of document.querySelectorAll(`#rev-list li[data-flow='${flow}']`)) {
+ item.classList.remove('highlight');
+ }
+ } else if (e.target.matches('#rel-container .flow-commit')) {
+ const rev = e.target.getAttribute('data-rev');
+ document.querySelector(`#rev-list li#commit-${rev}`)?.classList.remove('hover');
+ }
});
}
diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js
index 0d326aae581fd..2b2eed58bbfb3 100644
--- a/web_src/js/features/repo-issue.js
+++ b/web_src/js/features/repo-issue.js
@@ -449,12 +449,10 @@ export function initRepoPullRequestReview() {
offset += $('.diff-detail-box').outerHeight() + $(diffHeader).outerHeight();
}
- document.getElementById(`show-outdated-${id}`).classList.add('tw-hidden');
- document.getElementById(`code-comments-${id}`).classList.remove('tw-hidden');
- document.getElementById(`code-preview-${id}`).classList.remove('tw-hidden');
- document.getElementById(`hide-outdated-${id}`).classList.remove('tw-hidden');
+ hideElem(`#show-outdated-${id}`);
+ showElem(`#code-comments-${id}, #code-preview-${id}, #hide-outdated-${id}`);
// if the comment box is folded, expand it
- if (ancestorDiffBox.getAttribute('data-folded') === 'true') {
+ if (ancestorDiffBox?.getAttribute('data-folded') === 'true') {
setFileFolding(ancestorDiffBox, ancestorDiffBox.querySelector('.fold-file'), false);
}