feat(site): enhance monitoring, domain, and system tracking
Build Docker images / Hub (push) Failing after 5m57s

- Improve domain lookup by adding CNAME and SRV record support
- Enhance domain status logic to include expiry and DNS resolution verification
- Update monitoring API to perform synchronous initial checks for immediate status updates
- Refactor site UI:
    - Add tag filtering to domains and monitors tables
    - Improve calendar view with better visual indicators for today and events
    - Update monitor detail view with improved status badges and pending states
    - Simplify home page layout by removing redundant card wrappers
- Update localization files for numerous languages to support new UI elements
- Add `cleanEndpointsConfig` to hub to safely reuse Docker network settings during container updates
This commit is contained in:
Tomas Dvorak
2026-05-02 15:38:41 +02:00
parent c7e2c88604
commit 21657abe38
48 changed files with 3215 additions and 583 deletions
+16
View File
@@ -180,6 +180,22 @@ func (h *APIHandler) createDomain(e *core.RequestEvent) error {
domainData, err := lookupSvc.LookupDomain(ctx, domainName)
if err == nil && domainData != nil {
h.applyLookupData(record, domainData)
// Calculate status based on lookup results
status := domain.DomainStatusUnknown
if domainData.ExpiryDate != nil {
daysUntil := int(time.Until(*domainData.ExpiryDate).Hours() / 24)
if daysUntil < 0 {
status = domain.DomainStatusExpired
} else if daysUntil <= req.AlertDaysBefore {
status = domain.DomainStatusExpiring
} else {
status = domain.DomainStatusActive
}
} else if len(domainData.IPv4Addresses) > 0 || len(domainData.IPv6Addresses) > 0 || len(domainData.NameServers) > 0 {
// DNS resolves means the domain is active and functioning
status = domain.DomainStatusActive
}
record.Set("status", status)
}
}
+24 -13
View File
@@ -120,20 +120,31 @@ func (s *Scheduler) checkDomain(record *core.Record) error {
newData = &domain.Domain{DomainName: domainName}
}
// Independent DNS resolution check: if WHOIS failed, try to resolve the domain directly
if err != nil {
ips, lookupErr := net.LookupHost(domainName)
if lookupErr == nil && len(ips) > 0 {
newData.IPv4Addresses = []string{}
newData.IPv6Addresses = []string{}
for _, ip := range ips {
if strings.Contains(ip, ":") {
newData.IPv6Addresses = append(newData.IPv6Addresses, ip)
} else {
newData.IPv4Addresses = append(newData.IPv4Addresses, ip)
}
// Always perform independent DNS resolution to verify domain is alive.
// This is critical when WHOIS succeeds but returns partial data (e.g. no expiry for some TLDs),
// or when WHOIS fails completely. DNS resolution proves the domain exists and is active.
ips, lookupErr := net.LookupHost(domainName)
if lookupErr == nil && len(ips) > 0 {
newData.IPv4Addresses = []string{}
newData.IPv6Addresses = []string{}
for _, ip := range ips {
if strings.Contains(ip, ":") {
newData.IPv6Addresses = append(newData.IPv6Addresses, ip)
} else {
newData.IPv4Addresses = append(newData.IPv4Addresses, ip)
}
log.Printf("[domain-scheduler] DNS resolution succeeded for %s despite WHOIS failure", domainName)
}
log.Printf("[domain-scheduler] DNS A/AAAA resolution succeeded for %s", domainName)
}
// Also try to get nameservers independently if WHOIS didn't provide them
if len(newData.NameServers) == 0 {
nsRecords, nsErr := net.LookupNS(domainName)
if nsErr == nil && len(nsRecords) > 0 {
for _, ns := range nsRecords {
newData.NameServers = append(newData.NameServers, ns.Host)
}
log.Printf("[domain-scheduler] DNS NS lookup succeeded for %s", domainName)
}
}
+20
View File
@@ -672,6 +672,26 @@ func (s *LookupService) lookupDNS(ctx context.Context, domainName string, d *dom
txtRecords, _ := net.LookupTXT(domainName)
d.TXTRecords = txtRecords
// CNAME record
cname, err := net.LookupCNAME(domainName)
if err == nil && cname != domainName && cname != "" {
d.CNAMERecord = cname
}
// SRV records (common services)
srvServices := []string{"sip", "xmpp-server", "ldap", "autodiscover", "imap", "smtp", "caldavs", "carddavs"}
srvProtos := []string{"tcp", "udp", "tls"}
for _, service := range srvServices {
for _, proto := range srvProtos {
_, addrs, err := net.LookupSRV(service, proto, domainName)
if err == nil {
for _, addr := range addrs {
d.SRVRecords = append(d.SRVRecords, fmt.Sprintf("_%s._%s %s:%d (priority: %d, weight: %d)", service, proto, addr.Target, addr.Port, addr.Priority, addr.Weight))
}
}
}
}
// IPv4
ipv4Addrs, _ := net.LookupHost(domainName)
for _, ip := range ipv4Addrs {