package dashboard import ( "fmt" "net/http" ) type ipsPageData struct { PageData Items []ipQueueItem FIPSettleSeconds int PollSeconds int } type ipDetailData struct { PageData Detail ipDetailResponse } func (s *Server) handleIPsPage(w http.ResponseWriter, r *http.Request) { items, err := s.CA.ListIPs(r.Context()) settings, settingsErr := s.CA.GetOrchestratorSettings(r.Context()) if err == nil { err = settingsErr } data := ipsPageData{Items: items, FIPSettleSeconds: settings.FIPSettleSeconds, PollSeconds: s.Cfg.OverviewPollIntervalS} data.ActiveNav = "ips" data.Banner = bannerFor(err) s.renderPage(w, "ips_page", data) } // handleIPsFragment re-renders just the ips_table fragment, for the // periodic auto-refresh poll (see ips_content's hx-trigger="every Ns") — // identical to a mutating action's post-update render, just with no // actionErr of its own. func (s *Server) handleIPsFragment(w http.ResponseWriter, r *http.Request) { s.renderIPsTable(w, r, nil) } func (s *Server) handleIPDetail(w http.ResponseWriter, r *http.Request) { ip := r.PathValue("ip") detail, err := s.CA.GetIP(r.Context(), ip) data := ipDetailData{Detail: detail} data.ActiveNav = "ips" data.Banner = bannerFor(err) s.renderPage(w, "ip_detail_page", data) } // renderIPsTable re-fetches the current queue and renders the ips_table // fragment, tagging actionErr (if any) on the shared error banner. Called // after every mutating /ips/* request so the table always reflects true // current state regardless of whether the mutation itself succeeded. func (s *Server) renderIPsTable(w http.ResponseWriter, r *http.Request, actionErr error) { items, listErr := s.CA.ListIPs(r.Context()) if actionErr == nil { actionErr = listErr } settings, settingsErr := s.CA.GetOrchestratorSettings(r.Context()) if actionErr == nil { actionErr = settingsErr } s.renderFragment(w, "ips_table", ipsPageData{Items: items, FIPSettleSeconds: settings.FIPSettleSeconds}, actionErr) } func (s *Server) handleIPsSubmit(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { s.renderIPsTable(w, r, fmt.Errorf("invalid form: %w", err)) return } addresses := splitList(r.PostFormValue("addresses")) if len(addresses) == 0 { s.renderIPsTable(w, r, &apiErr{Status: http.StatusBadRequest, Message: "укажите хотя бы один адрес"}) return } _, err := s.CA.SubmitIPs(r.Context(), addresses) s.renderIPsTable(w, r, err) } func (s *Server) handleIPRecheck(w http.ResponseWriter, r *http.Request) { ip := r.PathValue("ip") _, err := s.CA.SubmitIPs(r.Context(), []string{ip}) s.renderIPsTable(w, r, err) } func (s *Server) handleIPCancel(w http.ResponseWriter, r *http.Request) { ip := r.PathValue("ip") err := s.CA.CancelIP(r.Context(), ip) s.renderIPsTable(w, r, err) } func (s *Server) handleIPDelete(w http.ResponseWriter, r *http.Request) { ip := r.PathValue("ip") err := s.CA.DeleteIP(r.Context(), ip) s.renderIPsTable(w, r, err) } func (s *Server) handleIPsDeleteSelected(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { s.renderIPsTable(w, r, fmt.Errorf("invalid form: %w", err)) return } addresses := r.Form["addresses"] if len(addresses) == 0 { s.renderIPsTable(w, r, &apiErr{Status: http.StatusBadRequest, Message: "ничего не выбрано"}) return } _, err := s.CA.DeleteIPs(r.Context(), addresses) s.renderIPsTable(w, r, err) } func (s *Server) handleIPsRecheckSelected(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { s.renderIPsTable(w, r, fmt.Errorf("invalid form: %w", err)) return } addresses := r.Form["addresses"] if len(addresses) == 0 { s.renderIPsTable(w, r, &apiErr{Status: http.StatusBadRequest, Message: "ничего не выбрано"}) return } _, err := s.CA.SubmitIPs(r.Context(), addresses) s.renderIPsTable(w, r, err) } func (s *Server) handleIPsClear(w http.ResponseWriter, r *http.Request) { _, err := s.CA.ClearQueue(r.Context()) s.renderIPsTable(w, r, err) }