Add server-side rendered setup UI accessible via `heatwave web`. The dashboard is now re-rendered per request and includes a nav bar linking to the new /setup page. Setup provides full CRUD for profiles, rooms, devices, occupants, AC units (with room assignment), scenario toggles, and forecast fetching — all via POST/redirect/GET forms. - Add ShowNav field to DashboardData for conditional nav bar - Extract fetchForecastForProfile() for reuse by web handler - Create setup.html.tmpl with Tailwind-styled entity sections - Create web_handlers.go with 15 route handlers and flash cookies - Switch web.go from pre-rendered to per-request dashboard rendering - Graceful dashboard fallback when no forecast data exists
107 lines
2.6 KiB
Go
107 lines
2.6 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
profileLat float64
|
|
profileLon float64
|
|
profileTZ string
|
|
)
|
|
|
|
func init() {
|
|
profileCmd := &cobra.Command{
|
|
Use: "profile",
|
|
Short: "Manage location profiles",
|
|
}
|
|
|
|
createCmd := &cobra.Command{
|
|
Use: "create <name>",
|
|
Short: "Create a new location profile",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
p, err := db.CreateProfile(args[0], profileLat, profileLon, profileTZ)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Profile created: %s (ID: %d, %.4f, %.4f)\n", p.Name, p.ID, p.Latitude, p.Longitude)
|
|
return nil
|
|
},
|
|
}
|
|
createCmd.Flags().Float64Var(&profileLat, "lat", 0, "latitude")
|
|
createCmd.Flags().Float64Var(&profileLon, "lon", 0, "longitude")
|
|
createCmd.Flags().StringVar(&profileTZ, "tz", "Europe/Berlin", "timezone")
|
|
createCmd.MarkFlagRequired("lat")
|
|
createCmd.MarkFlagRequired("lon")
|
|
|
|
showCmd := &cobra.Command{
|
|
Use: "show",
|
|
Short: "Display current profile",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
p, err := getActiveProfile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Profile: %s (ID: %d)\n", p.Name, p.ID)
|
|
fmt.Printf(" Location: %.4f, %.4f\n", p.Latitude, p.Longitude)
|
|
fmt.Printf(" Timezone: %s\n", p.Timezone)
|
|
fmt.Printf(" Created: %s\n", p.CreatedAt.Format("2006-01-02 15:04"))
|
|
return nil
|
|
},
|
|
}
|
|
|
|
editCmd := &cobra.Command{
|
|
Use: "edit <field> <value>",
|
|
Short: "Edit a profile field",
|
|
Args: cobra.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
p, err := getActiveProfile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return db.UpdateProfile(p.ID, args[0], args[1])
|
|
},
|
|
}
|
|
|
|
deleteCmd := &cobra.Command{
|
|
Use: "delete",
|
|
Short: "Delete current profile",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
p, err := getActiveProfile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := db.DeleteProfile(p.ID); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Profile %q deleted\n", p.Name)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
listCmd := &cobra.Command{
|
|
Use: "list",
|
|
Short: "List all profiles",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
profiles, err := db.ListProfiles()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(profiles) == 0 {
|
|
fmt.Println("No profiles found")
|
|
return nil
|
|
}
|
|
for _, p := range profiles {
|
|
fmt.Printf(" [%d] %s (%.4f, %.4f, %s)\n", p.ID, p.Name, p.Latitude, p.Longitude, p.Timezone)
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
profileCmd.AddCommand(createCmd, showCmd, editCmd, deleteCmd, listCmd)
|
|
rootCmd.AddCommand(profileCmd)
|
|
}
|