feat: add 24-hour traffic and capacity trend charts to dashboard and node detail pages

- Implemented TrendChart component for visualizing traffic and capacity trends.
- Enhanced DashboardOverview and NodeDetailPage components to display 24-hour request and capacity trends.
- Updated types to include traffic and capacity trend data structures.
- Created observability trends service to aggregate traffic and capacity data.
- Added tests for traffic report generation and trend data handling.
- Introduced new dependencies for charting (echarts and echarts-for-react).
This commit is contained in:
ryan
2026-03-14 11:48:05 +08:00
parent e94132a7d9
commit 16bb9e5879
25 changed files with 1063 additions and 109 deletions
+20 -4
View File
@@ -19,8 +19,10 @@ import (
const CertDirPlaceholder = "__ATSF_CERT_DIR__"
const RouteConfigPlaceholder = "__ATSF_ROUTE_CONFIG__"
const AccessLogPlaceholder = "__ATSF_ACCESS_LOG__"
const DockerMainConfigPath = "/usr/local/openresty/nginx/conf/nginx.conf"
const DockerRouteConfigPath = "/etc/nginx/conf.d/atsflare_routes.conf"
const DockerAccessLogPath = "/etc/nginx/conf.d/atsflare_access.log"
const dockerRuntimeCommand = "openresty"
@@ -285,6 +287,9 @@ func (m *Manager) CurrentChecksum() (string, error) {
if includePath := m.routeConfigIncludePath(); includePath != "" {
normalizedMain = strings.ReplaceAll(normalizedMain, includePath, RouteConfigPlaceholder)
}
if accessLogPath := m.accessLogRuntimePath(); accessLogPath != "" {
normalizedMain = strings.ReplaceAll(normalizedMain, accessLogPath, AccessLogPlaceholder)
}
normalizedRoute := string(data)
if m.NginxCertDir != "" {
normalizedRoute = strings.ReplaceAll(normalizedRoute, m.NginxCertDir, CertDirPlaceholder)
@@ -609,11 +614,14 @@ func (m *Manager) renderRouteConfig(content string) string {
}
func (m *Manager) renderMainConfig(content string) string {
includePath := m.routeConfigIncludePath()
if includePath == "" {
return content
rendered := content
if includePath := m.routeConfigIncludePath(); includePath != "" {
rendered = strings.ReplaceAll(rendered, RouteConfigPlaceholder, includePath)
}
return strings.ReplaceAll(content, RouteConfigPlaceholder, includePath)
if accessLogPath := m.accessLogRuntimePath(); accessLogPath != "" {
rendered = strings.ReplaceAll(rendered, AccessLogPlaceholder, accessLogPath)
}
return rendered
}
func (m *Manager) routeConfigIncludePath() string {
@@ -623,6 +631,14 @@ func (m *Manager) routeConfigIncludePath() string {
return strings.TrimSpace(m.RouteConfigPath)
}
func (m *Manager) accessLogRuntimePath() string {
includePath := m.routeConfigIncludePath()
if strings.TrimSpace(includePath) == "" {
return ""
}
return filepath.ToSlash(filepath.Join(filepath.Dir(includePath), "atsflare_access.log"))
}
func checksum(content string) string {
sum := sha256.Sum256([]byte(content))
return hex.EncodeToString(sum[:])