feat: add registry config, image upload/download, and OCI format support

Backend:
- Add registry_address configuration API (GET/POST)
- Add tar image upload with OCI and Docker format support
- Add image download with streaming optimization
- Fix blob download using c.Send (Fiber v3 SendStream bug)
- Add registry_address prefix stripping for all OCI v2 endpoints
- Add AGENTS.md for project documentation

Frontend:
- Add settings store with Snackbar notifications
- Add image upload dialog with progress bar
- Add download state tracking with multi-stage feedback
- Replace alert() with MUI Snackbar messages
- Display image names without registry_address prefix

🤖 Generated with [Qoder](https://qoder.com)
This commit is contained in:
loveuer
2025-11-10 16:28:58 +08:00
parent 29088a6b54
commit 9780a2b028
35 changed files with 3065 additions and 91 deletions

71
pkg/tool/string.go Normal file
View File

@@ -0,0 +1,71 @@
package tool
import (
"encoding/json"
"strings"
"unsafe"
)
func BytesToString(b []byte) string {
return unsafe.String(unsafe.SliceData(b), len(b))
}
func StringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func CopyString(s string) string {
return string([]byte(s))
}
// ToSnakeCase 将给定的字符串转换为 snake_case 风格。
//
// 参数:
//
// str: 待转换的字符串,只考虑 ASCII 字符。
func ToSnakeCase(str string) string {
if str == "" {
return ""
}
var (
sb strings.Builder
isLower = func(c byte) bool {
return c >= 'a' && c <= 'z'
}
isUpper = func(c byte) bool {
return c >= 'A' && c <= 'Z'
}
)
for i := 0; i < len(str); i++ {
c := str[i]
var prev byte
if i > 0 {
prev = str[i-1]
}
var next byte
if i < len(str)-1 {
next = str[i+1]
}
if isUpper(c) && (isLower(prev) || isLower(next)) {
sb.WriteRune('_')
sb.WriteByte(c + ('a' - 'A'))
} else if isUpper(c) {
sb.WriteByte(c + ('a' - 'A'))
} else {
sb.WriteRune(rune(c))
}
}
// 去除首尾下划线
return strings.Trim(sb.String(), "_")
}
func PrettyJSON(v any) string {
b, _ := json.MarshalIndent(v, "", " ")
return string(b)
}