refactor(frontend): move form-item hints from extra to tooltip

Switch reality target, node options, and WARP auto-update-IP hints from
inline extra text to label tooltips for a cleaner form layout.
This commit is contained in:
MHSanaei
2026-06-17 17:24:16 +02:00
parent d6cddaff12
commit 4915d6b18d
23 changed files with 218 additions and 223 deletions
+1 -1
View File
@@ -223,7 +223,7 @@ func copyTable(src, dst *gorm.DB, mdl any) (int, error) {
}
rows := make([]map[string]any, n)
for i := 0; i < n; i++ {
for i := range n {
rv := reflect.Indirect(slice.Index(i))
row := make(map[string]any, len(columns))
for _, name := range columns {
+1 -1
View File
@@ -12,7 +12,7 @@ func TestGetLogs_ReturnsAtMostC(t *testing.T) {
logBufferMu.Lock()
logBuffer = nil
logBufferMu.Unlock()
for i := 0; i < 5; i++ {
for i := range 5 {
addToBuffer("ERROR", fmt.Sprintf("m%d", i))
}
+4 -4
View File
@@ -425,12 +425,12 @@ func parseMetricLine(line string) (name string, labels map[string]string, value
if end < brace {
return "", nil, 0, fmt.Errorf("malformed metric line")
}
for _, kv := range strings.Split(line[brace+1:end], ",") {
eq := strings.IndexByte(kv, '=')
if eq < 0 {
for kv := range strings.SplitSeq(line[brace+1:end], ",") {
before, after, ok := strings.Cut(kv, "=")
if !ok {
continue
}
labels[strings.TrimSpace(kv[:eq])] = strings.Trim(strings.TrimSpace(kv[eq+1:]), `"`)
labels[strings.TrimSpace(before)] = strings.Trim(strings.TrimSpace(after), `"`)
}
rest = strings.TrimSpace(line[end+1:])
} else {
+2 -2
View File
@@ -220,8 +220,8 @@ func clashStringList(v any) []string {
}
func stripCIDR(addr string) string {
if i := strings.IndexByte(addr, '/'); i >= 0 {
return addr[:i]
if before, _, ok := strings.Cut(addr, "/"); ok {
return before
}
return addr
}
+4 -4
View File
@@ -147,9 +147,9 @@ func (a *SUBController) subs(c *gin.Context) {
if err != nil || len(subs) == 0 {
writeSubError(c, err)
} else {
result := ""
var result strings.Builder
for _, sub := range subs {
result += sub + "\n"
result.WriteString(sub + "\n")
}
// If the request expects HTML (e.g., browser) or explicitly asked (?html=1 or ?view=html), render the info page here
@@ -180,9 +180,9 @@ func (a *SUBController) subs(c *gin.Context) {
a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle, a.subSupportUrl, profileUrl, a.subAnnounce, a.subEnableRouting, a.subRoutingRules)
if a.subEncrypt {
c.String(200, base64.StdEncoding.EncodeToString([]byte(result)))
c.String(200, base64.StdEncoding.EncodeToString([]byte(result.String())))
} else {
c.String(200, result)
c.String(200, result.String())
}
}
}
+3 -3
View File
@@ -397,11 +397,11 @@ func parseShadowsocks(link string) (*ParseResult, error) {
}
func splitMethodPass(userInfo string) (string, string) {
colon := strings.Index(userInfo, ":")
if colon < 0 {
before, after, ok := strings.Cut(userInfo, ":")
if !ok {
return "2022-blake3-aes-128-gcm", userInfo // guess
}
return userInfo[:colon], userInfo[colon+1:]
return before, after
}
// --- hysteria2 ---
+1 -1
View File
@@ -325,7 +325,7 @@ func (a *XraySettingController) testOutbounds(c *gin.Context) {
func (a *XraySettingController) balancerStatus(c *gin.Context) {
raw := c.PostForm("tags")
var tags []string
for _, tag := range strings.Split(raw, ",") {
for tag := range strings.SplitSeq(raw, ",") {
if tag = strings.TrimSpace(tag); tag != "" {
tags = append(tags, tag)
}
+2 -3
View File
@@ -80,8 +80,7 @@ type ValidationPayload struct {
func writeBindFailure(c *gin.Context, err error) {
payload := ValidationPayload{Issues: []FieldIssue{}, Message: err.Error()}
var ve validator.ValidationErrors
if errors.As(err, &ve) {
if ve, ok := errors.AsType[validator.ValidationErrors](err); ok {
payload.Issues = make([]FieldIssue, 0, len(ve))
for _, fe := range ve {
payload.Issues = append(payload.Issues, FieldIssue{
@@ -102,7 +101,7 @@ func writeBindFailure(c *gin.Context, err error) {
func init() {
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
name, _, _ := strings.Cut(fld.Tag.Get("json"), ",")
if name == "-" || name == "" {
return fld.Name
}
@@ -92,7 +92,7 @@ func TestAllAPIsPostgresScale(t *testing.T) {
db.Exec("ANALYZE")
emails := make([]string, n)
for i := 0; i < n; i++ {
for i := range n {
emails[i] = clients[i].Email
}
emailsM := emails[:m]
@@ -196,7 +196,7 @@ func TestGetClientTrafficByEmailABScale(t *testing.T) {
targets := []string{clients[0].Email, clients[n/2].Email, clients[n-1].Email}
start := time.Now()
for i := 0; i < reps; i++ {
for i := range reps {
if _, err := inboundSvc.GetClientTrafficByEmail(targets[i%len(targets)]); err != nil {
t.Fatalf("new GetClientTrafficByEmail: %v", err)
}
@@ -204,7 +204,7 @@ func TestGetClientTrafficByEmailABScale(t *testing.T) {
newDur := time.Since(start) / reps
start = time.Now()
for i := 0; i < reps; i++ {
for i := range reps {
if err := oldImpl(targets[i%len(targets)]); err != nil {
t.Fatalf("old GetClientTrafficByEmail: %v", err)
}
+1 -1
View File
@@ -270,7 +270,7 @@ func parseRecipients(toStr string) []string {
return nil
}
var out []string
for _, s := range strings.Split(toStr, ",") {
for s := range strings.SplitSeq(toStr, ",") {
s = strings.TrimSpace(s)
if s != "" {
out = append(out, s)
+1 -1
View File
@@ -53,7 +53,7 @@ func (s *Subscriber) isEventEnabled(t eventbus.EventType) bool {
if err != nil || events == "" {
return false
}
for _, e := range strings.Split(events, ",") {
for e := range strings.SplitSeq(events, ",") {
if strings.TrimSpace(e) == string(t) {
return true
}
+2 -2
View File
@@ -190,8 +190,8 @@ func (s *WarpService) ChangeWarpIP() (string, error) {
}
var parsed struct {
Data map[string]string `json:"data"`
Config map[string]interface{} `json:"config"`
Data map[string]string `json:"data"`
Config map[string]any `json:"config"`
}
if err := json.Unmarshal([]byte(result), &parsed); err != nil {
return "", err
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"encoding/gob"
"os"
"path/filepath"
"slices"
"sync"
"time"
@@ -106,8 +107,8 @@ func (h *metricHistory) aggregate(metric string, bucketSeconds int, maxPoints in
h.mu.Lock()
hist := h.metrics[metric]
startIdx := 0
for i := len(hist) - 1; i >= 0; i-- {
if hist[i].T < cutoff {
for i, h := range slices.Backward(hist) {
if h.T < cutoff {
startIdx = i + 1
break
}
+3 -4
View File
@@ -11,6 +11,7 @@ import (
"net"
"net/http"
"net/url"
"slices"
"strconv"
"strings"
"time"
@@ -405,10 +406,8 @@ func (s *NodeService) EnsureInboundTagAllowed(nodeID int, tag string) error {
if node.InboundSyncMode != "selected" {
return nil
}
for _, t := range node.InboundTags {
if t == tag {
return nil
}
if slices.Contains(node.InboundTags, tag) {
return nil
}
buf, err := json.Marshal(append(node.InboundTags, tag))
if err != nil {
@@ -70,7 +70,7 @@ func syncInboundOld(tx *gorm.DB, inboundId int, clients []model.Client) error {
func makeScaleClients(n int) []model.Client {
out := make([]model.Client, n)
for i := 0; i < n; i++ {
for i := range n {
out[i] = model.Client{
ID: uuid.NewString(),
Email: fmt.Sprintf("user-%07d@scale", i),
@@ -260,7 +260,7 @@ func TestGroupAndListPostgresScale(t *testing.T) {
}
db.Exec("ANALYZE")
emails := make([]string, n)
for i := 0; i < n; i++ {
for i := range n {
emails[i] = clients[i].Email
}
@@ -382,7 +382,7 @@ func TestBulkOpsPostgresScale(t *testing.T) {
}
emailsM := make([]string, m)
for i := 0; i < m; i++ {
for i := range m {
emailsM[i] = clients[i].Email
}
@@ -405,7 +405,7 @@ func TestBulkOpsPostgresScale(t *testing.T) {
detachDur := time.Since(t0)
payloads := make([]ClientCreatePayload, m)
for i := 0; i < m; i++ {
for i := range m {
payloads[i] = ClientCreatePayload{
Client: model.Client{ID: uuid.NewString(), Email: fmt.Sprintf("bulknew-%07d@scale", i), SubID: fmt.Sprintf("bnsub-%07d", i), Enable: true},
InboundIds: []int{ib.Id},
+1 -1
View File
@@ -49,7 +49,7 @@ func (t *Tgbot) isEventEnabled(eventType eventbus.EventType) bool {
if err != nil || events == "" {
return false
}
for _, e := range strings.Split(events, ",") {
for e := range strings.SplitSeq(events, ",") {
if strings.TrimSpace(e) == string(eventType) {
return true
}
+13 -13
View File
@@ -41,39 +41,39 @@ func (s *XraySettingService) CheckXrayConfig(XrayTemplateConfig string) error {
return nil
}
func (s *XraySettingService) UpdateWarpXraySetting(warpData map[string]string, warpConfig map[string]interface{}) error {
func (s *XraySettingService) UpdateWarpXraySetting(warpData map[string]string, warpConfig map[string]any) error {
template, err := s.GetXrayConfigTemplate()
if err != nil {
return err
}
var cfg map[string]interface{}
var cfg map[string]any
if err := json.Unmarshal([]byte(template), &cfg); err != nil {
return err
}
outbounds, ok := cfg["outbounds"].([]interface{})
outbounds, ok := cfg["outbounds"].([]any)
if !ok {
return nil
}
updated := false
for _, outIface := range outbounds {
out, ok := outIface.(map[string]interface{})
out, ok := outIface.(map[string]any)
if !ok {
continue
}
if tag, ok := out["tag"].(string); ok && tag == "warp" {
settings, ok := out["settings"].(map[string]interface{})
settings, ok := out["settings"].(map[string]any)
if !ok {
continue
}
settings["secretKey"] = warpData["private_key"]
if conf, ok := warpConfig["config"].(map[string]interface{}); ok {
if iface, ok := conf["interface"].(map[string]interface{}); ok {
if addrs, ok := iface["addresses"].(map[string]interface{}); ok {
if conf, ok := warpConfig["config"].(map[string]any); ok {
if iface, ok := conf["interface"].(map[string]any); ok {
if addrs, ok := iface["addresses"].(map[string]any); ok {
var addrList []string
if v4, ok := addrs["v4"].(string); ok && v4 != "" {
addrList = append(addrList, v4+"/32")
@@ -100,12 +100,12 @@ func (s *XraySettingService) UpdateWarpXraySetting(warpData map[string]string, w
settings["reserved"] = res
}
if peers, ok := conf["peers"].([]interface{}); ok && len(peers) > 0 {
if peer, ok := peers[0].(map[string]interface{}); ok {
if pSettings, ok := settings["peers"].([]interface{}); ok && len(pSettings) > 0 {
if pSet, ok := pSettings[0].(map[string]interface{}); ok {
if peers, ok := conf["peers"].([]any); ok && len(peers) > 0 {
if peer, ok := peers[0].(map[string]any); ok {
if pSettings, ok := settings["peers"].([]any); ok && len(pSettings) > 0 {
if pSet, ok := pSettings[0].(map[string]any); ok {
pSet["publicKey"] = peer["public_key"]
if endpoint, ok := peer["endpoint"].(map[string]interface{}); ok {
if endpoint, ok := peer["endpoint"].(map[string]any); ok {
pSet["endpoint"] = endpoint["host"]
}
}
+1 -1
View File
@@ -388,7 +388,7 @@ func (s *Server) cpuAlarmWanted() bool {
if threshold <= 0 {
return false
}
for _, e := range strings.Split(events, ",") {
for e := range strings.SplitSeq(events, ",") {
if strings.TrimSpace(e) == string(eventbus.EventCPUHigh) {
return true
}
+2 -6
View File
@@ -4,6 +4,7 @@ import (
"os"
"os/exec"
"path/filepath"
"slices"
"testing"
"time"
@@ -248,12 +249,7 @@ func TestRefreshLocalOnline_GraceBoundaryInbounds(t *testing.T) {
}
func containsString(s []string, v string) bool {
for _, x := range s {
if x == v {
return true
}
}
return false
return slices.Contains(s, v)
}
// ---------------------------------------------------------------------------