mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
Overhaul: real metrics, Git integration UI, open-source hygiene, root cleanup
Backend: - GET /services/:id/metrics with real Docker container stats - DELETE /git/providers/:id and GET repo branches endpoint Frontend: - Service detail shows real telemetry or honest empty states - Live status distinguishes idle/polling/reconnecting - Git providers section in Settings; repo+branch pickers in Add Service - Real logo, compact Projects header, canvas fitView fix - index.css deduplicated (1725 -> 1384 lines) - Fixed smoke tests, lint errors, ToastProvider/context unification Repo hygiene: - Added LICENSE (MIT), CONTRIBUTING.md, SECURITY.md; rewrote README - Untracked .env.prod and data/letsencrypt secrets; fixed .gitignore - Removed legacy root src/internal/cmd and stale configs/docs/artifacts - Moved guides and design references under docs/ Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
355a97bab4
commit
9f3b196032
499 files changed
+4471
-94235
No files matched your search
@@ -146,6 +146,9 @@ func Load() *Config {
|
||||
cfg.CORSMethods = getenvSlice("CORS_METHODS", []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"})
|
||||
cfg.CORSHeaders = getenvSlice("CORS_HEADERS", []string{"Origin", "Content-Type", "Accept", "Authorization"})
|
||||
cfg.CORSCredentials = getenvBool("CORS_CREDENTIALS", true)
|
||||
if cfg.IsDevelopment() {
|
||||
cfg.CORSOrigins = expandDevelopmentCORSOrigins(cfg.CORSOrigins)
|
||||
}
|
||||
|
||||
cfg.APIKeyHeader = getenv("API_KEY_HEADER", "X-API-Key")
|
||||
cfg.ServiceTokenHeader = getenv("SERVICE_TOKEN_HEADER", "X-Service-Token")
|
||||
@@ -331,6 +334,57 @@ func getenvSliceWithAliases(keys []string, defaultValue []string) []string {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func expandDevelopmentCORSOrigins(origins []string) []string {
|
||||
hasLocalOrigin := false
|
||||
seen := make(map[string]struct{}, len(origins))
|
||||
expanded := make([]string, 0, len(origins)+12)
|
||||
|
||||
for _, origin := range origins {
|
||||
trimmed := strings.TrimSpace(origin)
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[trimmed]; ok {
|
||||
continue
|
||||
}
|
||||
seen[trimmed] = struct{}{}
|
||||
expanded = append(expanded, trimmed)
|
||||
|
||||
if strings.HasPrefix(trimmed, "http://localhost") ||
|
||||
strings.HasPrefix(trimmed, "http://127.0.0.1") ||
|
||||
strings.HasPrefix(trimmed, "http://0.0.0.0") {
|
||||
hasLocalOrigin = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasLocalOrigin {
|
||||
return expanded
|
||||
}
|
||||
|
||||
for _, origin := range []string{
|
||||
"http://localhost:3000",
|
||||
"http://localhost:5173",
|
||||
"http://localhost:5174",
|
||||
"http://localhost:5175",
|
||||
"http://127.0.0.1:3000",
|
||||
"http://127.0.0.1:5173",
|
||||
"http://127.0.0.1:5174",
|
||||
"http://127.0.0.1:5175",
|
||||
"http://0.0.0.0:3000",
|
||||
"http://0.0.0.0:5173",
|
||||
"http://0.0.0.0:5174",
|
||||
"http://0.0.0.0:5175",
|
||||
} {
|
||||
if _, ok := seen[origin]; ok {
|
||||
continue
|
||||
}
|
||||
seen[origin] = struct{}{}
|
||||
expanded = append(expanded, origin)
|
||||
}
|
||||
|
||||
return expanded
|
||||
}
|
||||
|
||||
// encodeDatabasePassword URL-encodes the password in a database connection string
|
||||
func encodeDatabasePassword(databaseURL string) string {
|
||||
// Find the password part between :@ and encode it
|
||||
|
||||
Reference in new issue
Block a user