7accb86203
- Add Background Transfers section with mock download/upload rows - Progress bars with green glow shadow, source/destination layout - Empty state when no transfers active - Delete PERBAIKANUI.md (all UI tasks complete)
173 lines
4.2 KiB
Go
173 lines
4.2 KiB
Go
package handler
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"git.tukangketik.id/swanadiva/hostkeeper/v2/internal/model"
|
|
"git.tukangketik.id/swanadiva/hostkeeper/v2/internal/store"
|
|
)
|
|
|
|
var hostStore = store.NewHostStore()
|
|
|
|
var navItems = []fiber.Map{
|
|
{"ID": "hosts", "Label": "Hosts", "Icon": "server"},
|
|
{"ID": "terminal", "Label": "Terminal", "Icon": "terminal"},
|
|
{"ID": "sftp", "Label": "SFTP", "Icon": "folder-sync"},
|
|
{"ID": "snippets", "Label": "Snippets", "Icon": "code2"},
|
|
{"ID": "keychain", "Label": "Keychain", "Icon": "key-round"},
|
|
{"ID": "settings", "Label": "Settings", "Icon": "settings2"},
|
|
}
|
|
|
|
func Dashboard(c *fiber.Ctx) error {
|
|
hosts := hostStore.All()
|
|
transfers := []model.Transfer{
|
|
{ID: "1", FileName: "backup_v4.tar.gz", Source: "production-api-01", Destination: "Local Machine", Progress: 82, Speed: "12.4 MB/s", Type: "download", Status: "transferring"},
|
|
{ID: "2", FileName: "assets_deploy.zip", Source: "Local Storage", Destination: "web-frontend-02", Progress: 35, Speed: "4.8 MB/s", Type: "upload", Status: "transferring"},
|
|
}
|
|
return c.Render("index", fiber.Map{
|
|
"View": "hosts",
|
|
"Title": "Hosts",
|
|
"Hosts": hosts,
|
|
"Active": countByStatus(hosts, "active"),
|
|
"Offline": countByStatus(hosts, "offline"),
|
|
"NavItems": navItems,
|
|
"Transfers": transfers,
|
|
})
|
|
}
|
|
|
|
func DashboardList(c *fiber.Ctx) error {
|
|
q := c.Query("q")
|
|
filter := c.Query("filter", "all")
|
|
hosts := hostStore.Search(q, filter)
|
|
return c.Render("host_list", fiber.Map{
|
|
"Hosts": hosts,
|
|
"Active": countByStatus(hosts, "active"),
|
|
"Offline": countByStatus(hosts, "offline"),
|
|
})
|
|
}
|
|
|
|
func parsePort(s string, def int) int {
|
|
i, err := strconv.Atoi(s)
|
|
if err != nil || i < 1 || i > 65535 {
|
|
return def
|
|
}
|
|
return i
|
|
}
|
|
|
|
func CreateHost(c *fiber.Ctx) error {
|
|
hostID := c.FormValue("hostId")
|
|
|
|
if hostID != "" {
|
|
return UpdateHost(c)
|
|
}
|
|
|
|
name := c.FormValue("name")
|
|
ip := c.FormValue("ip")
|
|
if name == "" || ip == "" {
|
|
return c.Status(400).SendString("name and ip required")
|
|
}
|
|
|
|
h := model.Host{
|
|
Name: name,
|
|
IP: ip,
|
|
OS: c.FormValue("os"),
|
|
Provider: c.FormValue("provider"),
|
|
Type: c.FormValue("type"),
|
|
Port: parsePort(c.FormValue("port"), 22),
|
|
Username: c.FormValue("username"),
|
|
AuthType: c.FormValue("authType"),
|
|
Password: c.FormValue("password"),
|
|
Hostname: c.FormValue("hostname"),
|
|
Notes: c.FormValue("notes"),
|
|
}
|
|
if h.Username == "" {
|
|
h.Username = "root"
|
|
}
|
|
if h.AuthType == "" {
|
|
h.AuthType = "key"
|
|
}
|
|
|
|
hostStore.AddFull(h)
|
|
hosts := hostStore.All()
|
|
return c.Render("host_list", fiber.Map{
|
|
"Hosts": hosts,
|
|
"Active": countByStatus(hosts, "active"),
|
|
"Offline": countByStatus(hosts, "offline"),
|
|
})
|
|
}
|
|
|
|
func UpdateHost(c *fiber.Ctx) error {
|
|
id := c.Params("id")
|
|
if id == "" {
|
|
id = c.FormValue("hostId")
|
|
}
|
|
existing, found := hostStore.Get(id)
|
|
if !found {
|
|
return c.Status(404).SendString("host not found")
|
|
}
|
|
|
|
if v := c.FormValue("name"); v != "" {
|
|
existing.Name = v
|
|
}
|
|
if v := c.FormValue("ip"); v != "" {
|
|
existing.IP = v
|
|
}
|
|
if v := c.FormValue("os"); v != "" {
|
|
existing.OS = v
|
|
}
|
|
if v := c.FormValue("provider"); v != "" {
|
|
existing.Provider = v
|
|
}
|
|
if v := c.FormValue("type"); v != "" {
|
|
existing.Type = v
|
|
}
|
|
if v := c.FormValue("port"); v != "" {
|
|
existing.Port = parsePort(v, 22)
|
|
}
|
|
if v := c.FormValue("username"); v != "" {
|
|
existing.Username = v
|
|
}
|
|
if v := c.FormValue("authType"); v != "" {
|
|
existing.AuthType = v
|
|
}
|
|
if v := c.FormValue("password"); v != "" {
|
|
existing.Password = v
|
|
}
|
|
if v := c.FormValue("hostname"); v != "" {
|
|
existing.Hostname = v
|
|
}
|
|
if v := c.FormValue("notes"); v != "" {
|
|
existing.Notes = v
|
|
}
|
|
|
|
hostStore.Update(existing)
|
|
hosts := hostStore.All()
|
|
return c.Render("host_list", fiber.Map{
|
|
"Hosts": hosts,
|
|
"Active": countByStatus(hosts, "active"),
|
|
"Offline": countByStatus(hosts, "offline"),
|
|
})
|
|
}
|
|
|
|
func DeleteHost(c *fiber.Ctx) error {
|
|
id := c.Params("id")
|
|
hostStore.Delete(id)
|
|
hosts := hostStore.All()
|
|
return c.Render("host_list", fiber.Map{
|
|
"Hosts": hosts,
|
|
"Active": countByStatus(hosts, "active"),
|
|
"Offline": countByStatus(hosts, "offline"),
|
|
})
|
|
}
|
|
|
|
func countByStatus(hosts []model.Host, status string) int {
|
|
n := 0
|
|
for _, h := range hosts {
|
|
if h.Status == status {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|