Add themed UI, favicon, plan deletion, regrow cycles, and crop prep/post tasks

This commit is contained in:
Kai
2026-02-16 13:27:47 +01:00
parent 51181a83c8
commit a1c1ef31a3
14 changed files with 552 additions and 127 deletions

View File

@@ -37,7 +37,21 @@ func ensureSchema(db *sql.DB) error {
name VARCHAR(80) NOT NULL UNIQUE,
sow_start_month TINYINT NOT NULL,
sow_end_month TINYINT NOT NULL,
grow_months TINYINT NOT NULL
grow_months TINYINT NOT NULL,
regrow_enabled TINYINT(1) NOT NULL DEFAULT 0,
regrow_cycles INT NOT NULL DEFAULT 0
)`,
`ALTER TABLE crops ADD COLUMN IF NOT EXISTS regrow_enabled TINYINT(1) NOT NULL DEFAULT 0`,
`ALTER TABLE crops ADD COLUMN IF NOT EXISTS regrow_cycles INT NOT NULL DEFAULT 0`,
`UPDATE crops SET regrow_cycles=0 WHERE regrow_cycles < 0`,
`CREATE TABLE IF NOT EXISTS crop_steps(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
crop_id BIGINT NOT NULL,
phase ENUM('pre','post') NOT NULL,
month_offset INT NOT NULL DEFAULT 0,
title VARCHAR(140) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_crop_steps_crop FOREIGN KEY(crop_id) REFERENCES crops(id) ON DELETE CASCADE
)`,
`CREATE TABLE IF NOT EXISTS plans(
@@ -114,7 +128,7 @@ func (a *App) getFieldsByIDs(ids []int64) ([]Field, error) {
}
func (a *App) listCrops() ([]Crop, error) {
rows, err := a.db.Query(`SELECT id,name,sow_start_month,sow_end_month,grow_months FROM crops ORDER BY name`)
rows, err := a.db.Query(`SELECT id,name,sow_start_month,sow_end_month,grow_months,regrow_enabled,regrow_cycles FROM crops ORDER BY name`)
if err != nil {
return nil, err
}
@@ -122,7 +136,7 @@ func (a *App) listCrops() ([]Crop, error) {
var out []Crop
for rows.Next() {
var c Crop
if err := rows.Scan(&c.ID, &c.Name, &c.SowStartMonth, &c.SowEndMonth, &c.GrowMonths); err != nil {
if err := rows.Scan(&c.ID, &c.Name, &c.SowStartMonth, &c.SowEndMonth, &c.GrowMonths, &c.RegrowEnabled, &c.RegrowCycles); err != nil {
return nil, err
}
out = append(out, c)
@@ -132,7 +146,7 @@ func (a *App) listCrops() ([]Crop, error) {
func (a *App) listPlans() ([]Plan, error) {
rows, err := a.db.Query(`
SELECT p.id,p.field_id,COALESCE(p.target_ref,''),COALESCE(p.target_name,''),p.crop_id,COALESCE(c.name,''),p.start_month,p.start_day,p.harvest_month,p.harvest_day,COALESCE(p.notes,'')
SELECT p.id,p.field_id,COALESCE(p.target_ref,''),COALESCE(p.target_name,''),p.crop_id,COALESCE(c.name,''),COALESCE(c.grow_months,1),p.start_month,p.start_day,p.harvest_month,p.harvest_day,COALESCE(p.notes,''),COALESCE(c.regrow_enabled,0),COALESCE(c.regrow_cycles,0)
FROM plans p
JOIN crops c ON c.id=p.crop_id
ORDER BY p.start_month,p.start_day,p.id DESC`)
@@ -143,7 +157,7 @@ func (a *App) listPlans() ([]Plan, error) {
var out []Plan
for rows.Next() {
var p Plan
if err := rows.Scan(&p.ID, &p.FieldID, &p.TargetRef, &p.TargetName, &p.CropID, &p.CropName, &p.StartMonth, &p.StartDay, &p.HarvestMonth, &p.HarvestDay, &p.Notes); err != nil {
if err := rows.Scan(&p.ID, &p.FieldID, &p.TargetRef, &p.TargetName, &p.CropID, &p.CropName, &p.GrowMonths, &p.StartMonth, &p.StartDay, &p.HarvestMonth, &p.HarvestDay, &p.Notes, &p.RegrowEnabled, &p.RegrowCycles); err != nil {
return nil, err
}
out = append(out, p)
@@ -151,6 +165,40 @@ func (a *App) listPlans() ([]Plan, error) {
return out, rows.Err()
}
func (a *App) listCropSteps() ([]CropStep, error) {
rows, err := a.db.Query(`
SELECT s.id,s.crop_id,COALESCE(c.name,''),s.phase,s.month_offset,s.title
FROM crop_steps s
JOIN crops c ON c.id=s.crop_id
ORDER BY c.name, s.phase, s.month_offset, s.id`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []CropStep
for rows.Next() {
var s CropStep
if err := rows.Scan(&s.ID, &s.CropID, &s.CropName, &s.Phase, &s.MonthOffset, &s.Title); err != nil {
return nil, err
}
out = append(out, s)
}
return out, rows.Err()
}
func (a *App) listCropStepsMap() (map[int64][]CropStep, error) {
all, err := a.listCropSteps()
if err != nil {
return nil, err
}
m := make(map[int64][]CropStep)
for _, s := range all {
m[s.CropID] = append(m[s.CropID], s)
}
return m, nil
}
func seedCrops(db *sql.DB) error {
items := []Crop{
{Name: "Weizen", SowStartMonth: 9, SowEndMonth: 11, GrowMonths: 10},
@@ -166,7 +214,7 @@ func seedCrops(db *sql.DB) error {
{Name: "Baumwolle", SowStartMonth: 2, SowEndMonth: 3, GrowMonths: 8},
}
for _, c := range items {
if _, err := db.Exec(`INSERT INTO crops(name,sow_start_month,sow_end_month,grow_months) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE sow_start_month=VALUES(sow_start_month),sow_end_month=VALUES(sow_end_month),grow_months=VALUES(grow_months)`, c.Name, c.SowStartMonth, c.SowEndMonth, c.GrowMonths); err != nil {
if _, err := db.Exec(`INSERT INTO crops(name,sow_start_month,sow_end_month,grow_months,regrow_enabled,regrow_cycles) VALUES (?,?,?,?,0,0) ON DUPLICATE KEY UPDATE sow_start_month=VALUES(sow_start_month),sow_end_month=VALUES(sow_end_month),grow_months=VALUES(grow_months)`, c.Name, c.SowStartMonth, c.SowEndMonth, c.GrowMonths); err != nil {
return err
}
}