@@ -318,7 +318,7 @@ rules: | |||
jquery/no-serialize: [2] | |||
jquery/no-show: [2] | |||
jquery/no-size: [2] | |||
jquery/no-sizzle: [0] | |||
jquery/no-sizzle: [2] | |||
jquery/no-slide: [0] | |||
jquery/no-submit: [0] | |||
jquery/no-text: [0] | |||
@@ -470,7 +470,7 @@ rules: | |||
no-jquery/no-selector-prop: [2] | |||
no-jquery/no-serialize: [2] | |||
no-jquery/no-size: [2] | |||
no-jquery/no-sizzle: [0] | |||
no-jquery/no-sizzle: [2] | |||
no-jquery/no-slide: [2] | |||
no-jquery/no-sub: [2] | |||
no-jquery/no-support: [2] |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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) | |||
} |
@@ -36,6 +36,7 @@ var microcmdUserChangePassword = &cli.Command{ | |||
&cli.BoolFlag{ | |||
Name: "must-change-password", | |||
Usage: "User must change password", | |||
Value: true, | |||
}, | |||
}, | |||
} | |||
@@ -57,23 +58,18 @@ func runChangePassword(c *cli.Context) error { | |||
return err | |||
} | |||
var mustChangePassword optional.Option[bool] | |||
if c.IsSet("must-change-password") { | |||
mustChangePassword = optional.Some(c.Bool("must-change-password")) | |||
} | |||
opts := &user_service.UpdateAuthOptions{ | |||
Password: optional.Some(c.String("password")), | |||
MustChangePassword: mustChangePassword, | |||
MustChangePassword: optional.Some(c.Bool("must-change-password")), | |||
} | |||
if err := user_service.UpdateAuth(ctx, user, opts); err != nil { | |||
switch { | |||
case errors.Is(err, password.ErrMinLength): | |||
return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength) | |||
return fmt.Errorf("password is not long enough, needs to be at least %d characters", setting.MinPasswordLength) | |||
case errors.Is(err, password.ErrComplexity): | |||
return errors.New("Password does not meet complexity requirements") | |||
return errors.New("password does not meet complexity requirements") | |||
case errors.Is(err, password.ErrIsPwned): | |||
return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords") | |||
return errors.New("the password is in a list of stolen passwords previously exposed in public data breaches, please try again with a different password, to see more details: https://haveibeenpwned.com/Passwords") | |||
default: | |||
return err | |||
} |
@@ -8,6 +8,7 @@ import ( | |||
"fmt" | |||
auth_model "code.gitea.io/gitea/models/auth" | |||
"code.gitea.io/gitea/models/db" | |||
user_model "code.gitea.io/gitea/models/user" | |||
pwd "code.gitea.io/gitea/modules/auth/password" | |||
"code.gitea.io/gitea/modules/optional" | |||
@@ -46,8 +47,9 @@ var microcmdUserCreate = &cli.Command{ | |||
Usage: "Generate a random password for the user", | |||
}, | |||
&cli.BoolFlag{ | |||
Name: "must-change-password", | |||
Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)", | |||
Name: "must-change-password", | |||
Usage: "Set to false to prevent forcing the user to change their password after initial login", | |||
DisableDefaultText: true, | |||
}, | |||
&cli.IntFlag{ | |||
Name: "random-password-length", | |||
@@ -71,10 +73,10 @@ func runCreateUser(c *cli.Context) error { | |||
} | |||
if c.IsSet("name") && c.IsSet("username") { | |||
return errors.New("Cannot set both --name and --username flags") | |||
return errors.New("cannot set both --name and --username flags") | |||
} | |||
if !c.IsSet("name") && !c.IsSet("username") { | |||
return errors.New("One of --name or --username flags must be set") | |||
return errors.New("one of --name or --username flags must be set") | |||
} | |||
if c.IsSet("password") && c.IsSet("random-password") { | |||
@@ -110,17 +112,21 @@ func runCreateUser(c *cli.Context) error { | |||
return errors.New("must set either password or random-password flag") | |||
} | |||
// always default to true | |||
changePassword := true | |||
// If this is the first user being created. | |||
// Take it as the admin and don't force a password update. | |||
if n := user_model.CountUsers(ctx, nil); n == 0 { | |||
changePassword = false | |||
} | |||
isAdmin := c.Bool("admin") | |||
mustChangePassword := true // always default to true | |||
if c.IsSet("must-change-password") { | |||
changePassword = c.Bool("must-change-password") | |||
// if the flag is set, use the value provided by the user | |||
mustChangePassword = c.Bool("must-change-password") | |||
} else { | |||
// check whether there are users in the database | |||
hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{}) | |||
if err != nil { | |||
return fmt.Errorf("IsTableNotEmpty: %w", err) | |||
} | |||
if !hasUserRecord && isAdmin { | |||
// if this is the first admin being created, don't force to change password (keep the old behavior) | |||
mustChangePassword = false | |||
} | |||
} | |||
restricted := optional.None[bool]() | |||
@@ -136,8 +142,8 @@ func runCreateUser(c *cli.Context) error { | |||
Name: username, | |||
Email: c.String("email"), | |||
Passwd: password, | |||
IsAdmin: c.Bool("admin"), | |||
MustChangePassword: changePassword, | |||
IsAdmin: isAdmin, | |||
MustChangePassword: mustChangePassword, | |||
Visibility: visibility, | |||
} | |||
@@ -83,8 +83,7 @@ Admin operations: | |||
- `--email value`: Email. Required. | |||
- `--admin`: If provided, this makes the user an admin. Optional. | |||
- `--access-token`: If provided, an access token will be created for the user. Optional. (default: false). | |||
- `--must-change-password`: If provided, the created user will be required to choose a newer password after the | |||
initial login. Optional. (default: true). | |||
- `--must-change-password`: The created user will be required to set a new password after the initial login, default: true. It could be disabled by `--must-change-password=false`. | |||
- `--random-password`: If provided, a randomly generated password will be used as the password of the created | |||
user. The value of `--password` will be discarded. Optional. | |||
- `--random-password-length`: If provided, it will be used to configure the length of the randomly generated | |||
@@ -95,7 +94,7 @@ Admin operations: | |||
- Options: | |||
- `--username value`, `-u value`: Username. Required. | |||
- `--password value`, `-p value`: New password. Required. | |||
- `--must-change-password`: If provided, the user is required to choose a new password after the login. Optional. | |||
- `--must-change-password`: The user is required to set a new password after the login, default: true. It could be disabled by `--must-change-password=false`. | |||
- Examples: | |||
- `gitea admin user change-password --username myname --password asecurepassword` | |||
- `must-change-password`: |
@@ -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 { |
@@ -284,8 +284,8 @@ func MaxBatchInsertSize(bean any) int { | |||
} | |||
// IsTableNotEmpty returns true if table has at least one record | |||
func IsTableNotEmpty(tableName string) (bool, error) { | |||
return x.Table(tableName).Exist() | |||
func IsTableNotEmpty(beanOrTableName any) (bool, error) { | |||
return x.Table(beanOrTableName).Exist() | |||
} | |||
// DeleteAllRecords will delete all the records of this table |
@@ -15,10 +15,11 @@ import ( | |||
// CommitStatusSummary holds the latest commit Status of a single Commit | |||
type CommitStatusSummary struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` | |||
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` | |||
State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` | |||
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` | |||
State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` | |||
TargetURL string `xorm:"TEXT"` | |||
} | |||
func init() { | |||
@@ -44,9 +45,10 @@ func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA | |||
commitStatuses := make([]*CommitStatus, 0, len(repoSHAs)) | |||
for _, summary := range summaries { | |||
commitStatuses = append(commitStatuses, &CommitStatus{ | |||
RepoID: summary.RepoID, | |||
SHA: summary.SHA, | |||
State: summary.State, | |||
RepoID: summary.RepoID, | |||
SHA: summary.SHA, | |||
State: summary.State, | |||
TargetURL: summary.TargetURL, | |||
}) | |||
} | |||
return commitStatuses, nil | |||
@@ -61,22 +63,24 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er | |||
// mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, | |||
// so we need to use insert in on duplicate | |||
if setting.Database.Type.IsMySQL() { | |||
_, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state) VALUES (?,?,?) ON DUPLICATE KEY UPDATE state=?", | |||
repoID, sha, state.State, state.State) | |||
_, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state,target_url) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?", | |||
repoID, sha, state.State, state.TargetURL, state.State) | |||
return err | |||
} | |||
if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha). | |||
Cols("state"). | |||
Cols("state, target_url"). | |||
Update(&CommitStatusSummary{ | |||
State: state.State, | |||
State: state.State, | |||
TargetURL: state.TargetURL, | |||
}); err != nil { | |||
return err | |||
} else if cnt == 0 { | |||
_, err = db.GetEngine(ctx).Insert(&CommitStatusSummary{ | |||
RepoID: repoID, | |||
SHA: sha, | |||
State: state.State, | |||
RepoID: repoID, | |||
SHA: sha, | |||
State: state.State, | |||
TargetURL: state.TargetURL, | |||
}) | |||
return err | |||
} |
@@ -580,6 +580,8 @@ var migrations = []Migration{ | |||
NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue), | |||
// v295 -> v296 | |||
NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary), | |||
// v296 -> v297 | |||
NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2), | |||
} | |||
// GetCurrentDBVersion returns the current db version |
@@ -0,0 +1,16 @@ | |||
// Copyright 2024 The Gitea Authors. All rights reserved. | |||
// SPDX-License-Identifier: MIT | |||
package v1_23 //nolint | |||
import "xorm.io/xorm" | |||
func AddCommitStatusSummary2(x *xorm.Engine) error { | |||
type CommitStatusSummary struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
TargetURL string `xorm:"TEXT"` | |||
} | |||
// there is no migrations because if there is no data on this table, it will fall back to get data | |||
// from commit status | |||
return x.Sync(new(CommitStatusSummary)) | |||
} |
@@ -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) | |||
} |
@@ -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" | |||
) | |||
@@ -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() | |||
@@ -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" | |||
) | |||
@@ -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 = "<CACHED-ERROR>:" | |||
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 | |||
} |
@@ -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 | |||
} |
@@ -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 | |||
} |
@@ -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 | |||
} |
@@ -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 { |
@@ -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 := `<span class="labels-list">` | |||
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("<a href='%s/issues?labels=%d'>%s</a> ", | |||
repoLink, label.ID, RenderLabel(ctx, locale, label)) | |||
htmlCode += fmt.Sprintf(`<a href="%s?labels=%d">%s</a>`, baseLink, label.ID, RenderLabel(ctx, locale, label)) | |||
} | |||
htmlCode += "</span>" | |||
return template.HTML(htmlCode) |
@@ -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<SPACE><SPACE> | |||
/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<SPACE><SPACE> | |||
` | |||
return strings.ReplaceAll(s, "<SPACE>", " ") | |||
} | |||
var testMetas = map[string]string{ | |||
"user": "user13", | |||
@@ -121,23 +127,23 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | |||
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a> | |||
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 <a href="/mention-user" class="mention">@mention-user</a> ` | |||
assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) | |||
assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput(), testMetas)) | |||
} | |||
func TestRenderCommitMessageLinkSubject(t *testing.T) { | |||
expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="/mention-user" class="mention">@mention-user</a>` | |||
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<SPACE><SPACE> | |||
/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 | |||
<a href="/user13/repo11/issues/123" class="ref-issue">#123</a> | |||
space | |||
space<SPACE><SPACE> | |||
` | |||
assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas)) | |||
expected = strings.ReplaceAll(expected, "<SPACE>", " ") | |||
assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput(), testMetas)) | |||
} | |||
func TestRenderMarkdownToHtml(t *testing.T) { | |||
@@ -183,5 +190,20 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | |||
#123 | |||
space</p> | |||
` | |||
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) | |||
} |
@@ -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()) | |||
} |
@@ -0,0 +1,27 @@ | |||
Copyright (C) 2006,2007,2009 NTT (Nippon Telegraph and Telephone | |||
Corporation). All rights reserved. | |||
Redistribution and use in source and binary forms, with or without | |||
modification, are permitted provided that the following conditions | |||
are met: | |||
1. Redistributions of source code must retain the above | |||
copyright notice, this list of conditions and the following | |||
disclaimer as the first lines of this file unmodified. | |||
2. Redistributions in binary form must reproduce the above | |||
copyright notice, this list of conditions and the following | |||
disclaimer in the documentation and/or other materials provided | |||
with the distribution. | |||
THIS SOFTWARE IS PROVIDED BY NTT "AS IS" AND ANY EXPRESS OR IMPLIED | |||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
DISCLAIMED. IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT, | |||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
OF THE POSSIBILITY OF SUCH DAMAGE. |
@@ -0,0 +1,13 @@ | |||
Copyright (c) 2000 by Sun Microsystems, Inc. | |||
All rights reserved. | |||
Permission to use, copy, modify, and distribute this software and its | |||
documentation is hereby granted, provided that the above copyright | |||
notice appears in all copies. | |||
SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF | |||
THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |||
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |||
PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR | |||
ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |||
DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES |
@@ -0,0 +1,7 @@ | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
This software is provided 'as is' and without any warranty, express or | |||
implied. In no event shall the authors be liable for any damages arising | |||
from the use of this software. |
@@ -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" |
@@ -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" |
@@ -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]] |
@@ -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 | |||
} |
@@ -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 |
@@ -3318,7 +3318,6 @@ func ChangeIssueReaction(ctx *context.Context) { | |||
} | |||
html, err := ctx.RenderToHTML(tplReactions, map[string]any{ | |||
"ctxData": ctx.Data, | |||
"ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index), | |||
"Reactions": issue.Reactions.GroupByType(), | |||
}) | |||
@@ -3425,7 +3424,6 @@ func ChangeCommentReaction(ctx *context.Context) { | |||
} | |||
html, err := ctx.RenderToHTML(tplReactions, map[string]any{ | |||
"ctxData": ctx.Data, | |||
"ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID), | |||
"Reactions": comment.Reactions.GroupByType(), | |||
}) |
@@ -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 |
@@ -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) |
@@ -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 | |||
} | |||
@@ -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{}, | |||
} |
@@ -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 | |||
} |
@@ -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 | |||
@@ -102,6 +101,7 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext { | |||
tmplCtx := NewTemplateContext(ctx) | |||
tmplCtx["Locale"] = ctx.Base.Locale | |||
tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) | |||
tmplCtx["RootData"] = ctx.Data | |||
return tmplCtx | |||
} | |||
@@ -111,7 +111,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{}, |
@@ -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") | |||
} | |||
@@ -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 { |
@@ -34,7 +34,7 @@ type commitStatusCacheValue struct { | |||
func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue { | |||
c := cache.GetCache() | |||
statusStr, ok := c.Get(getCacheKey(repoID, branchName)).(string) | |||
statusStr, ok := c.Get(getCacheKey(repoID, branchName)) | |||
if ok && statusStr != "" { | |||
var cv commitStatusCacheValue | |||
err := json.Unmarshal([]byte(statusStr), &cv) |
@@ -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{}{} |
@@ -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) |
@@ -49,7 +49,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<button class="ui small teal button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}"> | |||
<button class="ui small button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="?page={{.Page.Paginater.Current}}"> | |||
<span class="text">{{ctx.Locale.Tr "admin.notices.delete_selected"}}</span> | |||
</button> | |||
</th> |
@@ -54,7 +54,7 @@ | |||
<input type="hidden" name="action" value="delete"> | |||
<input type="hidden" name="q" value="{{$.Keyword}}"> | |||
<input type="hidden" name="page" value="{{$.CurrentPage}}"> | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} | |||
{{template "base/modal_actions_confirm"}} | |||
</form> | |||
</div> | |||
</div> |
@@ -1,7 +1,6 @@ | |||
{{/* | |||
Two buttons (negative, positive): | |||
* ModalButtonTypes: "yes" (default) or "confirm" | |||
* ModalButtonColors: "primary" (default) / "blue" / "yellow" | |||
* ModalButtonCancelText | |||
* ModalButtonOkText | |||
@@ -22,14 +21,7 @@ The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal | |||
{{end}} | |||
{{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}} | |||
{{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}} | |||
{{$stylePositive := "primary"}} | |||
{{if eq .ModalButtonColors "blue"}} | |||
{{$stylePositive = "blue"}} | |||
{{else if eq .ModalButtonColors "yellow"}} | |||
{{$stylePositive = "yellow"}} | |||
{{end}} | |||
<button class="ui cancel button">{{svg "octicon-x"}} {{$textNegitive}}</button> | |||
<button class="ui {{$stylePositive}} ok button">{{svg "octicon-check"}} {{$textPositive}}</button> | |||
<button class="ui primary ok button">{{svg "octicon-check"}} {{$textPositive}}</button> | |||
{{end}} | |||
</div> |
@@ -1,6 +1,15 @@ | |||
{{template "base/head" .}} | |||
<div class="page-content devtest ui container"> | |||
{{template "base/alert" .}} | |||
<div class="modal-buttons flex-text-block tw-flex-wrap"></div> | |||
<script type="module"> | |||
for (const el of $('.ui.modal')) { | |||
const $btn = $('<button class="ui button">').text(`${el.id}`).on('click', () => { | |||
$(el).modal({onApprove() {alert('confirmed')}}).modal('show'); | |||
}); | |||
$('.modal-buttons').append($btn); | |||
} | |||
</script> | |||
<div id="test-modal-form-1" class="ui mini modal"> | |||
<div class="header">Form dialog (layout 1)</div> | |||
@@ -54,33 +63,11 @@ | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}} | |||
</div> | |||
<div class="ui g-modal-confirm modal" id="test-modal-blue"> | |||
<div class="header">Blue dialog</div> | |||
<div class="content">hello, this is the modal dialog content</div> | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonColors" "blue")}} | |||
</div> | |||
<div class="ui g-modal-confirm modal" id="test-modal-yellow"> | |||
<div class="header">yellow dialog</div> | |||
<div class="content">hello, this is the modal dialog content</div> | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} | |||
</div> | |||
<div class="ui g-modal-confirm modal" id="test-modal-danger"> | |||
{{svg "octicon-x" 16 "inside close"}} | |||
<div class="header">dangerous action dialog</div> | |||
<div class="content">hello, this is the modal dialog content, this is a dangerous operation</div> | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do this is dangerous operation")}} | |||
</div> | |||
<div class="modal-buttons flex-text-block tw-flex-wrap"></div> | |||
<script type="module"> | |||
for (const el of $('.ui.modal')) { | |||
const $btn = $('<button>').text(`${el.id}`).on('click', () => { | |||
$(el).modal({onApprove() {alert('confirmed')}}).modal('show'); | |||
}); | |||
$('.modal-buttons').append($btn); | |||
} | |||
</script> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -29,41 +29,13 @@ | |||
<button class="ui basic button">Basic Unclassed</button> | |||
<button class="ui primary button">Primary</button> | |||
<button class="ui basic primary button">Basic Primary</button> | |||
<button class="ui negative button">Negative</button> | |||
<button class="ui basic negative button">Basic Negative</button> | |||
<button class="ui positive button">Positive</button> | |||
<button class="ui basic positive button">Basic Positive</button> | |||
</li> | |||
<li class="sample-group"> | |||
<h2>Recommended colors:</h2> | |||
<button class="ui red button">Red</button> | |||
<button class="ui basic red button">Basic Red</button> | |||
<button class="ui primary button">Green</button> | |||
<button class="ui basic primary button">Basic Green</button> | |||
<button class="ui blue button">Blue</button> | |||
<button class="ui basic blue button">Basic Blue</button> | |||
<button class="ui orange button">Orange</button> | |||
<button class="ui basic orange button">Basic Orange</button> | |||
<button class="ui yellow button">Yellow</button> | |||
<button class="ui basic yellow button">Basic Yellow</button> | |||
</li> | |||
<li class="sample-group"> | |||
<h2>Supported but not recommended:</h2> | |||
<p>Do not use if there is no strong requirement. Do not use grey/black buttons, they don't work well with dark theme.</p> | |||
<button class="ui secondary button">Secondary</button> | |||
<button class="ui basic secondary button">Basic Secondary</button> | |||
<button class="ui olive button">Olive</button> | |||
<button class="ui basic olive button">Basic Olive</button> | |||
<button class="ui teal button">Teal</button> | |||
<button class="ui basic teal button">Basic Teal</button> | |||
<button class="ui violet button">Violet</button> | |||
<button class="ui basic violet button">Basic Violet</button> | |||
<button class="ui purple button">Purple</button> | |||
<button class="ui basic purple button">Basic Purple</button> | |||
<button class="ui pink button">Pink</button> | |||
<button class="ui basic pink button">Basic Pink</button> | |||
<button class="ui brown button">Brown</button> | |||
<button class="ui basic brown button">Basic Brown</button> | |||
<button class="ui green button">Green</button> | |||
<button class="ui basic green button">Basic Green</button> | |||
</li> | |||
<li class="sample-group"> | |||
<h2>Inline / Plain:</h2> | |||
@@ -198,7 +170,7 @@ | |||
<button class="ui basic button">labeled button</button> | |||
<a class="ui basic label">123</a> | |||
</div> | |||
<button class="ui yellow button">{{svg "octicon-x" 16}} button with very very very very very very very very long text</button> | |||
<button class="ui button">{{svg "octicon-x" 16}} button with very very very very very very very very long text</button> | |||
</div> | |||
<h2>Input with SVG</h2> | |||
@@ -271,10 +243,6 @@ | |||
<span class="text">button dropdown</span> | |||
{{svg "octicon-triangle-down" 14 "dropdown icon"}} | |||
</div> | |||
<div class="ui dropdown large button"> | |||
<span class="text">large dropdown</span> | |||
{{svg "octicon-triangle-down" 14 "dropdown icon"}} | |||
</div> | |||
</div> | |||
<div> | |||
@@ -290,10 +258,6 @@ | |||
<span class="text">button compact</span> | |||
{{svg "octicon-triangle-down" 14 "dropdown icon"}} | |||
</div> | |||
<div class="ui dropdown large compact button"> | |||
<span class="text">large compact</span> | |||
{{svg "octicon-triangle-down" 14 "dropdown icon"}} | |||
</div> | |||
</div> | |||
<div> |
@@ -0,0 +1,27 @@ | |||
{{template "base/head" .}} | |||
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/devtest.css?v={{AssetVersion}}"> | |||
<div class="page-content devtest ui container"> | |||
<div> | |||
<h1>Label</h1> | |||
<div class="flex-text-block tw-my-2"> | |||
<span class="ui label">simple label</span> | |||
<span class="ui red label">red label</span> | |||
<span class="ui green label">green label</span> | |||
</div> | |||
<div class="flex-text-block tw-my-2"> | |||
<span class="ui basic label">basic label</span> | |||
<span class="ui basic red label">basic red label</span> | |||
<span class="ui basic green label">basic green label</span> | |||
</div> | |||
<div class="flex-text-block tw-my-2"> | |||
<span class="ui label">long content must be in a non-flex "gt-ellipsis" element, otherwise it won't get ellipsis. very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span> | |||
</div> | |||
<div class="flex-text-block tw-my-2"> | |||
<span class="ui label"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> | |||
</div> | |||
<div class="tw-my-2"> | |||
<span class="ui label tw-max-w-full"><span class="gt-ellipsis">very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label</span></span> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -79,7 +79,7 @@ | |||
</div> | |||
{{if .IsOrganizationOwner}} | |||
<div class="ui bottom attached segment"> | |||
<a class="ui teal small button" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit">{{svg "octicon-gear"}} {{ctx.Locale.Tr "org.teams.settings"}}</a> | |||
<a class="ui small button" href="{{.OrgLink}}/teams/{{.Team.LowerName | PathEscape}}/edit">{{svg "octicon-gear"}} {{ctx.Locale.Tr "org.teams.settings"}}</a> | |||
</div> | |||
{{end}} | |||
</div> |
@@ -5,7 +5,7 @@ | |||
{{$branchLink := HTMLFormat `<a href="%s/src/branch/%s">%s</a>` $.RepoLink (PathEscapeSegments .Name) .Name}} | |||
{{ctx.Locale.Tr "repo.pulls.recently_pushed_new_branches" $branchLink $timeSince}} | |||
</div> | |||
<a role="button" class="ui compact positive button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}"> | |||
<a role="button" class="ui compact green button tw-m-0" href="{{$.Repository.ComposeBranchCompareURL $.Repository.BaseRepo .Name}}"> | |||
{{ctx.Locale.Tr "repo.pulls.compare_changes"}} | |||
</a> | |||
</div> |
@@ -48,7 +48,7 @@ | |||
</div> | |||
{{end}} | |||
{{end}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $.root "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/context_menu" dict "ctxData" $.root "item" . "delete" true "issue" false "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}} | |||
</div> | |||
</div> | |||
@@ -68,7 +68,7 @@ | |||
</div> | |||
{{$reactions := .Reactions.GroupByType}} | |||
{{if $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ctxData" $.root "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -184,23 +184,15 @@ | |||
{{end}} | |||
{{else if and .PageIsComparePull (gt .CommitCount 0)}} | |||
{{if .HasPullRequest}} | |||
<div class="ui segment grid title"> | |||
<div class="twelve wide column issue-title"> | |||
{{ctx.Locale.Tr "repo.pulls.has_pull_request" (print $.RepoLink "/pulls/" .PullRequest.Issue.Index) $.RepoRelPath .PullRequest.Index}} | |||
<h1> | |||
<span id="issue-title">{{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx)}}</span> | |||
<span class="index">#{{.PullRequest.Issue.Index}}</span> | |||
</h1> | |||
</div> | |||
<div class="four wide column middle aligned text right"> | |||
{{- if .PullRequest.HasMerged -}} | |||
<a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button purple show-form">{{svg "octicon-git-merge" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> | |||
{{else if .Issue.IsClosed}} | |||
<a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button red show-form">{{svg "octicon-issue-closed" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> | |||
{{else}} | |||
<a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui button primary show-form">{{svg "octicon-git-pull-request" 16}} {{ctx.Locale.Tr "repo.pulls.view"}}</a> | |||
{{end}} | |||
<div class="ui segment flex-text-block tw-gap-4"> | |||
{{template "shared/issueicon" .}} | |||
<div class="issue-title tw-break-anywhere"> | |||
{{RenderIssueTitle $.Context .PullRequest.Issue.Title ($.Repository.ComposeMetas ctx) | RenderCodeBlock}} | |||
<span class="index">#{{.PullRequest.Issue.Index}}</span> | |||
</div> | |||
<a href="{{$.RepoLink}}/pulls/{{.PullRequest.Issue.Index}}" class="ui compact button primary"> | |||
{{ctx.Locale.Tr "repo.pulls.view"}} | |||
</a> | |||
</div> | |||
{{else}} | |||
{{if and $.IsSigned (not .Repository.IsArchived)}} |
@@ -46,7 +46,7 @@ | |||
<div class="comment-header-right actions tw-flex tw-items-center"> | |||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .Issue.ShowRole "IgnorePoster" true}} | |||
{{if not $.Repository.IsArchived}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} | |||
{{end}} | |||
{{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" .Issue "delete" false "issue" true "diff" false "IsCommentPoster" $.IsIssuePoster}} | |||
</div> | |||
@@ -67,7 +67,7 @@ | |||
</div> | |||
{{$reactions := .Issue.Reactions.GroupByType}} | |||
{{if $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index) "Reactions" $reactions}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -1,11 +1,9 @@ | |||
{{if .ctxData.IsSigned}} | |||
{{if ctx.RootData.IsSigned}} | |||
<div class="item action ui dropdown jump pointing top right select-reaction" data-action-url="{{.ActionURL}}"> | |||
<a class="add-reaction muted"> | |||
{{svg "octicon-smiley"}} | |||
</a> | |||
<div class="menu reactions-menu"> | |||
<a class="muted">{{svg "octicon-smiley"}}</a> | |||
<div class="menu"> | |||
{{range $value := AllowedReactions}} | |||
<a class="item reaction" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}">{{ReactionToEmoji $value}}</a> | |||
<a class="item emoji comment-reaction-button" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}">{{ReactionToEmoji $value}}</a> | |||
{{end}} | |||
</div> | |||
</div> |
@@ -53,7 +53,7 @@ | |||
<div class="comment-header-right actions tw-flex tw-items-center"> | |||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} | |||
{{if not $.Repository.IsArchived}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{end}} | |||
{{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" true "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} | |||
</div> | |||
@@ -74,7 +74,7 @@ | |||
</div> | |||
{{$reactions := .Reactions.GroupByType}} | |||
{{if $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{end}} | |||
</div> | |||
</div> | |||
@@ -173,11 +173,11 @@ | |||
<span class="text grey muted-links"> | |||
{{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}} | |||
</span> | |||
</div> | |||
@@ -427,7 +427,7 @@ | |||
<div class="comment-header-right actions tw-flex tw-items-center"> | |||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} | |||
{{if not $.Repository.IsArchived}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" false "issue" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} | |||
{{end}} | |||
</div> | |||
@@ -448,7 +448,7 @@ | |||
</div> | |||
{{$reactions := .Reactions.GroupByType}} | |||
{{if $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -55,8 +55,8 @@ | |||
<div class="ui comments tw-mb-0"> | |||
{{range .comments}} | |||
{{$createdSubStr:= TimeSinceUnix .CreatedUnix ctx.Locale}} | |||
<div class="comment code-comment tw-pb-4" id="{{.HashTag}}"> | |||
<div class="content"> | |||
<div class="comment code-comment" id="{{.HashTag}}"> | |||
<div class="content comment-container"> | |||
<div class="header comment-header"> | |||
<div class="comment-header-left tw-flex tw-items-center"> | |||
{{if not .OriginalAuthor}} | |||
@@ -82,7 +82,7 @@ | |||
<div class="comment-header-right actions tw-flex tw-items-center"> | |||
{{template "repo/issue/view_content/show_role" dict "ShowRole" .ShowRole}} | |||
{{if not $.Repository.IsArchived}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID)}} | |||
{{template "repo/issue/view_content/context_menu" dict "ctxData" $ "item" . "delete" true "issue" true "diff" true "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} | |||
{{end}} | |||
</div> | |||
@@ -103,7 +103,7 @@ | |||
</div> | |||
{{$reactions := .Reactions.GroupByType}} | |||
{{if $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ctxData" $ "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{template "repo/issue/view_content/reactions" dict "ActionURL" (printf "%s/comments/%d/reactions" $.RepoLink .ID) "Reactions" $reactions}} | |||
{{end}} | |||
</div> | |||
</div> |
@@ -1,7 +1,7 @@ | |||
<div class="ui attached segment reactions" data-action-url="{{$.ActionURL}}"> | |||
<div class="bottom-reactions" data-action-url="{{$.ActionURL}}"> | |||
{{range $key, $value := .Reactions}} | |||
{{$hasReacted := $value.HasUser $.ctxData.SignedUserID}} | |||
<a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not $.ctxData.IsSigned}} disabled{{end}} comment-reaction-button" | |||
{{$hasReacted := $value.HasUser ctx.RootData.SignedUserID}} | |||
<a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not ctx.RootData.IsSigned}} disabled{{end}} comment-reaction-button" | |||
data-tooltip-content | |||
title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" | |||
aria-label="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}" | |||
@@ -12,6 +12,6 @@ | |||
</a> | |||
{{end}} | |||
{{if AllowedReactions}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ctxData" $.ctxData "ActionURL" .ActionURL}} | |||
{{template "repo/issue/view_content/add_reaction" dict "ActionURL" .ActionURL}} | |||
{{end}} | |||
</div> |
@@ -572,7 +572,7 @@ | |||
</form> | |||
{{end}} | |||
<button class="tw-mt-1 fluid ui show-modal button {{if .Issue.IsLocked}} negative {{end}}" data-modal="#lock"> | |||
<button class="tw-mt-1 fluid ui show-modal button{{if .Issue.IsLocked}} red{{end}}" data-modal="#lock"> | |||
{{if .Issue.IsLocked}} | |||
{{svg "octicon-key"}} | |||
{{ctx.Locale.Tr "repo.issues.unlock"}} |
@@ -25,12 +25,14 @@ | |||
<div class="column"> | |||
{{if gt .Activity.ActivePRCount 0}} | |||
<div class="stats-table"> | |||
<a href="#merged-pull-requests" class="table-cell tiny background purple" style="width: {{.Activity.MergedPRPerc}}{{if ne .Activity.MergedPRPerc 0}}%{{end}}"></a> | |||
<a href="#proposed-pull-requests" class="table-cell tiny background green"></a> | |||
{{if gt .Activity.MergedPRPerc 0}} | |||
<a href="#merged-pull-requests" class="table-cell tiny tw-bg-purple" style="width: {{.Activity.MergedPRPerc}}%"></a> | |||
{{end}} | |||
<a href="#proposed-pull-requests" class="table-cell tiny tw-bg-green"></a> | |||
</div> | |||
{{else}} | |||
<div class="stats-table"> | |||
<a class="table-cell tiny background light grey"></a> | |||
<a class="table-cell tiny tw-bg-grey"></a> | |||
</div> | |||
{{end}} | |||
{{ctx.Locale.TrN .Activity.ActivePRCount "repo.activity.active_prs_count_1" "repo.activity.active_prs_count_n" .Activity.ActivePRCount}} | |||
@@ -40,8 +42,10 @@ | |||
<div class="column"> | |||
{{if gt .Activity.ActiveIssueCount 0}} | |||
<div class="stats-table"> | |||
<a href="#closed-issues" class="table-cell tiny background red" style="width: {{.Activity.ClosedIssuePerc}}{{if ne .Activity.ClosedIssuePerc 0}}%{{end}}"></a> | |||
<a href="#new-issues" class="table-cell tiny background green"></a> | |||
{{if gt .Activity.ClosedIssuePerc 0}} | |||
<a href="#closed-issues" class="table-cell tiny tw-bg-red" style="width: {{.Activity.ClosedIssuePerc}}%"></a> | |||
{{end}} | |||
<a href="#new-issues" class="table-cell tiny tw-bg-green"></a> | |||
</div> | |||
{{else}} | |||
<div class="stats-table"> | |||
@@ -108,7 +112,7 @@ | |||
{{end}} | |||
{{if gt .Activity.PublishedReleaseCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="published-releases"> | |||
<h4 class="divider divider-text" id="published-releases"> | |||
{{svg "octicon-tag" 16 "tw-mr-2"}} | |||
{{ctx.Locale.Tr "repo.activity.title.releases_published_by" | |||
(ctx.Locale.TrN .Activity.PublishedReleaseCount "repo.activity.title.releases_1" "repo.activity.title.releases_n" .Activity.PublishedReleaseCount) | |||
@@ -130,7 +134,7 @@ | |||
{{end}} | |||
{{if gt .Activity.MergedPRCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="merged-pull-requests"> | |||
<h4 class="divider divider-text" id="merged-pull-requests"> | |||
{{svg "octicon-git-pull-request" 16 "tw-mr-2"}} | |||
{{ctx.Locale.Tr "repo.activity.title.prs_merged_by" | |||
(ctx.Locale.TrN .Activity.MergedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.MergedPRCount) | |||
@@ -149,7 +153,7 @@ | |||
{{end}} | |||
{{if gt .Activity.OpenedPRCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="proposed-pull-requests"> | |||
<h4 class="divider divider-text" id="proposed-pull-requests"> | |||
{{svg "octicon-git-branch" 16 "tw-mr-2"}} | |||
{{ctx.Locale.Tr "repo.activity.title.prs_opened_by" | |||
(ctx.Locale.TrN .Activity.OpenedPRCount "repo.activity.title.prs_1" "repo.activity.title.prs_n" .Activity.OpenedPRCount) | |||
@@ -168,7 +172,7 @@ | |||
{{end}} | |||
{{if gt .Activity.ClosedIssueCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="closed-issues"> | |||
<h4 class="divider divider-text" id="closed-issues"> | |||
{{svg "octicon-issue-closed" 16 "tw-mr-2"}} | |||
{{ctx.Locale.Tr "repo.activity.title.issues_closed_from" | |||
(ctx.Locale.TrN .Activity.ClosedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.ClosedIssueCount) | |||
@@ -187,7 +191,7 @@ | |||
{{end}} | |||
{{if gt .Activity.OpenedIssueCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="new-issues"> | |||
<h4 class="divider divider-text" id="new-issues"> | |||
{{svg "octicon-issue-opened" 16 "tw-mr-2"}} | |||
{{ctx.Locale.Tr "repo.activity.title.issues_created_by" | |||
(ctx.Locale.TrN .Activity.OpenedIssueCount "repo.activity.title.issues_1" "repo.activity.title.issues_n" .Activity.OpenedIssueCount) | |||
@@ -206,7 +210,7 @@ | |||
{{end}} | |||
{{if gt .Activity.UnresolvedIssueCount 0}} | |||
<h4 class="divider divider-text tw-normal-case" id="unresolved-conversations" data-tooltip-content="{{ctx.Locale.Tr "repo.activity.unresolved_conv_desc"}}"> | |||
<h4 class="divider divider-text" id="unresolved-conversations" data-tooltip-content="{{ctx.Locale.Tr "repo.activity.unresolved_conv_desc"}}"> | |||
{{svg "octicon-comment-discussion" 16 "tw-mr-2"}} | |||
{{ctx.Locale.TrN .Activity.UnresolvedIssueCount "repo.activity.title.unresolved_conv_1" "repo.activity.title.unresolved_conv_n" .Activity.UnresolvedIssueCount}} | |||
</h4> |
@@ -44,7 +44,7 @@ | |||
</p> | |||
<form class="ui form" action="{{$.Link}}/delete/{{.Oid}}" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} | |||
{{template "base/modal_actions_confirm"}} | |||
</form> | |||
</div> | |||
</div> |
@@ -37,7 +37,7 @@ | |||
</a> | |||
</td> | |||
<td> | |||
<a {{if and .Exists .InRepo}}href="{{$.LFSFilesLink}}/show/{{.Oid}}" rel="nofollow" target="_blank"{{end}} title="{{.Oid}}" class="ui brown button tw-font-mono"> | |||
<a {{if and .Exists .InRepo}}href="{{$.LFSFilesLink}}/show/{{.Oid}}" rel="nofollow" target="_blank"{{end}} title="{{.Oid}}" class="ui button tw-font-mono"> | |||
{{ShortSha .Oid}} | |||
</a> | |||
</td> |
@@ -156,7 +156,7 @@ | |||
<label for="interval">{{ctx.Locale.Tr "repo.mirror_interval" .MinimumMirrorInterval}}</label> | |||
<input id="interval" name="interval" value="{{.PullMirror.Interval}}"> | |||
</div> | |||
{{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}} | |||
{{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName}} | |||
<div class="field {{if .Err_MirrorAddress}}error{{end}}"> | |||
<label for="mirror_address">{{ctx.Locale.Tr "repo.mirror_address"}}</label> | |||
<input id="mirror_address" name="mirror_address" value="{{$address.Address}}" required> |
@@ -6,7 +6,7 @@ | |||
<div class="ui right"> | |||
<!-- the button is wrapped with a span because the tooltip doesn't show on hover if we put data-tooltip-content directly on the button --> | |||
<span data-tooltip-content="{{if or $isNew .Webhook.IsActive}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc"}}{{else}}{{ctx.Locale.Tr "repo.settings.webhook.test_delivery_desc_disabled"}}{{end}}"> | |||
<button class="ui teal tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}"> | |||
<button class="ui tiny button{{if not (or $isNew .Webhook.IsActive)}} disabled{{end}}" id="test-delivery" data-link="{{.Link}}/test" data-redirect="{{.Link}}"> | |||
<span class="text">{{ctx.Locale.Tr "repo.settings.webhook.test_delivery"}}</span> | |||
</button> | |||
</span> |
@@ -1,15 +1,13 @@ | |||
{{template "base/head" .}} | |||
<div role="main" aria-label="{{.Title}}" class="page-content dashboard feeds"> | |||
{{template "user/dashboard/navbar" .}} | |||
<div class="ui container"> | |||
<div class="ui container flex-container"> | |||
{{template "base/alert" .}} | |||
<div class="ui mobile reversed stackable grid"> | |||
<div class="ui container ten wide column"> | |||
{{template "user/heatmap" .}} | |||
{{template "user/dashboard/feeds" .}} | |||
</div> | |||
{{template "user/dashboard/repolist" .}} | |||
<div class="flex-container-main"> | |||
{{template "user/heatmap" .}} | |||
{{template "user/dashboard/feeds" .}} | |||
</div> | |||
{{template "user/dashboard/repolist" .}} | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -56,4 +56,4 @@ data.organizationId = {{.ContextUser.ID}}; | |||
window.config.pageData.dashboardRepoList = data; | |||
</script> | |||
<div id="dashboard-repo-list" class="six wide column"></div> | |||
<div id="dashboard-repo-list" class="flex-container-sidebar"></div> |
@@ -109,7 +109,7 @@ | |||
<div class="content"> | |||
<p>{{ctx.Locale.Tr "settings.access_token_deletion_desc"}}</p> | |||
</div> | |||
{{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}} | |||
{{template "base/modal_actions_confirm"}} | |||
</div> | |||
{{template "user/settings/layout_footer" .}} |
@@ -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 | |||
], | |||
}; |
@@ -319,27 +319,6 @@ a.label, | |||
background-color: var(--color-label-bg); | |||
} | |||
.ui.menu { | |||
display: flex; | |||
} | |||
.ui.menu, | |||
.ui.vertical.menu { | |||
background: var(--color-menu); | |||
border-color: var(--color-secondary); | |||
box-shadow: none; | |||
} | |||
.ui.menu .item { | |||
color: var(--color-text); | |||
user-select: auto; | |||
line-height: var(--line-height-default); /* fomantic uses "1" which causes overflow problems because "1" doesn't consider the descent part */ | |||
} | |||
.ui.menu .item > .svg { | |||
margin-right: 0.35em; | |||
} | |||
.ui.menu .dropdown.item:hover, | |||
.ui.menu a.item:hover, | |||
.ui.menu details.item summary:hover { | |||
@@ -347,42 +326,6 @@ a.label, | |||
background: var(--color-hover); | |||
} | |||
.ui.menu .active.item, | |||
.ui.menu .active.item:hover, | |||
.ui.vertical.menu .active.item, | |||
.ui.vertical.menu .active.item:hover { | |||
color: var(--color-text); | |||
background: var(--color-active); | |||
} | |||
.ui.menu a.item:active { | |||
color: var(--color-text); | |||
background: none; | |||
} | |||
.ui.ui.menu .item.disabled { | |||
color: var(--color-text-light-3); | |||
} | |||
.ui.menu .item::before, .ui.vertical.menu .item::before { | |||
background: var(--color-secondary); | |||
} | |||
/* sub menu of vertical menu */ | |||
.ui.vertical.menu .item .menu .item { | |||
color: var(--color-text-light-2); | |||
text-indent: 16px; | |||
} | |||
.ui.vertical.menu .item .menu .item:hover, | |||
.ui.vertical.menu .item .menu a.item:hover { | |||
color: var(--color-text-light-1); | |||
} | |||
.ui.vertical.menu .item .menu .active.item { | |||
color: var(--color-text); | |||
} | |||
/* slightly more contrast for filters on issue list */ | |||
.ui.ui.menu .dropdown.item.disabled { | |||
color: var(--color-text-light-2); | |||
@@ -441,11 +384,6 @@ a.label, | |||
background: var(--color-hover); | |||
} | |||
.ui.menu .ui.dropdown .menu > .selected.item { | |||
color: var(--color-text) !important; | |||
background: var(--color-hover) !important; | |||
} | |||
.ui.dropdown .menu > .message:not(.ui) { | |||
color: var(--color-text-light-2); | |||
} | |||
@@ -462,58 +400,6 @@ a.label, | |||
color: var(--color-text-light-2); | |||
} | |||
/* replace item margin on secondary menu items with gap and remove both the | |||
negative margins on the menu as well as margin on the items */ | |||
.ui.secondary.menu { | |||
margin-left: 0; | |||
margin-right: 0; | |||
gap: .35714286em; | |||
} | |||
.ui.secondary.menu .item { | |||
margin-left: 0; | |||
margin-right: 0; | |||
} | |||
.ui.secondary.menu .dropdown.item:hover, | |||
.ui.secondary.menu a.item:hover { | |||
color: var(--color-text); | |||
background: var(--color-hover); | |||
} | |||
.ui.secondary.menu .active.item, | |||
.ui.secondary.menu .active.item:hover { | |||
color: var(--color-text); | |||
background: var(--color-active); | |||
} | |||
.ui.secondary.menu.tight .item { | |||
padding-left: 0.85714286em; | |||
padding-right: 0.85714286em; | |||
} | |||
/* remove the menu clearfix so that it won't add undesired gaps when using "gap" */ | |||
.ui.menu::after { | |||
content: normal; | |||
} | |||
.ui.menu .dropdown.item .menu { | |||
background: var(--color-body); | |||
} | |||
.ui.menu .ui.dropdown .menu > .item { | |||
color: var(--color-text) !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .item:hover { | |||
color: var(--color-text) !important; | |||
background: var(--color-hover) !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .active.item { | |||
color: var(--color-text) !important; | |||
background: var(--color-active) !important; | |||
} | |||
.ui.form textarea:not([rows]) { | |||
height: var(--min-height-textarea); /* override fomantic default 12em */ | |||
min-height: var(--min-height-textarea); /* override fomantic default 8em */ | |||
@@ -606,11 +492,6 @@ img.ui.avatar, | |||
margin-top: calc(var(--page-spacing) - 1rem); | |||
} | |||
.ui.pagination.menu .active.item { | |||
color: var(--color-text); | |||
background: var(--color-active); | |||
} | |||
.ui.form .fields.error .field textarea, | |||
.ui.form .fields.error .field select, | |||
.ui.form .fields.error .field input:not([type]), | |||
@@ -782,11 +663,7 @@ input:-webkit-autofill:active, | |||
font-size: 0.75em; | |||
} | |||
.ui.form .ui.button { | |||
font-weight: var(--font-weight-normal); | |||
} | |||
/* replace fomantic popover box shadows */ | |||
/* popover box shadows */ | |||
.ui.dropdown .menu, | |||
.ui.upward.dropdown > .menu, | |||
.ui.menu .dropdown.item .menu, | |||
@@ -804,22 +681,6 @@ input:-webkit-autofill:active, | |||
background: var(--color-overlay-backdrop); | |||
} | |||
/* Override semantic selector '.ui.menu:not(.vertical) .item > .button' */ | |||
/* This fixes the commit graph button on the commits page */ | |||
/* modal svg icons, copied from fomantic except width and height */ | |||
/* center text in fomantic modal dialogs */ | |||
.ui .menu:not(.vertical) .item > .button.compact { | |||
padding: 0.58928571em 1.125em; | |||
} | |||
.ui .menu:not(.vertical) .item > .button.small { | |||
font-size: 0.92857143rem; | |||
} | |||
.ui.menu .ui.dropdown.item .menu .item { | |||
width: 100%; | |||
} | |||
.ui.dropdown .menu > .header { | |||
font-size: 0.8em; | |||
} | |||
@@ -1010,24 +871,6 @@ input:-webkit-autofill:active, | |||
border-color: var(--color-gold) !important; | |||
} | |||
@media (max-width: 767.98px) { | |||
.ui.pagination.menu .item:not(.active,.navigation), | |||
.ui.pagination.menu .item.navigation span.navigation_label { | |||
display: none; | |||
} | |||
} | |||
.ui.pagination.menu.narrow .item { | |||
padding-left: 8px; | |||
padding-right: 8px; | |||
min-width: 1em; | |||
text-align: center; | |||
} | |||
.ui.pagination.menu.narrow .item .icon { | |||
margin-right: 0; | |||
} | |||
.ui.floating.dropdown .overflow.menu .scrolling.menu.items { | |||
border-radius: 0 !important; | |||
box-shadow: none !important; | |||
@@ -1149,11 +992,6 @@ overflow-menu .ui.label { | |||
margin-top: 1px; | |||
} | |||
.ui.menu .item > .label { | |||
background: var(--color-label-bg); | |||
color: var(--color-label-text); | |||
} | |||
.lines-blame-btn { | |||
padding: 0 0 0 5px; | |||
display: flex; | |||
@@ -1366,8 +1204,7 @@ table th[data-sortt-desc] .svg { | |||
box-shadow: 0 0 0 1px var(--color-secondary) inset; | |||
} | |||
.emoji, | |||
.reaction { | |||
.emoji { | |||
font-size: 1.25em; | |||
line-height: var(--line-height-default); | |||
font-style: normal !important; | |||
@@ -1375,8 +1212,7 @@ table th[data-sortt-desc] .svg { | |||
vertical-align: -0.075em; | |||
} | |||
.emoji img, | |||
.reaction img { | |||
.emoji img { | |||
border-width: 0 !important; | |||
margin: 0 !important; | |||
width: 1em !important; | |||
@@ -1384,26 +1220,6 @@ table th[data-sortt-desc] .svg { | |||
vertical-align: -0.15em; | |||
} | |||
.ui.tabular.menu { | |||
border-color: var(--color-secondary); | |||
} | |||
.ui.tabular.menu .active.item, | |||
.ui.tabular.menu .active.item:hover { | |||
background: var(--color-body); | |||
border-color: var(--color-secondary); | |||
color: var(--color-text); | |||
} | |||
.ui.segment .ui.tabular.menu .active.item, | |||
.ui.segment .ui.tabular.menu .active.item:hover { | |||
background: var(--color-box-body); | |||
} | |||
.ui.secondary.pointing.menu { | |||
border-color: var(--color-secondary); | |||
} | |||
.ui.tabular.menu .item, | |||
.ui.secondary.pointing.menu .item { | |||
padding: 11.55px 12px !important; /* match .dashboard-navbar in height */ | |||
@@ -1415,12 +1231,6 @@ table th[data-sortt-desc] .svg { | |||
color: var(--color-text); | |||
} | |||
.ui.secondary.pointing.menu .active.item, | |||
.ui.secondary.pointing.menu .active.item:hover, | |||
.ui.secondary.pointing.menu .dropdown.item:hover { | |||
color: var(--color-text-dark); | |||
} | |||
.ui.tabular.menu .active.item, | |||
.ui.secondary.pointing.menu .active.item, | |||
.resize-for-semibold::before { | |||
@@ -1531,10 +1341,7 @@ table th[data-sortt-desc] .svg { | |||
align-items: center; | |||
gap: .25rem; | |||
vertical-align: middle; | |||
} | |||
.ui.ui.button { | |||
justify-content: center; | |||
min-width: 0; | |||
} | |||
.ui.dropdown .ui.label .svg { | |||
@@ -1551,6 +1358,7 @@ table th[data-sortt-desc] .svg { | |||
display: flex; | |||
align-items: center; | |||
gap: .25rem; | |||
min-width: 0; | |||
} | |||
/* to override Fomantic's default display: block for ".menu .item", and use a slightly larger gap for menu item content */ | |||
@@ -1558,4 +1366,5 @@ table th[data-sortt-desc] .svg { | |||
display: flex !important; | |||
align-items: center; | |||
gap: .5rem; | |||
min-width: 0; | |||
} |
@@ -7,7 +7,6 @@ | |||
.dashboard.feeds .context.user.menu .ui.header, | |||
.dashboard.issues .context.user.menu .ui.header { | |||
font-size: 1rem; | |||
text-transform: none; | |||
} | |||
.dashboard.feeds .filter.menu, |
@@ -52,6 +52,9 @@ only use: | |||
*/ | |||
.tw-hidden.tw-hidden { display: none !important; } | |||
/* proposed class from https://github.com/tailwindlabs/tailwindcss/pull/12128 */ | |||
.tw-break-anywhere { overflow-wrap: anywhere !important; } | |||
@media (max-width: 767.98px) { | |||
/* double selector so it wins over .tw-flex (old .gt-df) etc */ | |||
.not-mobile.not-mobile { |
@@ -11,6 +11,7 @@ | |||
@import "./modules/list.css"; | |||
@import "./modules/segment.css"; | |||
@import "./modules/grid.css"; | |||
@import "./modules/menu.css"; | |||
@import "./modules/message.css"; | |||
@import "./modules/table.css"; | |||
@import "./modules/card.css"; | |||
@@ -62,6 +63,7 @@ | |||
@import "./repo/linebutton.css"; | |||
@import "./repo/wiki.css"; | |||
@import "./repo/header.css"; | |||
@import "./repo/reactions.css"; | |||
@import "./editor/fileeditor.css"; | |||
@import "./editor/combomarkdowneditor.css"; |
@@ -1,11 +1,33 @@ | |||
/* this contains override styles for buttons and related elements */ | |||
/* these styles changed the Fomantic UI's rules, Fomantic UI expects only "basic" buttons have borders */ | |||
.ui.button, | |||
.ui.button:focus { | |||
/* based on Fomantic UI checkbox module, with just the parts extracted that we use. If you find any | |||
unused rules here after refactoring, please remove them. */ | |||
.ui.button { | |||
cursor: pointer; | |||
display: inline-block; | |||
min-height: 1em; | |||
outline: none; | |||
vertical-align: baseline; | |||
font-family: var(--fonts-regular); | |||
margin: 0 0.25em 0 0; | |||
padding: 0.78571429em 1.5em; | |||
font-weight: var(--font-weight-normal); | |||
text-align: center; | |||
text-decoration: none; | |||
line-height: 1; | |||
border-radius: 0.28571429rem; | |||
user-select: none; | |||
-webkit-tap-highlight-color: transparent; | |||
justify-content: center; | |||
background: var(--color-button); | |||
border: 1px solid var(--color-light-border); | |||
color: var(--color-text); | |||
white-space: nowrap; | |||
} | |||
@media (max-width: 767.98px) { | |||
.ui.button { | |||
white-space: normal; | |||
} | |||
} | |||
.ui.button:hover { | |||
@@ -13,10 +35,6 @@ | |||
color: var(--color-text); | |||
} | |||
.page-content .ui.button { | |||
box-shadow: none !important; | |||
} | |||
.ui.active.button, | |||
.ui.button:active, | |||
.ui.active.button:active, | |||
@@ -25,89 +43,116 @@ | |||
color: var(--color-text); | |||
} | |||
.delete-button, | |||
.delete-button:hover { | |||
color: var(--color-red); | |||
.ui.buttons .disabled.button:not(.basic), | |||
.ui.disabled.button, | |||
.ui.button:disabled, | |||
.ui.disabled.button:hover, | |||
.ui.disabled.active.button { | |||
cursor: default; | |||
opacity: var(--opacity-disabled) !important; | |||
background-image: none; | |||
pointer-events: none !important; | |||
} | |||
/* btn is a plain button without any opinionated styling, it only uses flex for vertical alignment like ".ui.button" in base.css */ | |||
.btn { | |||
background: transparent; | |||
border-radius: var(--border-radius); | |||
.ui.labeled.button:not(.icon) { | |||
display: inline-flex; | |||
flex-direction: row; | |||
background: none; | |||
padding: 0 !important; | |||
border: none; | |||
color: inherit; | |||
} | |||
.ui.labeled.button > .button { | |||
margin: 0; | |||
padding: 0; | |||
} | |||
.btn:hover, | |||
.btn:active, | |||
.btn:focus { | |||
background: none; | |||
border: none; | |||
.ui.labeled.button > .label { | |||
display: flex; | |||
align-items: center; | |||
margin: 0 0 0 -1px !important; | |||
font-size: 1em; | |||
border-color: var(--color-light-border); | |||
} | |||
a.btn, | |||
a.btn:hover { | |||
color: inherit; | |||
.ui.button > .icon:not(.button) { | |||
height: auto; | |||
opacity: 0.8; | |||
} | |||
/* By default, Fomantic UI doesn't support "bordered" buttons group, but Gitea would like to use it. | |||
And the default buttons always have borders now (not the same as Fomantic UI's default buttons, see above). | |||
It needs some tricks to tweak the left/right borders with active state */ | |||
.ui.buttons .button { | |||
border-right: none; | |||
.ui.button:not(.icon) > .icon:not(.button):not(.dropdown), | |||
.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) { | |||
margin: 0 0.42857143em 0 -0.21428571em; | |||
vertical-align: baseline; | |||
} | |||
.ui.buttons .button:hover { | |||
border-color: var(--color-secondary-dark-2); | |||
.ui.button:not(.icon) > .icons:not(.button):not(.dropdown) > .icon { | |||
vertical-align: baseline; | |||
} | |||
.ui.buttons .button:hover + .button { | |||
border-left: 1px solid var(--color-secondary-dark-2); | |||
.ui.button:not(.icon) > .right.icon:not(.button):not(.dropdown) { | |||
margin: 0 -0.21428571em 0 0.42857143em; | |||
} | |||
/* TODO: these "tw-hidden" selectors are only used by "blame.tmpl" buttons: Raw/Normal View/History/Unescape, need to be refactored to a clear solution later */ | |||
.ui.buttons .button:first-child, | |||
.ui.buttons .button.tw-hidden:first-child + .button { | |||
border-left: 1px solid var(--color-light-border); | |||
.ui.compact.buttons .button, | |||
.ui.compact.button { | |||
padding: 0.58928571em 1.125em; | |||
} | |||
.ui.buttons .button:last-child, | |||
.ui.buttons .button:nth-last-child(2):has(+ .button.tw-hidden) { | |||
border-right: 1px solid var(--color-light-border); | |||
.ui.compact.icon.buttons .button, | |||
.ui.compact.icon.button { | |||
padding: 0.58928571em; | |||
} | |||
.ui.compact.labeled.icon.button { | |||
padding: 0.58928571em 3.69642857em; | |||
} | |||
.ui.compact.labeled.icon.button > .icon { | |||
padding: 0.58928571em 0; | |||
} | |||
.ui.buttons .button.active { | |||
border-left: 1px solid var(--color-light-border); | |||
border-right: 1px solid var(--color-light-border); | |||
.ui.buttons .button, | |||
.ui.button { | |||
font-size: 1rem; | |||
} | |||
.ui.mini.buttons .dropdown, | |||
.ui.mini.buttons .dropdown .menu > .item, | |||
.ui.mini.buttons .button, | |||
.ui.ui.ui.ui.mini.button { | |||
font-size: 0.78571429rem; | |||
} | |||
.ui.tiny.buttons .dropdown, | |||
.ui.tiny.buttons .dropdown .menu > .item, | |||
.ui.tiny.buttons .button, | |||
.ui.ui.ui.ui.tiny.button { | |||
font-size: 0.85714286rem; | |||
} | |||
.ui.small.buttons .dropdown, | |||
.ui.small.buttons .dropdown .menu > .item, | |||
.ui.small.buttons .button, | |||
.ui.ui.ui.ui.small.button { | |||
font-size: 0.92857143rem; | |||
} | |||
.ui.buttons .button.active + .button { | |||
border-left: none; | |||
.ui.icon.buttons .button, | |||
.ui.icon.button:not(.compact) { | |||
padding: 0.78571429em; | |||
} | |||
.ui.icon.buttons .button > .icon, | |||
.ui.icon.button > .icon { | |||
margin: 0 !important; | |||
vertical-align: top; | |||
} | |||
.ui.basic.buttons .button, | |||
.ui.basic.button, | |||
.ui.basic.buttons .button:hover, | |||
.ui.basic.button:hover { | |||
box-shadow: none; | |||
.ui.basic.button { | |||
border-radius: 0.28571429rem; | |||
background: none; | |||
} | |||
/* apply the vertical padding of .compact to non-compact buttons when they contain a svg as they | |||
would otherwise appear too large. Seen on "RSS Feed" button on repo releases tab. */ | |||
.ui.small.button:not(.compact):has(.svg) { | |||
padding-top: 0.58928571em; | |||
padding-bottom: 0.58928571em; | |||
.ui.basic.buttons { | |||
border: 1px solid var(--color-secondary); | |||
border-radius: 0.28571429rem; | |||
} | |||
.ui.basic.buttons .button { | |||
border-radius: 0; | |||
border-left: 1px solid var(--color-secondary); | |||
} | |||
.ui.labeled.button.disabled > .button, | |||
.ui.basic.buttons .button, | |||
.ui.basic.button, | |||
.ui.basic.buttons .button:focus, | |||
.ui.basic.button:focus { | |||
.ui.basic.button { | |||
color: var(--color-text-light); | |||
background: var(--color-button); | |||
} | |||
@@ -129,23 +174,45 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
background: var(--color-active); | |||
} | |||
.ui.labeled.button > .label { | |||
border-color: var(--color-light-border); | |||
.ui.labeled.icon.button { | |||
position: relative; | |||
padding-left: 4.07142857em !important; | |||
padding-right: 1.5em !important; | |||
} | |||
.ui.labeled.icon.buttons > .button > .icon, | |||
.ui.labeled.icon.button > .icon { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
height: 100%; | |||
line-height: 1; | |||
border-radius: 0; | |||
border-top-left-radius: inherit; | |||
border-bottom-left-radius: inherit; | |||
text-align: center; | |||
animation: none; | |||
padding: 0.78571429em 0; | |||
margin: 0; | |||
width: 2.57142857em; | |||
background: var(--color-hover); | |||
} | |||
/* primary */ | |||
.ui.button.toggle.active { | |||
background-color: var(--color-green); | |||
color: var(--color-white); | |||
} | |||
.ui.button.toggle.active:hover { | |||
background-color: var(--color-green-dark-1); | |||
color: var(--color-white); | |||
} | |||
.ui.fluid.button { | |||
width: 100%; | |||
display: block; | |||
} | |||
.ui.primary.labels .label, | |||
.ui.ui.ui.primary.label, | |||
.ui.primary.button, | |||
.ui.primary.buttons .button, | |||
.ui.primary.button:focus, | |||
.ui.primary.buttons .button:focus { | |||
.ui.primary.buttons .button { | |||
background: var(--color-primary); | |||
color: var(--color-primary-contrast); | |||
} | |||
@@ -162,11 +229,10 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
} | |||
.ui.basic.primary.buttons .button, | |||
.ui.basic.primary.button, | |||
.ui.basic.primary.buttons .button:focus, | |||
.ui.basic.primary.button:focus { | |||
.ui.basic.primary.button { | |||
color: var(--color-primary); | |||
border-color: var(--color-primary); | |||
background: none; | |||
} | |||
.ui.basic.primary.buttons .button:hover, | |||
@@ -181,55 +247,8 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
border-color: var(--color-primary-active); | |||
} | |||
/* secondary */ | |||
.ui.secondary.labels .label, | |||
.ui.ui.ui.secondary.label, | |||
.ui.secondary.button, | |||
.ui.secondary.buttons .button, | |||
.ui.secondary.button:focus, | |||
.ui.secondary.buttons .button:focus { | |||
background: var(--color-secondary-button); | |||
} | |||
.ui.secondary.button:hover, | |||
.ui.secondary.buttons .button:hover { | |||
background: var(--color-secondary-hover); | |||
} | |||
.ui.secondary.button:active, | |||
.ui.secondary.buttons .button:active { | |||
background: var(--color-secondary-active); | |||
} | |||
.ui.basic.secondary.buttons .button, | |||
.ui.basic.secondary.button, | |||
.ui.basic.secondary.button:focus, | |||
.ui.basic.secondary.buttons .button:focus { | |||
color: var(--color-secondary-button); | |||
border-color: var(--color-secondary-button); | |||
} | |||
.ui.basic.secondary.buttons .button:hover, | |||
.ui.basic.secondary.button:hover { | |||
color: var(--color-secondary-hover); | |||
border-color: var(--color-secondary-hover); | |||
} | |||
.ui.basic.secondary.buttons .button:active, | |||
.ui.basic.secondary.button:active { | |||
color: var(--color-secondary-active); | |||
border-color: var(--color-secondary-active); | |||
} | |||
/* red */ | |||
.ui.red.labels .label, | |||
.ui.ui.ui.red.label, | |||
.ui.red.button, | |||
.ui.red.buttons .button, | |||
.ui.red.button:focus, | |||
.ui.red.buttons .button:focus { | |||
.ui.red.buttons .button { | |||
background: var(--color-red); | |||
} | |||
@@ -244,11 +263,10 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
} | |||
.ui.basic.red.buttons .button, | |||
.ui.basic.red.button, | |||
.ui.basic.red.buttons .button:focus, | |||
.ui.basic.red.button:focus { | |||
.ui.basic.red.button { | |||
color: var(--color-red); | |||
border-color: var(--color-red); | |||
background: none; | |||
} | |||
.ui.basic.red.buttons .button:hover, | |||
@@ -263,137 +281,8 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
border-color: var(--color-red-dark-2); | |||
} | |||
/* orange */ | |||
.ui.orange.labels .label, | |||
.ui.ui.ui.orange.label, | |||
.ui.orange.button, | |||
.ui.orange.buttons .button, | |||
.ui.orange.button:focus, | |||
.ui.orange.buttons .button:focus { | |||
background: var(--color-orange); | |||
} | |||
.ui.orange.button:hover, | |||
.ui.orange.buttons .button:hover { | |||
background: var(--color-orange-dark-1); | |||
} | |||
.ui.orange.button:active, | |||
.ui.orange.buttons .button:active { | |||
background: var(--color-orange-dark-2); | |||
} | |||
.ui.basic.orange.buttons .button, | |||
.ui.basic.orange.button, | |||
.ui.basic.orange.buttons .button:focus, | |||
.ui.basic.orange.button:focus { | |||
color: var(--color-orange); | |||
border-color: var(--color-orange); | |||
} | |||
.ui.basic.orange.buttons .button:hover, | |||
.ui.basic.orange.button:hover { | |||
color: var(--color-orange-dark-1); | |||
border-color: var(--color-orange-dark-1); | |||
} | |||
.ui.basic.orange.buttons .button:active, | |||
.ui.basic.orange.button:active { | |||
color: var(--color-orange-dark-2); | |||
border-color: var(--color-orange-dark-2); | |||
} | |||
/* yellow */ | |||
.ui.yellow.labels .label, | |||
.ui.ui.ui.yellow.label, | |||
.ui.yellow.button, | |||
.ui.yellow.buttons .button, | |||
.ui.yellow.button:focus, | |||
.ui.yellow.buttons .button:focus { | |||
background: var(--color-yellow); | |||
} | |||
.ui.yellow.button:hover, | |||
.ui.yellow.buttons .button:hover { | |||
background: var(--color-yellow-dark-1); | |||
} | |||
.ui.yellow.button:active, | |||
.ui.yellow.buttons .button:active { | |||
background: var(--color-yellow-dark-2); | |||
} | |||
.ui.basic.yellow.buttons .button, | |||
.ui.basic.yellow.button, | |||
.ui.basic.yellow.buttons .button:focus, | |||
.ui.basic.yellow.button:focus { | |||
color: var(--color-yellow); | |||
border-color: var(--color-yellow); | |||
} | |||
.ui.basic.yellow.buttons .button:hover, | |||
.ui.basic.yellow.button:hover { | |||
color: var(--color-yellow-dark-1); | |||
border-color: var(--color-yellow-dark-1); | |||
} | |||
.ui.basic.yellow.buttons .button:active, | |||
.ui.basic.yellow.button:active { | |||
color: var(--color-yellow-dark-2); | |||
border-color: var(--color-yellow-dark-2); | |||
} | |||
/* olive */ | |||
.ui.olive.labels .label, | |||
.ui.ui.ui.olive.label, | |||
.ui.olive.button, | |||
.ui.olive.buttons .button, | |||
.ui.olive.button:focus, | |||
.ui.olive.buttons .button:focus { | |||
background: var(--color-olive); | |||
} | |||
.ui.olive.button:hover, | |||
.ui.olive.buttons .button:hover { | |||
background: var(--color-olive-dark-1); | |||
} | |||
.ui.olive.button:active, | |||
.ui.olive.buttons .button:active { | |||
background: var(--color-olive-dark-2); | |||
} | |||
.ui.basic.olive.buttons .button, | |||
.ui.basic.olive.button, | |||
.ui.basic.olive.buttons .button:focus, | |||
.ui.basic.olive.button:focus { | |||
color: var(--color-olive); | |||
border-color: var(--color-olive); | |||
} | |||
.ui.basic.olive.buttons .button:hover, | |||
.ui.basic.olive.button:hover { | |||
color: var(--color-olive-dark-1); | |||
border-color: var(--color-olive-dark-1); | |||
} | |||
.ui.basic.olive.buttons .button:active, | |||
.ui.basic.olive.button:active { | |||
color: var(--color-olive-dark-2); | |||
border-color: var(--color-olive-dark-2); | |||
} | |||
/* green */ | |||
.ui.green.labels .label, | |||
.ui.ui.ui.green.label, | |||
.ui.green.button, | |||
.ui.green.buttons .button, | |||
.ui.green.button:focus, | |||
.ui.green.buttons .button:focus { | |||
.ui.green.buttons .button { | |||
background: var(--color-green); | |||
} | |||
@@ -408,11 +297,10 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
} | |||
.ui.basic.green.buttons .button, | |||
.ui.basic.green.button, | |||
.ui.basic.green.buttons .button:focus, | |||
.ui.basic.green.button:focus { | |||
.ui.basic.green.button { | |||
color: var(--color-green); | |||
border-color: var(--color-green); | |||
background: none; | |||
} | |||
.ui.basic.green.buttons .button:hover, | |||
@@ -427,326 +315,93 @@ It needs some tricks to tweak the left/right borders with active state */ | |||
border-color: var(--color-green-dark-2); | |||
} | |||
/* teal */ | |||
.ui.teal.labels .label, | |||
.ui.ui.ui.teal.label, | |||
.ui.teal.button, | |||
.ui.teal.buttons .button, | |||
.ui.teal.button:focus, | |||
.ui.teal.buttons .button:focus { | |||
background: var(--color-teal); | |||
} | |||
.ui.teal.button:hover, | |||
.ui.teal.buttons .button:hover { | |||
background: var(--color-teal-dark-1); | |||
.ui.buttons { | |||
display: inline-flex; | |||
flex-direction: row; | |||
font-size: 0; | |||
vertical-align: baseline; | |||
margin: 0 0.25em 0 0; | |||
} | |||
.ui.teal.button:active, | |||
.ui.teal.buttons .button:active { | |||
background: var(--color-teal-dark-2); | |||
} | |||
.ui.basic.teal.buttons .button, | |||
.ui.basic.teal.button, | |||
.ui.basic.teal.buttons .button:focus, | |||
.ui.basic.teal.button:focus { | |||
color: var(--color-teal); | |||
border-color: var(--color-teal); | |||
} | |||
.ui.basic.teal.buttons .button:hover, | |||
.ui.basic.teal.button:hover { | |||
color: var(--color-teal-dark-1); | |||
border-color: var(--color-teal-dark-1); | |||
} | |||
.ui.basic.teal.buttons .button:active, | |||
.ui.basic.teal.button:active { | |||
color: var(--color-teal-dark-2); | |||
border-color: var(--color-teal-dark-2); | |||
} | |||
/* blue */ | |||
.ui.blue.labels .label, | |||
.ui.ui.ui.blue.label, | |||
.ui.blue.button, | |||
.ui.blue.buttons .button, | |||
.ui.blue.button:focus, | |||
.ui.blue.buttons .button:focus { | |||
background: var(--color-blue); | |||
} | |||
.ui.blue.button:hover, | |||
.ui.blue.buttons .button:hover { | |||
background: var(--color-blue-dark-1); | |||
} | |||
.ui.blue.button:active, | |||
.ui.blue.buttons .button:active { | |||
background: var(--color-blue-dark-2); | |||
} | |||
.ui.basic.blue.buttons .button, | |||
.ui.basic.blue.button, | |||
.ui.basic.blue.buttons .button:focus, | |||
.ui.basic.blue.button:focus { | |||
color: var(--color-blue); | |||
border-color: var(--color-blue); | |||
} | |||
.ui.basic.blue.buttons .button:hover, | |||
.ui.basic.blue.button:hover { | |||
color: var(--color-blue-dark-1); | |||
border-color: var(--color-blue-dark-1); | |||
} | |||
.ui.basic.blue.buttons .button:active, | |||
.ui.basic.blue.button:active { | |||
color: var(--color-blue-dark-2); | |||
border-color: var(--color-blue-dark-2); | |||
} | |||
/* violet */ | |||
.ui.violet.labels .label, | |||
.ui.ui.ui.violet.label, | |||
.ui.violet.button, | |||
.ui.violet.buttons .button, | |||
.ui.violet.button:focus, | |||
.ui.violet.buttons .button:focus { | |||
background: var(--color-violet); | |||
} | |||
.ui.violet.button:hover, | |||
.ui.violet.buttons .button:hover { | |||
background: var(--color-violet-dark-1); | |||
} | |||
.ui.violet.button:active, | |||
.ui.violet.buttons .button:active { | |||
background: var(--color-violet-dark-2); | |||
} | |||
.ui.basic.violet.buttons .button, | |||
.ui.basic.violet.button, | |||
.ui.basic.violet.buttons .button:focus, | |||
.ui.basic.violet.button:focus { | |||
color: var(--color-violet); | |||
border-color: var(--color-violet); | |||
} | |||
.ui.basic.violet.buttons .button:hover, | |||
.ui.basic.violet.button:hover { | |||
color: var(--color-violet-dark-1); | |||
border-color: var(--color-violet-dark-1); | |||
} | |||
.ui.basic.violet.buttons .button:active, | |||
.ui.basic.violet.button:active { | |||
color: var(--color-violet-dark-2); | |||
border-color: var(--color-violet-dark-2); | |||
} | |||
/* purple */ | |||
.ui.purple.labels .label, | |||
.ui.ui.ui.purple.label, | |||
.ui.purple.button, | |||
.ui.purple.buttons .button, | |||
.ui.purple.button:focus, | |||
.ui.purple.buttons .button:focus { | |||
background: var(--color-purple); | |||
} | |||
.ui.purple.button:hover, | |||
.ui.purple.buttons .button:hover { | |||
background: var(--color-purple-dark-1); | |||
} | |||
.ui.purple.button:active, | |||
.ui.purple.buttons .button:active { | |||
background: var(--color-purple-dark-2); | |||
} | |||
.ui.basic.purple.buttons .button, | |||
.ui.basic.purple.button, | |||
.ui.basic.purple.buttons .button:focus, | |||
.ui.basic.purple.button:focus { | |||
color: var(--color-purple); | |||
border-color: var(--color-purple); | |||
} | |||
.ui.basic.purple.buttons .button:hover, | |||
.ui.basic.purple.button:hover { | |||
color: var(--color-purple-dark-1); | |||
border-color: var(--color-purple-dark-1); | |||
} | |||
.ui.basic.purple.buttons .button:active, | |||
.ui.basic.purple.button:active { | |||
color: var(--color-purple-dark-2); | |||
border-color: var(--color-purple-dark-2); | |||
} | |||
/* pink */ | |||
.ui.pink.labels .label, | |||
.ui.ui.ui.pink.label, | |||
.ui.pink.button, | |||
.ui.pink.buttons .button, | |||
.ui.pink.button:focus, | |||
.ui.pink.buttons .button:focus { | |||
background: var(--color-pink); | |||
} | |||
.ui.pink.button:hover, | |||
.ui.pink.buttons .button:hover { | |||
background: var(--color-pink-dark-1); | |||
} | |||
.ui.pink.button:active, | |||
.ui.pink.buttons .button:active { | |||
background: var(--color-pink-dark-2); | |||
} | |||
.ui.basic.pink.buttons .button, | |||
.ui.basic.pink.button, | |||
.ui.basic.pink.buttons .button:focus, | |||
.ui.basic.pink.button:focus { | |||
color: var(--color-pink); | |||
border-color: var(--color-pink); | |||
} | |||
.ui.basic.pink.buttons .button:hover, | |||
.ui.basic.pink.button:hover { | |||
color: var(--color-pink-dark-1); | |||
border-color: var(--color-pink-dark-1); | |||
} | |||
.ui.basic.pink.buttons .button:active, | |||
.ui.basic.pink.button:active { | |||
color: var(--color-pink-dark-2); | |||
border-color: var(--color-pink-dark-2); | |||
} | |||
/* brown */ | |||
.ui.brown.labels .label, | |||
.ui.ui.ui.brown.label, | |||
.ui.brown.button, | |||
.ui.brown.buttons .button, | |||
.ui.brown.button:focus, | |||
.ui.brown.buttons .button:focus { | |||
background: var(--color-brown); | |||
} | |||
.ui.brown.button:hover, | |||
.ui.brown.buttons .button:hover { | |||
background: var(--color-brown-dark-1); | |||
} | |||
.ui.brown.button:active, | |||
.ui.brown.buttons .button:active { | |||
background: var(--color-brown-dark-2); | |||
.delete-button, | |||
.delete-button:hover { | |||
color: var(--color-red); | |||
} | |||
.ui.basic.brown.buttons .button, | |||
.ui.basic.brown.button, | |||
.ui.basic.brown.buttons .button:focus, | |||
.ui.basic.brown.button:focus { | |||
color: var(--color-brown); | |||
border-color: var(--color-brown); | |||
} | |||
/* btn is a plain button without any opinionated styling, it only uses flex for vertical alignment like ".ui.button" in base.css */ | |||
.ui.basic.brown.buttons .button:hover, | |||
.ui.basic.brown.button:hover { | |||
color: var(--color-brown-dark-1); | |||
border-color: var(--color-brown-dark-1); | |||
.btn { | |||
background: transparent; | |||
border-radius: var(--border-radius); | |||
border: none; | |||
color: inherit; | |||
margin: 0; | |||
padding: 0; | |||
} | |||
.ui.basic.brown.buttons .button:active, | |||
.ui.basic.brown.button:active { | |||
color: var(--color-brown-dark-2); | |||
border-color: var(--color-brown-dark-2); | |||
.btn:hover, | |||
.btn:active { | |||
background: none; | |||
border: none; | |||
} | |||
/* negative */ | |||
.ui.negative.buttons .button, | |||
.ui.negative.button, | |||
.ui.negative.buttons .button:focus, | |||
.ui.negative.button:focus { | |||
background: var(--color-red); | |||
a.btn, | |||
a.btn:hover { | |||
color: inherit; | |||
} | |||
.ui.negative.buttons .button:hover, | |||
.ui.negative.button:hover { | |||
background: var(--color-red-dark-1); | |||
} | |||
/* By default, Fomantic UI doesn't support "bordered" buttons group, but Gitea would like to use it. | |||
And the default buttons always have borders now (not the same as Fomantic UI's default buttons, see above). | |||
It needs some tricks to tweak the left/right borders with active state */ | |||
.ui.negative.buttons .button:active, | |||
.ui.negative.button:active { | |||
background: var(--color-red-dark-2); | |||
.ui.buttons .button { | |||
border-right: none; | |||
flex: 1 0 auto; | |||
border-radius: 0; | |||
margin: 0; | |||
} | |||
.ui.basic.negative.buttons .button, | |||
.ui.basic.negative.button, | |||
.ui.basic.negative.buttons .button:focus, | |||
.ui.basic.negative.button:focus { | |||
color: var(--color-red); | |||
border-color: var(--color-red); | |||
.ui.buttons .button:first-child { | |||
border-left: none; | |||
margin-left: 0; | |||
border-top-left-radius: 0.28571429rem; | |||
border-bottom-left-radius: 0.28571429rem; | |||
} | |||
.ui.basic.negative.buttons .button:hover, | |||
.ui.basic.negative.button:hover { | |||
color: var(--color-red-dark-1); | |||
border-color: var(--color-red-dark-1); | |||
.ui.buttons .button:last-child { | |||
border-top-right-radius: 0.28571429rem; | |||
border-bottom-right-radius: 0.28571429rem; | |||
} | |||
.ui.basic.negative.buttons .button:active, | |||
.ui.basic.negative.button:active { | |||
color: var(--color-red-dark-2); | |||
border-color: var(--color-red-dark-2); | |||
.ui.buttons .button:hover { | |||
border-color: var(--color-secondary-dark-2); | |||
} | |||
/* positive */ | |||
.ui.positive.buttons .button, | |||
.ui.positive.button, | |||
.ui.positive.buttons .button:focus, | |||
.ui.positive.button:focus { | |||
background: var(--color-green); | |||
.ui.buttons .button:hover + .button { | |||
border-left: 1px solid var(--color-secondary-dark-2); | |||
} | |||
.ui.positive.buttons .button:hover, | |||
.ui.positive.button:hover { | |||
background: var(--color-green-dark-1); | |||
/* TODO: these "tw-hidden" selectors are only used by "blame.tmpl" buttons: Raw/Normal View/History/Unescape, need to be refactored to a clear solution later */ | |||
.ui.buttons .button:first-child, | |||
.ui.buttons .button.tw-hidden:first-child + .button { | |||
border-left: 1px solid var(--color-light-border); | |||
} | |||
.ui.positive.buttons .button:active, | |||
.ui.positive.button:active { | |||
background: var(--color-green-dark-2); | |||
.ui.buttons .button:last-child, | |||
.ui.buttons .button:nth-last-child(2):has(+ .button.tw-hidden) { | |||
border-right: 1px solid var(--color-light-border); | |||
} | |||
.ui.basic.positive.buttons .button, | |||
.ui.basic.positive.button, | |||
.ui.basic.positive.buttons .button:focus, | |||
.ui.basic.positive.button:focus { | |||
color: var(--color-green); | |||
border-color: var(--color-green); | |||
.ui.buttons .button.active { | |||
border-left: 1px solid var(--color-light-border); | |||
border-right: 1px solid var(--color-light-border); | |||
} | |||
.ui.basic.positive.buttons .button:hover, | |||
.ui.basic.positive.button:hover { | |||
color: var(--color-green-dark-1); | |||
border-color: var(--color-green-dark-1); | |||
.ui.buttons .button.active + .button { | |||
border-left: none; | |||
} | |||
.ui.basic.positive.buttons .button:active, | |||
.ui.basic.positive.button:active { | |||
color: var(--color-green-dark-2); | |||
border-color: var(--color-green-dark-2); | |||
/* apply the vertical padding of .compact to non-compact buttons when they contain a svg as they | |||
would otherwise appear too large. Seen on "RSS Feed" button on repo releases tab. */ | |||
.ui.small.button:not(.compact):has(.svg) { | |||
padding-top: 0.58928571em; | |||
padding-bottom: 0.58928571em; | |||
} |
@@ -16,7 +16,7 @@ | |||
.ui.comments .comment { | |||
position: relative; | |||
background: none; | |||
margin: 0.5em 0 0; | |||
margin: 3px 0 0; | |||
padding: 0.5em 0 0; | |||
border: none; | |||
border-top: none; |
@@ -2,12 +2,16 @@ | |||
margin: 10px 0; | |||
height: 0; | |||
font-weight: var(--font-weight-medium); | |||
text-transform: uppercase; | |||
color: var(--color-text); | |||
font-size: 1rem; | |||
width: 100%; | |||
} | |||
h4.divider { | |||
margin-top: 1.25rem; | |||
margin-bottom: 1.25rem; | |||
} | |||
.divider:not(.divider-text) { | |||
border-top: 1px solid var(--color-secondary); | |||
} |
@@ -6,10 +6,16 @@ | |||
margin-top: var(--page-spacing); | |||
} | |||
/* small options menu on the left, used in settings/admin pages */ | |||
.flex-container-nav { | |||
width: 240px; | |||
} | |||
/* wide sidebar on the right, used in frontpage */ | |||
.flex-container-sidebar { | |||
width: 35%; | |||
} | |||
.flex-container-main { | |||
flex: 1; | |||
min-width: 0; /* make the "text truncate" work, otherwise the flex axis is not limited and the text just overflows */ | |||
@@ -19,7 +25,9 @@ | |||
.flex-container { | |||
flex-direction: column; | |||
} | |||
.flex-container-nav { | |||
.flex-container-nav, | |||
.flex-container-sidebar { | |||
order: -1; | |||
width: auto; | |||
} | |||
} |
@@ -9,7 +9,6 @@ | |||
font-family: var(--fonts-regular); | |||
font-weight: var(--font-weight-medium); | |||
line-height: 1.28571429; | |||
text-transform: none; | |||
} | |||
.ui.header:first-child { |
@@ -5,12 +5,12 @@ | |||
display: inline-flex; | |||
align-items: center; | |||
gap: .25rem; | |||
min-width: 0; | |||
vertical-align: middle; | |||
line-height: 1; | |||
background: var(--color-label-bg); | |||
color: var(--color-label-text); | |||
padding: 0.3em 0.5em; | |||
text-transform: none; | |||
font-size: 0.85714286rem; | |||
font-weight: var(--font-weight-medium); | |||
border: 0 solid transparent; |
@@ -0,0 +1,802 @@ | |||
.ui.menu { | |||
display: flex; | |||
margin: 1rem 0; | |||
font-family: var(--fonts-regular); | |||
font-weight: var(--font-weight-normal); | |||
background: var(--color-menu); | |||
border: 1px solid var(--color-secondary); | |||
border-radius: 0.28571429rem; | |||
min-height: 2.85714286em; | |||
font-size: 1rem; | |||
} | |||
.ui.menu:first-child { | |||
margin-top: 0; | |||
} | |||
.ui.menu:last-child { | |||
margin-bottom: 0; | |||
} | |||
.ui.menu .menu { | |||
margin: 0; | |||
} | |||
.ui.menu:not(.vertical) > .menu { | |||
display: flex; | |||
} | |||
.ui.menu:not(.vertical) .item { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.ui.menu .item { | |||
position: relative; | |||
vertical-align: middle; | |||
line-height: var(--line-height-default); | |||
text-decoration: none; | |||
flex: 0 0 auto; | |||
background: none; | |||
padding: 0.92857143em 1.14285714em; | |||
color: var(--color-text); | |||
font-weight: var(--font-weight-normal); | |||
} | |||
.ui.menu > .item:first-child { | |||
border-radius: 0.28571429rem 0 0 0.28571429rem; | |||
} | |||
.ui.menu .item::before { | |||
position: absolute; | |||
content: ""; | |||
top: 0; | |||
right: 0; | |||
height: 100%; | |||
width: 1px; | |||
background: var(--color-secondary); | |||
} | |||
.ui.menu .item > .svg { | |||
margin-right: 0.35em; | |||
} | |||
.ui.menu .item > a:not(.ui), | |||
.ui.menu .item > p:only-child { | |||
line-height: 1.3; | |||
} | |||
.ui.menu .item > p:first-child { | |||
margin-top: 0; | |||
} | |||
.ui.menu .item > p:last-child { | |||
margin-bottom: 0; | |||
} | |||
.ui.menu .item > i.icon { | |||
opacity: 0.9; | |||
float: none; | |||
margin: 0 0.35714286em 0 0; | |||
} | |||
.ui.menu:not(.vertical) .item > .button { | |||
position: relative; | |||
top: 0; | |||
margin: -0.5em 0; | |||
padding: 0.58928571em 1.125em; | |||
font-size: 1em; | |||
} | |||
.ui.menu > .grid, | |||
.ui.menu > .container { | |||
display: flex; | |||
align-items: inherit; | |||
flex-direction: inherit; | |||
} | |||
.ui.menu .item > .input { | |||
width: 100%; | |||
} | |||
.ui.menu:not(.vertical) .item > .input { | |||
position: relative; | |||
top: 0; | |||
margin: -0.5em 0; | |||
} | |||
.ui.menu .item > .input input { | |||
font-size: 1em; | |||
padding-top: 0.57142857em; | |||
padding-bottom: 0.57142857em; | |||
} | |||
.ui.menu .header.item, | |||
.ui.vertical.menu .header.item { | |||
margin: 0; | |||
font-size: 1.1em; | |||
background: var(--color-box-header); | |||
font-weight: var(--font-weight-medium); | |||
} | |||
.ui.vertical.menu .item > .header:not(.ui) { | |||
margin: 0 0 0.5em; | |||
font-size: 1em; | |||
font-weight: var(--font-weight-medium); | |||
} | |||
.ui.menu .item > i.dropdown.icon { | |||
padding: 0; | |||
float: right; | |||
margin: 0 0 0 1em; | |||
} | |||
.ui.menu .dropdown.item .menu { | |||
min-width: calc(100% - 1px); | |||
border-radius: 0 0 0.28571429rem 0.28571429rem; | |||
background: var(--color-body); | |||
margin: 0; | |||
flex-direction: column !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .item { | |||
margin: 0; | |||
text-align: left; | |||
font-size: 1em !important; | |||
padding: 0.78571429em 1.14285714em !important; | |||
background: transparent !important; | |||
color: var(--color-text) !important; | |||
font-weight: var(--font-weight-normal) !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .item:hover { | |||
color: var(--color-text) !important; | |||
background: var(--color-hover) !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .selected.item { | |||
color: var(--color-text) !important; | |||
background: var(--color-hover) !important; | |||
} | |||
.ui.menu .ui.dropdown .menu > .active.item { | |||
color: var(--color-text) !important; | |||
background: var(--color-active) !important; | |||
font-weight: var(--font-weight-medium) !important; | |||
} | |||
.ui.menu .ui.dropdown.item .menu .item { | |||
width: 100%; | |||
} | |||
.ui.menu .ui.dropdown.item .menu .item:not(.filtered) { | |||
display: block; | |||
} | |||
.ui.menu .ui.dropdown .menu > .item > i.icon:not(.dropdown) { | |||
display: inline-block; | |||
font-size: 1em !important; | |||
float: none; | |||
margin: 0 0.75em 0 0 !important; | |||
} | |||
.ui.secondary.menu .dropdown.item > .menu { | |||
border-radius: 0.28571429rem; | |||
margin-top: 0.35714286em; | |||
} | |||
.ui.menu .pointing.dropdown.item .menu { | |||
margin-top: 0.75em; | |||
} | |||
.ui.menu .item > .label:not(.floating) { | |||
margin-left: 1em; | |||
padding: 0.3em 0.78571429em; | |||
} | |||
.ui.vertical.menu .item > .label { | |||
margin-top: -0.15em; | |||
margin-bottom: -0.15em; | |||
padding: 0.3em 0.78571429em; | |||
float: right; | |||
text-align: center; | |||
} | |||
.ui.menu .item > .floating.label { | |||
padding: 0.3em 0.78571429em; | |||
} | |||
.ui.menu .item > .label { | |||
background: var(--color-label-bg); | |||
color: var(--color-label-text); | |||
} | |||
.ui.menu .item > .image.label img { | |||
margin: -0.2833em 0.8em -0.2833em -0.8em; | |||
height: 1.5666em; | |||
} | |||
.ui.menu .item > img:not(.ui) { | |||
display: inline-block; | |||
vertical-align: middle; | |||
margin: -0.3em 0; | |||
width: 2.5em; | |||
} | |||
.ui.vertical.menu .item > img:not(.ui):only-child { | |||
display: block; | |||
max-width: 100%; | |||
width: auto; | |||
} | |||
.ui.menu .list .item::before { | |||
background: none !important; | |||
} | |||
@media only screen and (max-width: 767.98px) { | |||
.ui.menu > .ui.container { | |||
width: 100% !important; | |||
margin-left: 0 !important; | |||
margin-right: 0 !important; | |||
} | |||
} | |||
.ui.menu .dropdown.item:hover, | |||
.ui.menu a.item:hover { | |||
cursor: pointer; | |||
} | |||
.ui.menu a.item:active { | |||
color: var(--color-text); | |||
background: none; | |||
} | |||
.ui.menu .active.item { | |||
color: var(--color-text); | |||
background: var(--color-active); | |||
font-weight: var(--font-weight-normal); | |||
} | |||
.ui.menu .active.item > i.icon { | |||
opacity: 1; | |||
} | |||
.ui.ui.menu .item.disabled { | |||
cursor: default; | |||
background-color: transparent; | |||
pointer-events: none; | |||
opacity: var(--opacity-disabled); | |||
} | |||
.ui.menu:not(.vertical) .left.item, | |||
.ui.menu:not(.vertical) .left.menu { | |||
display: flex; | |||
margin-right: auto !important; | |||
} | |||
.ui.menu:not(.vertical) .right.item, | |||
.ui.menu:not(.vertical) .right.menu { | |||
display: flex; | |||
margin-left: auto !important; | |||
} | |||
.ui.menu:not(.vertical) :not(.dropdown) > .left.menu, | |||
.ui.menu:not(.vertical) :not(.dropdown) > .right.menu { | |||
display: inherit; | |||
} | |||
.ui.menu:not(.vertical) .center.item { | |||
display: flex; | |||
margin-left: auto !important; | |||
margin-right: auto !important; | |||
} | |||
.ui.menu .right.item::before, | |||
.ui.menu .right.menu > .item::before { | |||
right: auto; | |||
left: 0; | |||
} | |||
.ui.menu .center.item:last-child::before { | |||
display: none; | |||
} | |||
.ui.vertical.menu { | |||
display: block; | |||
flex-direction: column; | |||
background: var(--color-menu); | |||
width: 15rem; | |||
} | |||
.ui.vertical.menu .item { | |||
display: block; | |||
background: none; | |||
border-top: none; | |||
border-right: none; | |||
} | |||
.ui.vertical.menu > .item:first-child { | |||
border-radius: 0.28571429rem 0.28571429rem 0 0; | |||
} | |||
.ui.vertical.menu > .item:last-child { | |||
border-radius: 0 0 0.28571429rem 0.28571429rem; | |||
} | |||
.ui.vertical.menu .item > i.icon { | |||
width: 1.18em; | |||
float: right; | |||
margin: 0 0 0 0.5em; | |||
} | |||
.ui.vertical.menu .item > .label + i.icon { | |||
float: none; | |||
margin: 0 0.5em 0 0; | |||
} | |||
.ui.vertical.menu .item::before { | |||
position: absolute; | |||
content: ""; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 1px; | |||
background: var(--color-secondary); | |||
} | |||
.ui.vertical.menu .item:first-child::before { | |||
display: none !important; | |||
} | |||
.ui.vertical.menu .item > .menu { | |||
margin: 0.5em -1.14285714em 0; | |||
} | |||
.ui.vertical.menu .menu .item { | |||
background: none; | |||
padding: 0.5em 1.33333333em; | |||
font-size: 0.85714286em; | |||
color: var(--color-text-light-2); | |||
} | |||
.ui.vertical.menu .item .menu .item { | |||
color: var(--color-text-light-2); | |||
text-indent: 16px; | |||
} | |||
.ui.vertical.menu .item .menu .item:hover, | |||
.ui.vertical.menu .item .menu a.item:hover { | |||
color: var(--color-text-light-1); | |||
} | |||
.ui.vertical.menu .item .menu .active.item { | |||
background-color: transparent; | |||
font-weight: var(--font-weight-medium); | |||
color: var(--color-text); | |||
} | |||
.ui.vertical.menu .item .menu a.item:hover { | |||
color: var(--color-text); | |||
} | |||
.ui.vertical.menu .menu .item::before { | |||
display: none; | |||
} | |||
.ui.vertical.menu .active.item { | |||
border-radius: 0; | |||
} | |||
.ui.vertical.menu > .active.item:first-child { | |||
border-radius: 0.28571429rem 0.28571429rem 0 0; | |||
} | |||
.ui.vertical.menu > .active.item:last-child { | |||
border-radius: 0 0 0.28571429rem 0.28571429rem; | |||
} | |||
.ui.vertical.menu > .active.item:only-child { | |||
border-radius: 0.28571429rem; | |||
} | |||
.ui.vertical.menu .active.item .menu .active.item { | |||
border-left: none; | |||
} | |||
.ui.tabular.menu { | |||
border-radius: 0; | |||
border: none; | |||
background: none transparent; | |||
border-bottom: 1px solid var(--color-secondary); | |||
} | |||
.ui.tabular.fluid.menu { | |||
width: calc(100% + 2px) !important; | |||
} | |||
.ui.tabular.menu .item { | |||
background: transparent; | |||
border-bottom: none; | |||
border-left: 1px solid transparent; | |||
border-right: 1px solid transparent; | |||
border-top: 2px solid transparent; | |||
color: var(--color-text-light-2); | |||
} | |||
.ui.tabular.menu .item::before { | |||
display: none; | |||
} | |||
.ui.tabular.menu .item:hover { | |||
background-color: transparent; | |||
} | |||
.ui.tabular.menu .active.item, | |||
.ui.tabular.menu .active.item:hover { | |||
background: var(--color-body); | |||
border-top-width: 1px; | |||
border-color: var(--color-secondary); | |||
font-weight: var(--font-weight-medium); | |||
margin-bottom: -1px; | |||
border-radius: 0.28571429rem 0.28571429rem 0 0 !important; | |||
} | |||
.ui.tabular.menu + .attached:not(.top).segment, | |||
.ui.tabular.menu + .attached:not(.top).segment + .attached:not(.top).segment { | |||
border-top: none; | |||
margin-left: 0; | |||
margin-top: 0; | |||
margin-right: 0; | |||
width: 100%; | |||
} | |||
.ui.tabular.menu .active.dropdown.item { | |||
margin-bottom: 0; | |||
border-left: 1px solid transparent; | |||
border-right: 1px solid transparent; | |||
border-top: 2px solid transparent; | |||
border-bottom: none; | |||
} | |||
.ui.pagination.menu { | |||
margin: 0; | |||
display: inline-flex; | |||
vertical-align: middle; | |||
} | |||
.ui.pagination.menu .item:last-child { | |||
border-radius: 0 0.28571429rem 0.28571429rem 0; | |||
} | |||
.ui.compact.menu .item:last-child { | |||
border-radius: 0 0.28571429rem 0.28571429rem 0; | |||
} | |||
.ui.pagination.menu .item:last-child::before { | |||
display: none; | |||
} | |||
.ui.pagination.menu .item { | |||
min-width: 3em; | |||
text-align: center; | |||
} | |||
.ui.pagination.menu .icon.item i.icon { | |||
vertical-align: top; | |||
} | |||
.ui.pagination.menu .active.item, | |||
.ui.pagination.menu .active.item:hover { | |||
border-top: none; | |||
padding-top: 0.92857143em; | |||
color: var(--color-text); | |||
background: var(--color-active); | |||
} | |||
@media (max-width: 767.98px) { | |||
.ui.pagination.menu .item:not(.active,.navigation), | |||
.ui.pagination.menu .item.navigation span.navigation_label { | |||
display: none; | |||
} | |||
} | |||
.ui.pagination.menu.narrow .item { | |||
padding-left: 8px; | |||
padding-right: 8px; | |||
min-width: 1em; | |||
text-align: center; | |||
} | |||
.ui.pagination.menu.narrow .item .icon { | |||
margin-right: 0; | |||
} | |||
.ui.secondary.menu { | |||
background: none; | |||
margin-left: 0; | |||
margin-right: 0; | |||
gap: .35714286em; | |||
border-radius: 0; | |||
border: none; | |||
} | |||
.ui.secondary.menu .item { | |||
align-self: center; | |||
border: none; | |||
padding: 0.78571429em 0.92857143em; | |||
margin: 0; | |||
background: none; | |||
border-radius: 0.28571429rem; | |||
} | |||
.ui.secondary.menu .item::before { | |||
display: none !important; | |||
} | |||
.ui.secondary.menu .header.item { | |||
border-radius: 0; | |||
border-right: none; | |||
background: none transparent; | |||
} | |||
.ui.secondary.menu .item > img:not(.ui) { | |||
margin: 0; | |||
} | |||
.ui.secondary.menu .dropdown.item:hover, | |||
.ui.secondary.menu a.item:hover { | |||
color: var(--color-text); | |||
background: var(--color-hover); | |||
} | |||
.ui.secondary.menu .active.item, | |||
.ui.secondary.menu .active.item:hover { | |||
color: var(--color-text-dark); | |||
background: var(--color-active); | |||
border-radius: 0.28571429rem; | |||
} | |||
.ui.secondary.item.menu { | |||
margin-left: 0; | |||
margin-right: 0; | |||
} | |||
.ui.secondary.item.menu .item:last-child { | |||
margin-right: 0; | |||
} | |||
.ui.vertical.secondary.menu .item:not(.dropdown) > .menu { | |||
margin: 0 -0.92857143em; | |||
} | |||
.ui.vertical.secondary.menu .item:not(.dropdown) > .menu > .item { | |||
margin: 0; | |||
padding: 0.5em 1.33333333em; | |||
} | |||
.ui.secondary.vertical.menu > .item { | |||
border: none; | |||
margin: 0 0 0.35714286em; | |||
border-radius: 0.28571429rem !important; | |||
} | |||
.ui.secondary.vertical.menu > .header.item { | |||
border-radius: 0; | |||
} | |||
.ui.vertical.secondary.menu .item > .menu .item { | |||
background-color: transparent; | |||
} | |||
.ui.secondary.pointing.menu { | |||
margin-left: 0; | |||
margin-right: 0; | |||
border-bottom: 2px solid var(--color-secondary); | |||
} | |||
.ui.secondary.pointing.menu .item { | |||
border-bottom-color: transparent; | |||
border-bottom-style: solid; | |||
border-radius: 0; | |||
align-self: flex-end; | |||
margin: 0 0 -2px; | |||
padding: 0.85714286em 1.14285714em; | |||
border-bottom-width: 2px; | |||
} | |||
.ui.secondary.pointing.menu .ui.dropdown .menu .item { | |||
border-bottom-width: 0; | |||
} | |||
.ui.secondary.pointing.menu .item > .label:not(.floating) { | |||
margin-top: -0.3em; | |||
margin-bottom: -0.3em; | |||
} | |||
.ui.secondary.pointing.menu .item > .circular.label { | |||
margin-top: -0.5em; | |||
margin-bottom: -0.5em; | |||
} | |||
.ui.secondary.pointing.menu .header.item { | |||
color: var(--color-text) !important; | |||
} | |||
.ui.secondary.pointing.menu .item::after { | |||
display: none; | |||
} | |||
.ui.secondary.pointing.menu .dropdown.item:hover, | |||
.ui.secondary.pointing.menu a.item:hover { | |||
background-color: transparent; | |||
color: var(--color-text); | |||
} | |||
.ui.secondary.pointing.menu .dropdown.item:active, | |||
.ui.secondary.pointing.menu a.item:active { | |||
background-color: transparent; | |||
border-color: var(--color-secondary); | |||
} | |||
.ui.secondary.pointing.menu .active.item { | |||
background-color: transparent; | |||
border-color: currentcolor; | |||
font-weight: var(--font-weight-medium); | |||
} | |||
.ui.secondary.pointing.menu .active.item, | |||
.ui.secondary.pointing.menu .active.item:hover, | |||
.ui.secondary.pointing.menu .dropdown.item:hover { | |||
color: var(--color-text-dark); | |||
} | |||
.ui.secondary.pointing.menu .active.dropdown.item { | |||
border-color: transparent; | |||
} | |||
@media only screen and (max-width: 767.98px) { | |||
.ui.stackable.menu { | |||
flex-direction: column; | |||
} | |||
.ui.stackable.menu .item { | |||
width: 100% !important; | |||
} | |||
.ui.stackable.menu .left.menu, | |||
.ui.stackable.menu .left.item { | |||
margin-right: 0 !important; | |||
} | |||
.ui.stackable.menu .right.menu, | |||
.ui.stackable.menu .right.item { | |||
margin-left: 0 !important; | |||
} | |||
.ui.stackable.menu .center.item { | |||
margin-left: 0 !important; | |||
margin-right: 0 !important; | |||
} | |||
.ui.stackable.menu .right.menu, | |||
.ui.stackable.menu .left.menu { | |||
flex-direction: column; | |||
} | |||
} | |||
.ui.floated.menu { | |||
float: left; | |||
margin: 0 0.5rem 0 0; | |||
} | |||
.ui.floated.menu .item:last-child::before { | |||
display: none; | |||
} | |||
.ui.right.floated.menu { | |||
float: right; | |||
margin: 0 0 0 0.5rem; | |||
} | |||
.ui.borderless.menu .item::before, | |||
.ui.borderless.menu .item .menu .item::before, | |||
.ui.menu .borderless.item::before { | |||
background: none !important; | |||
} | |||
.ui.compact.menu { | |||
display: inline-flex; | |||
margin: 0; | |||
vertical-align: middle; | |||
} | |||
.ui.compact.vertical.menu { | |||
display: inline-block; | |||
width: auto !important; | |||
} | |||
.ui.compact.menu:not(.secondary) .item:last-child { | |||
border-radius: 0 0.28571429rem 0.28571429rem 0; | |||
} | |||
.ui.compact.menu .item:last-child::before { | |||
display: none; | |||
} | |||
.ui.compact.vertical.menu .item:last-child::before { | |||
display: block; | |||
} | |||
.ui.menu.fluid, | |||
.ui.vertical.menu.fluid { | |||
width: 100% !important; | |||
} | |||
.ui.item.menu, | |||
.ui.item.menu .item { | |||
width: 100%; | |||
padding-left: 0 !important; | |||
padding-right: 0 !important; | |||
margin-left: 0 !important; | |||
margin-right: 0 !important; | |||
text-align: center; | |||
justify-content: center; | |||
} | |||
.ui.attached.item.menu:not(.tabular) { | |||
margin: 0 -1px !important; | |||
} | |||
.ui.item.menu .item:last-child::before { | |||
display: none; | |||
} | |||
.ui.menu.two.item .item { | |||
width: 50%; | |||
} | |||
.ui.pointing.menu .item::after { | |||
visibility: hidden; | |||
position: absolute; | |||
content: ""; | |||
top: 100%; | |||
left: 50%; | |||
transform: translateX(-50%) translateY(-50%) rotate(45deg); | |||
background: none; | |||
margin: 0.5px 0 0; | |||
width: 0.57142857em; | |||
height: 0.57142857em; | |||
border: none; | |||
border-bottom: 1px solid var(--color-secondary); | |||
border-right: 1px solid var(--color-secondary); | |||
z-index: 2; | |||
} | |||
.ui.pointing.menu .ui.dropdown .menu .item::after { | |||
display: none; | |||
} | |||
.ui.pointing.menu .active.item::after { | |||
visibility: visible; | |||
} | |||
.ui.pointing.menu .active.dropdown.item::after { | |||
visibility: hidden; | |||
} | |||
.ui.pointing.menu .dropdown.active.item::after, | |||
.ui.pointing.menu .active.item .menu .active.item::after { | |||
display: none; | |||
} | |||
.ui.pointing.menu .active.item::after, | |||
.ui.pointing.menu .active.item:hover::after { | |||
background-color: var(--color-active); | |||
} | |||
.ui.attached.menu { | |||
top: 0; | |||
bottom: 0; | |||
border-radius: 0; | |||
margin: 0 -1px; | |||
width: calc(100% + 2px); | |||
max-width: calc(100% + 2px); | |||
} | |||
.ui.attached + .ui.attached.menu:not(.top) { | |||
border-top: none; | |||
} | |||
.ui[class*="top attached"].menu { | |||
bottom: 0; | |||
margin-bottom: 0; | |||
top: 0; | |||
margin-top: 1rem; | |||
border-radius: 0.28571429rem 0.28571429rem 0 0; | |||
} | |||
.ui.menu[class*="top attached"]:first-child { | |||
margin-top: 0; | |||
} | |||
.ui.top.attached.menu > .item:first-child { | |||
border-radius: 0.28571429rem 0 0; | |||
} | |||
.ui.attached.menu:not(.tabular) { | |||
border: 1px solid var(--color-secondary); | |||
} | |||
.ui.attached.tabular.menu { | |||
margin-left: 0; | |||
margin-right: 0; | |||
width: 100%; | |||
} | |||
.ui.mini.menu, | |||
.ui.mini.menu .dropdown, | |||
.ui.mini.menu .dropdown .menu > .item { | |||
font-size: 0.78571429rem; | |||
} | |||
.ui.mini.vertical.menu:not(.icon) { | |||
width: 9rem; | |||
} | |||
.ui.tiny.menu, | |||
.ui.tiny.menu .dropdown, | |||
.ui.tiny.menu .dropdown .menu > .item { | |||
font-size: 0.85714286rem; | |||
} | |||
.ui.tiny.vertical.menu:not(.icon) { | |||
width: 11rem; | |||
} | |||
.ui.small.menu, | |||
.ui.small.menu .dropdown, | |||
.ui.small.menu .dropdown .menu > .item { | |||
font-size: 0.92857143rem; | |||
} | |||
.ui.small.vertical.menu:not(.icon) { | |||
width: 13rem; | |||
} | |||
.ui .menu:not(.vertical) .item > .button.small { | |||
font-size: 0.92857143rem; | |||
} | |||
.ui.segment .ui.tabular.menu .active.item, | |||
.ui.segment .ui.tabular.menu .active.item:hover { | |||
background: var(--color-box-body); | |||
} |
@@ -10,6 +10,10 @@ | |||
top: 1.2em; | |||
} | |||
.ui.modal > .close.inside { | |||
color: inherit; | |||
} | |||
.ui.modal > .close.icon[height="16"] { | |||
top: 0.7em; /* fomantic uses absolute layout, so if we have special icon size, it needs this trick to align vertically */ | |||
color: var(--color-text-dark); |
@@ -654,15 +654,15 @@ td .commit-summary { | |||
padding: 2px .5rem; | |||
} | |||
.repository.view.issue .issue-title .index { | |||
.issue-title .index { | |||
color: var(--color-text-light-2); | |||
} | |||
.repository.view.issue .issue-title .label { | |||
.issue-title .label { | |||
margin-right: 10px; | |||
} | |||
.repository.view.issue .issue-title .edit-zone { | |||
.issue-title .edit-zone { | |||
margin-top: 10px; | |||
} | |||
@@ -913,6 +913,9 @@ td .commit-summary { | |||
.repository.view.issue .comment-list .ui.comments { | |||
max-width: 100%; | |||
display: flex; | |||
flex-direction: column; | |||
gap: 3px; | |||
} | |||
.repository.view.issue .comment-list .comment > .content > div:first-child { | |||
@@ -928,6 +931,11 @@ td .commit-summary { | |||
.repository.view.issue .comment-list .comment .comment-container { | |||
border: 1px solid var(--color-secondary); | |||
border-radius: var(--border-radius); | |||
background: var(--color-box-body); | |||
} | |||
.repository.view.issue .comment-list .conversation-holder .comment .comment-container { | |||
border: none; | |||
} | |||
@media (max-width: 767.98px) { | |||
@@ -1042,30 +1050,6 @@ td .commit-summary { | |||
margin-left: 42px; | |||
} | |||
.repository.view.issue .comment-list .comment-code-cloud .segment.reactions { | |||
margin-top: 16px !important; | |||
margin-bottom: -8px !important; | |||
border-top: none !important; | |||
} | |||
.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label { | |||
border: 1px solid; | |||
padding: 5px 8px !important; | |||
margin: 0 2px; | |||
border-radius: var(--border-radius); | |||
border-color: var(--color-secondary-dark-1) !important; | |||
} | |||
.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label.basic.primary { | |||
background-color: var(--color-reaction-active-bg) !important; | |||
border-color: var(--color-primary-alpha-80) !important; | |||
} | |||
.repository.view.issue .comment-list .comment-code-cloud .segment.reactions .ui.label.basic.primary:hover { | |||
background-color: var(--color-reaction-hover-bg) !important; | |||
border-color: var(--color-primary-alpha-80) !important; | |||
} | |||
.repository.view.issue .comment-list .comment-code-cloud button.comment-form-reply { | |||
margin: 0; | |||
} | |||
@@ -1180,14 +1164,6 @@ td .commit-summary { | |||
font-size: 14px; | |||
} | |||
.repository.compare.pull .title .issue-title { | |||
margin-bottom: 0.5rem; | |||
} | |||
.repository.compare.pull .title .issue-title .index { | |||
color: var(--color-text-light-2); | |||
} | |||
.repository .ui.dropdown.filter > .menu { | |||
margin-top: 1px; | |||
} | |||
@@ -1902,98 +1878,6 @@ td .commit-summary { | |||
border-bottom: 1px solid var(--color-warning-border); | |||
} | |||
.repository .segment.reactions.dropdown .menu, | |||
.repository .select-reaction.dropdown .menu { | |||
right: 0 !important; | |||
left: auto !important; | |||
min-width: 170px; | |||
} | |||
.repository .segment.reactions.dropdown .menu > .header, | |||
.repository .select-reaction.dropdown .menu > .header { | |||
margin: 0.75rem 0 0.5rem; | |||
} | |||
.repository .segment.reactions.dropdown .menu > .item, | |||
.repository .select-reaction.dropdown .menu > .item { | |||
float: left; | |||
margin: 4px; | |||
font-size: 20px; | |||
width: 34px; | |||
height: 34px; | |||
min-height: 0 !important; | |||
border-radius: var(--border-radius); | |||
display: flex !important; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.repository .segment.reactions { | |||
padding: 0; | |||
display: flex; | |||
border: none !important; | |||
border-top: 1px solid var(--color-secondary) !important; | |||
width: 100% !important; | |||
max-width: 100% !important; | |||
margin: 0 !important; | |||
border-radius: 0 0 var(--border-radius) var(--border-radius); | |||
} | |||
.repository .segment.reactions .ui.label { | |||
max-height: 40px; | |||
padding: 8px 16px !important; | |||
display: flex !important; | |||
align-items: center; | |||
border: 0; | |||
border-right: 1px solid; | |||
border-radius: 0; | |||
margin: 0; | |||
font-size: 12px; | |||
font-weight: var(--font-weight-normal); | |||
border-color: var(--color-secondary) !important; | |||
background: var(--color-reaction-bg); | |||
} | |||
.repository .segment.reactions .ui.label:first-of-type { | |||
border-bottom-left-radius: 3px; | |||
} | |||
.repository .segment.reactions .ui.label.disabled { | |||
cursor: default; | |||
opacity: 1; | |||
} | |||
.repository .segment.reactions .ui.label.basic.primary { | |||
color: var(--color-primary) !important; | |||
background-color: var(--color-reaction-active-bg) !important; | |||
border-color: var(--color-secondary-dark-1) !important; | |||
} | |||
.repository .segment.reactions .ui.label.basic:hover { | |||
background-color: var(--color-reaction-hover-bg) !important; | |||
} | |||
.repository .segment.reactions .reaction-count { | |||
margin-left: 0.5rem; | |||
} | |||
.repository .segment.reactions .select-reaction { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.repository .segment.reactions .select-reaction a { | |||
padding: 0 14px; | |||
} | |||
.repository .segment.reactions .select-reaction:not(.active) a { | |||
display: none; | |||
} | |||
.repository .segment.reactions:hover .select-reaction a { | |||
display: block; | |||
} | |||
.repository .ui.fluid.action.input .ui.search.action.input { | |||
flex: auto; | |||
} | |||
@@ -2187,11 +2071,6 @@ td .commit-summary { | |||
padding: 10px 0 0; | |||
} | |||
.ui.vertical.menu .header.item { | |||
font-size: 1.1em; | |||
background: var(--color-box-header); | |||
} | |||
.comment:target .comment-container { | |||
border-color: var(--color-primary) !important; | |||
box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; | |||
@@ -2304,6 +2183,8 @@ td .commit-summary { | |||
.stats-table { | |||
display: table; | |||
width: 100%; | |||
margin: 6px 0; | |||
border-spacing: 2px; | |||
} | |||
.stats-table .table-cell { | |||
@@ -2311,7 +2192,17 @@ td .commit-summary { | |||
} | |||
.stats-table .table-cell.tiny { | |||
height: 0.5em; | |||
height: 8px; | |||
} | |||
.stats-table .table-cell:first-child { | |||
border-top-left-radius: 4px; | |||
border-bottom-left-radius: 4px; | |||
} | |||
.stats-table .table-cell:last-child { | |||
border-top-right-radius: 4px; | |||
border-bottom-right-radius: 4px; | |||
} | |||
.labels-list { |
@@ -0,0 +1,70 @@ | |||
.bottom-reactions { | |||
display: flex; | |||
gap: 6px; | |||
margin: 0 1em 1em; | |||
} | |||
.timeline-item .conversation-holder .bottom-reactions { | |||
margin: 1em 0 0 36px; | |||
padding-bottom: 8px; | |||
} | |||
.bottom-reactions .ui.label { | |||
padding: 5px 8px; | |||
font-weight: var(--font-weight-normal); | |||
} | |||
.bottom-reactions .ui.label.primary { | |||
background-color: var(--color-reaction-active-bg) !important; | |||
} | |||
.bottom-reactions .ui.label:hover { | |||
background-color: var(--color-reaction-hover-bg) !important; | |||
} | |||
.bottom-reactions .ui.label.disabled { | |||
cursor: default; | |||
opacity: 1; | |||
} | |||
.bottom-reactions .ui.label .reaction { | |||
font-size: 16px; | |||
display: flex; | |||
} | |||
.bottom-reactions .ui.label .reaction img { | |||
height: 16px; | |||
aspect-ratio: 1; | |||
} | |||
.bottom-reactions .reaction-count { | |||
margin-left: 4px; | |||
} | |||
.ui.dropdown.select-reaction .menu { | |||
min-width: 170px; /* item-outer-width * 4 */ | |||
} | |||
.ui.dropdown.select-reaction .menu > .item { | |||
float: left; | |||
margin: 4px; | |||
font-size: 20px; | |||
width: 34px; | |||
height: 34px; | |||
border-radius: var(--border-radius); | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.bottom-reactions .select-reaction { | |||
padding: 0 10px; | |||
} | |||
.bottom-reactions .select-reaction:not(.active) { | |||
visibility: hidden; | |||
} | |||
.bottom-reactions:hover .select-reaction { | |||
visibility: visible; | |||
} |
@@ -22,11 +22,9 @@ | |||
"admin": false, | |||
"components": [ | |||
"api", | |||
"button", | |||
"dimmer", | |||
"dropdown", | |||
"form", | |||
"menu", | |||
"modal", | |||
"search", | |||
"tab" |
@@ -138,7 +138,7 @@ export default { | |||
<div v-if="!showActionForm" class="tw-flex"> | |||
<!-- the merge button --> | |||
<div class="ui buttons merge-button" :class="[mergeForm.emptyCommit ? 'grey' : mergeForm.allOverridableChecksOk ? 'primary' : 'red']" @click="toggleActionForm(true)"> | |||
<div class="ui buttons merge-button" :class="[mergeForm.emptyCommit ? '' : mergeForm.allOverridableChecksOk ? 'primary' : 'red']" @click="toggleActionForm(true)"> | |||
<button class="ui button"> | |||
<svg-icon name="octicon-git-merge"/> | |||
<span class="button-text"> |
@@ -1,38 +1,36 @@ | |||
import $ from 'jquery'; | |||
import {POST} from '../../modules/fetch.js'; | |||
export function initCompReactionSelector($parent) { | |||
$parent.find(`.select-reaction .item.reaction, .comment-reaction-button`).on('click', async function (e) { | |||
e.preventDefault(); | |||
export function initCompReactionSelector() { | |||
for (const container of document.querySelectorAll('.issue-content, .diff-file-body')) { | |||
container.addEventListener('click', async (e) => { | |||
// there are 2 places for the "reaction" buttons, one is the top-right reaction menu, one is the bottom of the comment | |||
const target = e.target.closest('.comment-reaction-button'); | |||
if (!target) return; | |||
e.preventDefault(); | |||
if (this.classList.contains('disabled')) return; | |||
if (target.classList.contains('disabled')) return; | |||
const actionUrl = this.closest('[data-action-url]')?.getAttribute('data-action-url'); | |||
const reactionContent = this.getAttribute('data-reaction-content'); | |||
const hasReacted = this.closest('.ui.segment.reactions')?.querySelector(`a[data-reaction-content="${reactionContent}"]`)?.getAttribute('data-has-reacted') === 'true'; | |||
const actionUrl = target.closest('[data-action-url]').getAttribute('data-action-url'); | |||
const reactionContent = target.getAttribute('data-reaction-content'); | |||
const res = await POST(`${actionUrl}/${hasReacted ? 'unreact' : 'react'}`, { | |||
data: new URLSearchParams({content: reactionContent}), | |||
}); | |||
const commentContainer = target.closest('.comment-container'); | |||
const data = await res.json(); | |||
if (data && (data.html || data.empty)) { | |||
const $content = $(this).closest('.content'); | |||
let $react = $content.find('.segment.reactions'); | |||
if ((!data.empty || data.html === '') && $react.length > 0) { | |||
$react.remove(); | |||
} | |||
if (!data.empty) { | |||
const $attachments = $content.find('.segment.bottom:first'); | |||
$react = $(data.html); | |||
if ($attachments.length > 0) { | |||
$react.insertBefore($attachments); | |||
} else { | |||
$react.appendTo($content); | |||
} | |||
$react.find('.dropdown').dropdown(); | |||
initCompReactionSelector($react); | |||
const bottomReactions = commentContainer.querySelector('.bottom-reactions'); // may not exist if there is no reaction | |||
const bottomReactionBtn = bottomReactions?.querySelector(`a[data-reaction-content="${CSS.escape(reactionContent)}"]`); | |||
const hasReacted = bottomReactionBtn?.getAttribute('data-has-reacted') === 'true'; | |||
const res = await POST(`${actionUrl}/${hasReacted ? 'unreact' : 'react'}`, { | |||
data: new URLSearchParams({content: reactionContent}), | |||
}); | |||
const data = await res.json(); | |||
bottomReactions?.remove(); | |||
if (data.html) { | |||
commentContainer.insertAdjacentHTML('beforeend', data.html); | |||
const bottomReactionsDropdowns = commentContainer.querySelectorAll('.bottom-reactions .dropdown.select-reaction'); | |||
$(bottomReactionsDropdowns).dropdown(); // re-init the dropdown | |||
} | |||
} | |||
}); | |||
}); | |||
} | |||
} |
@@ -87,7 +87,6 @@ function initRepoDiffConversationForm() { | |||
el.classList.add('tw-invisible'); | |||
} | |||
$newConversationHolder.find('.dropdown').dropdown(); | |||
initCompReactionSelector($newConversationHolder); | |||
} catch (error) { | |||
console.error('Error:', error); | |||
showErrorToast(i18n.network_error); |
@@ -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); | |||
} | |||
@@ -393,7 +393,7 @@ export function initRepository() { | |||
initRepoIssueDependencyDelete(); | |||
initRepoIssueCodeCommentCancel(); | |||
initRepoPullRequestUpdate(); | |||
initCompReactionSelector($(document)); | |||
initCompReactionSelector(); | |||
initRepoPullRequestMergeForm(); | |||
initRepoPullRequestCommitStatus(); |