refactor(core): remove store global singleton, thread store explicitly
Remove store.Get()/SetGlobal()/Current. Store is now passed explicitly to all consumers via constructor parameters and function arguments. - TUI Model holds store field, set via InitialModel(isAdmin, store) - monitor.StartEngine(s) and InitHistoryFromStore(s) accept store - server.Start(cfg, s) closes over store in HTTP handlers - main.go threads store to SSH server, TUI, monitor, server - isKeyAllowed receives store as parameter No more hidden dependency on package-level mutable state in store pkg. Monitor package still uses package-level state (LiveState, etc.) — will be encapsulated into Engine struct in Phase 7.
This commit is contained in:
+10
-12
@@ -97,8 +97,6 @@ func main() {
|
|||||||
fmt.Printf("Database init error: %v\n", err)
|
fmt.Printf("Database init error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
store.SetGlobal(s)
|
|
||||||
|
|
||||||
if *demo {
|
if *demo {
|
||||||
seedDemoData(s)
|
seedDemoData(s)
|
||||||
}
|
}
|
||||||
@@ -117,15 +115,15 @@ func main() {
|
|||||||
fmt.Printf("Imported %d monitors and %d alerts from Uptime Kuma v%s\n", len(backup.Sites), len(backup.Alerts), kb.Version)
|
fmt.Printf("Imported %d monitors and %d alerts from Uptime Kuma v%s\n", len(backup.Sites), len(backup.Alerts), kb.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor.InitHistoryFromStore()
|
monitor.InitHistoryFromStore(s)
|
||||||
monitor.StartEngine()
|
monitor.StartEngine(s)
|
||||||
|
|
||||||
server.Start(server.ServerConfig{
|
server.Start(server.ServerConfig{
|
||||||
Port: httpPort,
|
Port: httpPort,
|
||||||
EnableStatus: enableStatus,
|
EnableStatus: enableStatus,
|
||||||
Title: statusTitle,
|
Title: statusTitle,
|
||||||
ClusterKey: clusterKey,
|
ClusterKey: clusterKey,
|
||||||
})
|
}, s)
|
||||||
|
|
||||||
cluster.Start(cluster.Config{
|
cluster.Start(cluster.Config{
|
||||||
Mode: clusterMode,
|
Mode: clusterMode,
|
||||||
@@ -133,10 +131,10 @@ func main() {
|
|||||||
SharedKey: clusterKey,
|
SharedKey: clusterKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
startSSHServer(*port)
|
startSSHServer(*port, s)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
||||||
p := tea.NewProgram(tui.InitialModel(true), tea.WithAltScreen(), tea.WithMouseCellMotion())
|
p := tea.NewProgram(tui.InitialModel(true, s), tea.WithAltScreen(), tea.WithMouseCellMotion())
|
||||||
if _, err := p.Run(); err != nil {
|
if _, err := p.Run(); err != nil {
|
||||||
fmt.Printf("Error: %v\n", err)
|
fmt.Printf("Error: %v\n", err)
|
||||||
}
|
}
|
||||||
@@ -149,16 +147,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startSSHServer(port int) {
|
func startSSHServer(port int, db store.Store) {
|
||||||
s, err := wish.NewServer(
|
s, err := wish.NewServer(
|
||||||
wish.WithAddress(fmt.Sprintf(":%d", port)),
|
wish.WithAddress(fmt.Sprintf(":%d", port)),
|
||||||
wish.WithHostKeyPath(".ssh/id_ed25519"),
|
wish.WithHostKeyPath(".ssh/id_ed25519"),
|
||||||
wish.WithPublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
wish.WithPublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||||
return isKeyAllowed(key)
|
return isKeyAllowed(db, key)
|
||||||
}),
|
}),
|
||||||
wish.WithMiddleware(
|
wish.WithMiddleware(
|
||||||
bm.Middleware(func(s ssh.Session) (tea.Model, []tea.ProgramOption) {
|
bm.Middleware(func(s ssh.Session) (tea.Model, []tea.ProgramOption) {
|
||||||
return tui.InitialModel(false), []tea.ProgramOption{tea.WithAltScreen(), tea.WithMouseCellMotion()}
|
return tui.InitialModel(false, db), []tea.ProgramOption{tea.WithAltScreen(), tea.WithMouseCellMotion()}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -206,8 +204,8 @@ func seedDemoData(s store.Store) {
|
|||||||
s.AddSite(models.Site{Name: "SSH Server", Type: "port", Interval: 60, AlertID: alertID, Hostname: "10.0.0.1", Port: 22, Timeout: 5, ExpiryThreshold: 7})
|
s.AddSite(models.Site{Name: "SSH Server", Type: "port", Interval: 60, AlertID: alertID, Hostname: "10.0.0.1", Port: 22, Timeout: 5, ExpiryThreshold: 7})
|
||||||
}
|
}
|
||||||
|
|
||||||
func isKeyAllowed(incomingKey ssh.PublicKey) bool {
|
func isKeyAllowed(db store.Store, incomingKey ssh.PublicKey) bool {
|
||||||
users, err := store.Get().GetAllUsers()
|
users, err := db.GetAllUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,7 @@ var (
|
|||||||
historyMu sync.RWMutex
|
historyMu sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitHistoryFromStore() {
|
func InitHistoryFromStore(s store.Store) {
|
||||||
s := store.Get()
|
|
||||||
if s == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
all, err := s.LoadAllHistory(maxHistoryLen)
|
all, err := s.LoadAllHistory(maxHistoryLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AddLog("Failed to load check history: " + err.Error())
|
AddLog("Failed to load check history: " + err.Error())
|
||||||
@@ -74,8 +70,8 @@ func RecordCheck(siteID int, latency time.Duration, isUp bool) {
|
|||||||
h.Statuses = h.Statuses[len(h.Statuses)-maxHistoryLen:]
|
h.Statuses = h.Statuses[len(h.Statuses)-maxHistoryLen:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if s := store.Get(); s != nil {
|
if db != nil {
|
||||||
go func() { _ = s.SaveCheck(siteID, latency.Nanoseconds(), isUp) }()
|
go func() { _ = db.SaveCheck(siteID, latency.Nanoseconds(), isUp) }()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ var (
|
|||||||
|
|
||||||
insecureSkipVerify bool
|
insecureSkipVerify bool
|
||||||
|
|
||||||
|
db store.Store
|
||||||
|
|
||||||
strictClient = &http.Client{
|
strictClient = &http.Client{
|
||||||
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: false}},
|
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: false}},
|
||||||
}
|
}
|
||||||
@@ -119,16 +121,11 @@ func RecordHeartbeat(token string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartEngine() {
|
func StartEngine(s store.Store) {
|
||||||
|
db = s
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
s_instance := store.Get()
|
sites, err := db.GetSites()
|
||||||
if s_instance == nil {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sites, err := s_instance.GetSites()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AddLog(fmt.Sprintf("Failed to load sites: %v", err))
|
AddLog(fmt.Sprintf("Failed to load sites: %v", err))
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
@@ -407,11 +404,10 @@ func handleStatusChange(site models.Site, rawStatus string, code int, latency ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func triggerAlert(alertID int, title, message string) {
|
func triggerAlert(alertID int, title, message string) {
|
||||||
s_instance := store.Get()
|
if db == nil {
|
||||||
if s_instance == nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg, err := s_instance.GetAlert(alertID)
|
cfg, err := db.GetAlert(alertID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ type ServerConfig struct {
|
|||||||
ClusterKey string // Shared Secret for Security
|
ClusterKey string // Shared Secret for Security
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(cfg ServerConfig) {
|
func Start(cfg ServerConfig, s store.Store) {
|
||||||
if cfg.ClusterKey == "" {
|
if cfg.ClusterKey == "" {
|
||||||
fmt.Println("WARNING: No UPKEEP_CLUSTER_SECRET set. Cluster API endpoints are unauthenticated.")
|
fmt.Println("WARNING: No UPKEEP_CLUSTER_SECRET set. Cluster API endpoints are unauthenticated.")
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ func Start(cfg ServerConfig) {
|
|||||||
http.Error(w, "Unauthorized: UPKEEP_CLUSTER_SECRET required", 401)
|
http.Error(w, "Unauthorized: UPKEEP_CLUSTER_SECRET required", 401)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := store.Get().ExportData()
|
data, err := s.ExportData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Export failed: %v", err)
|
log.Printf("Export failed: %v", err)
|
||||||
http.Error(w, "Export failed", 500)
|
http.Error(w, "Export failed", 500)
|
||||||
@@ -209,7 +209,7 @@ func Start(cfg ServerConfig) {
|
|||||||
http.Error(w, "Invalid JSON", 400)
|
http.Error(w, "Invalid JSON", 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := store.Get().ImportData(data); err != nil {
|
if err := s.ImportData(data); err != nil {
|
||||||
log.Printf("Import failed: %v", err)
|
log.Printf("Import failed: %v", err)
|
||||||
http.Error(w, "Import failed", 500)
|
http.Error(w, "Import failed", 500)
|
||||||
return
|
return
|
||||||
@@ -234,7 +234,7 @@ func Start(cfg ServerConfig) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
backup := importer.ConvertKuma(&kb)
|
backup := importer.ConvertKuma(&kb)
|
||||||
if err := store.Get().ImportData(backup); err != nil {
|
if err := s.ImportData(backup); err != nil {
|
||||||
log.Printf("Kuma import failed: %v", err)
|
log.Printf("Kuma import failed: %v", err)
|
||||||
http.Error(w, "Import failed", 500)
|
http.Error(w, "Import failed", 500)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -35,13 +35,3 @@ type Store interface {
|
|||||||
ExportData() (models.Backup, error)
|
ExportData() (models.Backup, error)
|
||||||
ImportData(data models.Backup) error
|
ImportData(data models.Backup) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var Current Store
|
|
||||||
|
|
||||||
func SetGlobal(s Store) {
|
|
||||||
Current = s
|
|
||||||
}
|
|
||||||
|
|
||||||
func Get() Store {
|
|
||||||
return Current
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package tui
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go-upkeep/internal/monitor"
|
"go-upkeep/internal/monitor"
|
||||||
"go-upkeep/internal/store"
|
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
@@ -278,11 +277,11 @@ func (m *Model) submitAlertForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.editID > 0 {
|
if m.editID > 0 {
|
||||||
if err := store.Get().UpdateAlert(m.editID, d.Name, d.AlertType, settings); err != nil {
|
if err := m.store.UpdateAlert(m.editID, d.Name, d.AlertType, settings); err != nil {
|
||||||
monitor.AddLog("Update alert failed: " + err.Error())
|
monitor.AddLog("Update alert failed: " + err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := store.Get().AddAlert(d.Name, d.AlertType, settings); err != nil {
|
if err := m.store.AddAlert(d.Name, d.AlertType, settings); err != nil {
|
||||||
monitor.AddLog("Add alert failed: " + err.Error())
|
monitor.AddLog("Add alert failed: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go-upkeep/internal/models"
|
"go-upkeep/internal/models"
|
||||||
"go-upkeep/internal/monitor"
|
"go-upkeep/internal/monitor"
|
||||||
"go-upkeep/internal/store"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -361,14 +360,12 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
alertOpts := []huh.Option[string]{huh.NewOption("None", "0")}
|
alertOpts := []huh.Option[string]{huh.NewOption("None", "0")}
|
||||||
if s := store.Get(); s != nil {
|
if alerts, err := m.store.GetAllAlerts(); err == nil {
|
||||||
if alerts, err := s.GetAllAlerts(); err == nil {
|
for _, a := range alerts {
|
||||||
for _, a := range alerts {
|
alertOpts = append(alertOpts, huh.NewOption(
|
||||||
alertOpts = append(alertOpts, huh.NewOption(
|
fmt.Sprintf("%s (%s)", a.Name, a.Type),
|
||||||
fmt.Sprintf("%s (%s)", a.Name, a.Type),
|
strconv.Itoa(a.ID),
|
||||||
strconv.Itoa(a.ID),
|
))
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,12 +557,12 @@ func (m *Model) submitSiteForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if m.editID > 0 {
|
if m.editID > 0 {
|
||||||
if err := store.Get().UpdateSite(site); err != nil {
|
if err := m.store.UpdateSite(site); err != nil {
|
||||||
monitor.AddLog("Update site failed: " + err.Error())
|
monitor.AddLog("Update site failed: " + err.Error())
|
||||||
}
|
}
|
||||||
monitor.UpdateSiteConfig(site)
|
monitor.UpdateSiteConfig(site)
|
||||||
} else {
|
} else {
|
||||||
if err := store.Get().AddSite(site); err != nil {
|
if err := m.store.AddSite(site); err != nil {
|
||||||
monitor.AddLog("Add site failed: " + err.Error())
|
monitor.AddLog("Add site failed: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package tui
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go-upkeep/internal/monitor"
|
"go-upkeep/internal/monitor"
|
||||||
"go-upkeep/internal/store"
|
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
@@ -146,11 +145,11 @@ func (m *Model) initUserHuhForm() tea.Cmd {
|
|||||||
func (m *Model) submitUserForm() {
|
func (m *Model) submitUserForm() {
|
||||||
d := m.userFormData
|
d := m.userFormData
|
||||||
if m.editID > 0 {
|
if m.editID > 0 {
|
||||||
if err := store.Get().UpdateUser(m.editID, d.Username, d.PublicKey, d.Role); err != nil {
|
if err := m.store.UpdateUser(m.editID, d.Username, d.PublicKey, d.Role); err != nil {
|
||||||
monitor.AddLog("Update user failed: " + err.Error())
|
monitor.AddLog("Update user failed: " + err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := store.Get().AddUser(d.Username, d.PublicKey, d.Role); err != nil {
|
if err := m.store.AddUser(d.Username, d.PublicKey, d.Role); err != nil {
|
||||||
monitor.AddLog("Add user failed: " + err.Error())
|
monitor.AddLog("Add user failed: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-33
@@ -68,6 +68,7 @@ type Model struct {
|
|||||||
deleteTab int
|
deleteTab int
|
||||||
|
|
||||||
collapsed map[int]bool
|
collapsed map[int]bool
|
||||||
|
store store.Store
|
||||||
|
|
||||||
// harmonica animation state
|
// harmonica animation state
|
||||||
pulseSpring harmonica.Spring
|
pulseSpring harmonica.Spring
|
||||||
@@ -80,7 +81,7 @@ type Model struct {
|
|||||||
users []models.User
|
users []models.User
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitialModel(isAdmin bool) Model {
|
func InitialModel(isAdmin bool, s store.Store) Model {
|
||||||
vpLogs := viewport.New(100, 20)
|
vpLogs := viewport.New(100, 20)
|
||||||
vpLogs.SetContent("Waiting for logs...")
|
vpLogs.SetContent("Waiting for logs...")
|
||||||
z := zone.New()
|
z := zone.New()
|
||||||
@@ -90,6 +91,7 @@ func InitialModel(isAdmin bool) Model {
|
|||||||
logViewport: vpLogs,
|
logViewport: vpLogs,
|
||||||
maxTableRows: 5,
|
maxTableRows: 5,
|
||||||
isAdmin: isAdmin,
|
isAdmin: isAdmin,
|
||||||
|
store: s,
|
||||||
zones: z,
|
zones: z,
|
||||||
pulseSpring: spring,
|
pulseSpring: spring,
|
||||||
collapsed: make(map[int]bool),
|
collapsed: make(map[int]bool),
|
||||||
@@ -107,25 +109,23 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
if keyMsg, ok := msg.(tea.KeyMsg); ok {
|
if keyMsg, ok := msg.(tea.KeyMsg); ok {
|
||||||
switch keyMsg.String() {
|
switch keyMsg.String() {
|
||||||
case "y", "Y":
|
case "y", "Y":
|
||||||
if s := store.Get(); s != nil {
|
switch m.deleteTab {
|
||||||
switch m.deleteTab {
|
case 0:
|
||||||
case 0:
|
if err := m.store.DeleteSite(m.deleteID); err != nil {
|
||||||
if err := s.DeleteSite(m.deleteID); err != nil {
|
monitor.AddLog("Delete site failed: " + err.Error())
|
||||||
monitor.AddLog("Delete site failed: " + err.Error())
|
|
||||||
}
|
|
||||||
monitor.RemoveSite(m.deleteID)
|
|
||||||
m.adjustCursor(len(m.sites) - 1)
|
|
||||||
case 1:
|
|
||||||
if err := s.DeleteAlert(m.deleteID); err != nil {
|
|
||||||
monitor.AddLog("Delete alert failed: " + err.Error())
|
|
||||||
}
|
|
||||||
m.adjustCursor(len(m.alerts) - 1)
|
|
||||||
case 3:
|
|
||||||
if err := s.DeleteUser(m.deleteID); err != nil {
|
|
||||||
monitor.AddLog("Delete user failed: " + err.Error())
|
|
||||||
}
|
|
||||||
m.adjustCursor(len(m.users) - 1)
|
|
||||||
}
|
}
|
||||||
|
monitor.RemoveSite(m.deleteID)
|
||||||
|
m.adjustCursor(len(m.sites) - 1)
|
||||||
|
case 1:
|
||||||
|
if err := m.store.DeleteAlert(m.deleteID); err != nil {
|
||||||
|
monitor.AddLog("Delete alert failed: " + err.Error())
|
||||||
|
}
|
||||||
|
m.adjustCursor(len(m.alerts) - 1)
|
||||||
|
case 3:
|
||||||
|
if err := m.store.DeleteUser(m.deleteID); err != nil {
|
||||||
|
monitor.AddLog("Delete user failed: " + err.Error())
|
||||||
|
}
|
||||||
|
m.adjustCursor(len(m.users) - 1)
|
||||||
}
|
}
|
||||||
m.refreshData()
|
m.refreshData()
|
||||||
m.state = stateDashboard
|
m.state = stateDashboard
|
||||||
@@ -319,9 +319,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
site := m.sites[m.cursor]
|
site := m.sites[m.cursor]
|
||||||
monitor.ToggleSitePause(site.ID)
|
monitor.ToggleSitePause(site.ID)
|
||||||
site.Paused = !site.Paused
|
site.Paused = !site.Paused
|
||||||
if s := store.Get(); s != nil {
|
_ = m.store.UpdateSitePaused(site.ID, site.Paused)
|
||||||
_ = s.UpdateSitePaused(site.ID, site.Paused)
|
|
||||||
}
|
|
||||||
m.refreshData()
|
m.refreshData()
|
||||||
}
|
}
|
||||||
case "d", "backspace":
|
case "d", "backspace":
|
||||||
@@ -470,23 +468,18 @@ func (m *Model) refreshData() {
|
|||||||
}
|
}
|
||||||
ordered = append(ordered, ungrouped...)
|
ordered = append(ordered, ungrouped...)
|
||||||
m.sites = ordered
|
m.sites = ordered
|
||||||
if s := store.Get(); s != nil {
|
if alerts, err := m.store.GetAllAlerts(); err == nil {
|
||||||
if alerts, err := s.GetAllAlerts(); err == nil {
|
m.alerts = alerts
|
||||||
m.alerts = alerts
|
}
|
||||||
}
|
if m.isAdmin {
|
||||||
if m.isAdmin {
|
if users, err := m.store.GetAllUsers(); err == nil {
|
||||||
if users, err := s.GetAllUsers(); err == nil {
|
m.users = users
|
||||||
m.users = users
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.logViewport.SetContent(strings.Join(monitor.GetLogs(), "\n"))
|
m.logViewport.SetContent(strings.Join(monitor.GetLogs(), "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) submitForm() {
|
func (m *Model) submitForm() {
|
||||||
if store.Get() == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch m.state {
|
switch m.state {
|
||||||
case stateFormSite:
|
case stateFormSite:
|
||||||
if m.siteFormData != nil {
|
if m.siteFormData != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user