fix(issues): auto-seed default statuses and priorities #526

Merged
jmiller merged 1 commits from fix/auto-seed-status-priority into dev 2026-06-06 18:42:06 +00:00
2 changed files with 58 additions and 4 deletions
+28 -2
View File
@@ -33,12 +33,38 @@ func (IssuePriorityDef) TableName() string {
}
// GetIssuePriorityDefsByOrg returns active priority definitions for an org.
// If none exist, seeds the org with default priorities automatically.
func GetIssuePriorityDefsByOrg(ctx context.Context, orgID int64) ([]*IssuePriorityDef, error) {
defs := make([]*IssuePriorityDef, 0, 10)
return defs, db.GetEngine(ctx).
if err := db.GetEngine(ctx).
Where("org_id = ? AND is_active = ?", orgID, true).
OrderBy("sort_order ASC, id ASC").
Find(&defs)
Find(&defs); err != nil {
return nil, err
}
if len(defs) == 0 && orgID > 0 {
if err := seedDefaultIssuePriorities(ctx, orgID); err != nil {
return defs, nil // non-fatal
}
return GetIssuePriorityDefsByOrg(ctx, orgID)
}
return defs, nil
}
// seedDefaultIssuePriorities creates the standard priority presets for an org.
func seedDefaultIssuePriorities(ctx context.Context, orgID int64) error {
defaults := []*IssuePriorityDef{
{OrgID: orgID, Name: "Critical", Color: "#dc2626", Description: "Requires immediate attention", SortOrder: 1, IsActive: true},
{OrgID: orgID, Name: "High", Color: "#f97316", Description: "Should be addressed soon", SortOrder: 2, IsActive: true},
{OrgID: orgID, Name: "Medium", Color: "#eab308", Description: "Normal priority", SortOrder: 3, IsDefault: true, IsActive: true},
{OrgID: orgID, Name: "Low", Color: "#2563eb", Description: "Can wait", SortOrder: 4, IsActive: true},
}
for _, d := range defaults {
if _, err := db.GetEngine(ctx).Insert(d); err != nil {
return err
}
}
return nil
}
// GetAllIssuePriorityDefsByOrg returns all priority definitions (including inactive).
+30 -2
View File
@@ -37,12 +37,40 @@ func (IssueStatusDef) TableName() string {
// ──────────────────────────────────────────────────────────────────────
// GetIssueStatusDefsByOrg returns active status definitions for an org.
// If none exist, seeds the org with default statuses automatically.
func GetIssueStatusDefsByOrg(ctx context.Context, orgID int64) ([]*IssueStatusDef, error) {
defs := make([]*IssueStatusDef, 0, 10)
return defs, db.GetEngine(ctx).
if err := db.GetEngine(ctx).
Where("org_id = ? AND is_active = ?", orgID, true).
OrderBy("sort_order ASC, id ASC").
Find(&defs)
Find(&defs); err != nil {
return nil, err
}
if len(defs) == 0 && orgID > 0 {
if err := seedDefaultIssueStatuses(ctx, orgID); err != nil {
return defs, nil // non-fatal
}
return GetIssueStatusDefsByOrg(ctx, orgID)
}
return defs, nil
}
// seedDefaultIssueStatuses creates the standard status presets for an org.
func seedDefaultIssueStatuses(ctx context.Context, orgID int64) error {
defaults := []*IssueStatusDef{
{OrgID: orgID, Name: "In Progress", Color: "#2563eb", Description: "Work is actively being done", SortOrder: 1, IsActive: true},
{OrgID: orgID, Name: "Needs Info", Color: "#f59e0b", Description: "Waiting for more information", SortOrder: 2, IsActive: true},
{OrgID: orgID, Name: "Blocked", Color: "#dc2626", Description: "Cannot proceed due to dependency", SortOrder: 3, IsActive: true},
{OrgID: orgID, Name: "Resolved", Color: "#16a34a", Description: "Fix implemented and verified", ClosesIssue: true, SortOrder: 4, IsActive: true},
{OrgID: orgID, Name: "Won't Fix", Color: "#6b7280", Description: "Decided not to address", ClosesIssue: true, SortOrder: 5, IsActive: true},
{OrgID: orgID, Name: "Duplicate", Color: "#8b5cf6", Description: "Already tracked elsewhere", ClosesIssue: true, SortOrder: 6, IsActive: true},
}
for _, d := range defaults {
if _, err := db.GetEngine(ctx).Insert(d); err != nil {
return err
}
}
return nil
}
// GetAllIssueStatusDefsByOrg returns all status definitions (including inactive).