From ba4d3df66907a9aa3d4ebfae3f9901d9cc1b8d0a Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Sat, 28 Feb 2026 22:17:55 +0100 Subject: [PATCH] refactor names and minimize dependencies --- cmd/pm/main.go | 2 +- cmd/survey/main.go | 6 +-- cmd/survey/tasks/backlogRefinement.go | 29 ++++++-------- cmd/survey/tasks/base.go | 34 ++++++++++------ cmd/survey/tasks/codingTask.go | 13 +++--- cmd/survey/tasks/createIssue.go | 18 ++++----- cmd/survey/tasks/dependencyManagement.go | 13 +++--- cmd/survey/tasks/gitTask.go | 13 +++--- cmd/survey/tasks/issueTriage.go | 13 +++--- cmd/survey/tasks/milestoneTracking.go | 27 ++++++------- cmd/survey/tasks/priorityManagement.go | 50 ++++++++++++------------ cmd/survey/tasks/reportGeneration.go | 33 +++++++--------- cmd/survey/tasks/sprintPlanning.go | 27 ++++++------- cmd/survey/tasks/stakeholderUpdate.go | 25 ++++++------ cmd/survey/tasks/teamCapacity.go | 29 ++++++-------- cmd/tui/main.go | 2 +- cmd/web/main.go | 2 +- pkg/cli/cli.go | 2 +- pkg/repl/repl.go | 6 +-- pkg/task/{ui => }/questionnaire.go | 2 +- pkg/task/register.go | 8 ++-- pkg/task/runner.go | 6 +-- pkg/task/{ui/task.go => taskui.go} | 2 +- pkg/tui/tui.go | 2 +- pkg/web/web.go | 2 +- 25 files changed, 169 insertions(+), 197 deletions(-) rename pkg/task/{ui => }/questionnaire.go (99%) rename pkg/task/{ui/task.go => taskui.go} (99%) diff --git a/cmd/pm/main.go b/cmd/pm/main.go index 3746bcb..2b1ecb0 100644 --- a/cmd/pm/main.go +++ b/cmd/pm/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - if err := cli.NewCli(issuesCmd.RootCmd).Run(context.Background(), models.BaseConfig); err != nil { + if err := cli.New(issuesCmd.RootCmd).Run(context.Background(), models.BaseConfig); err != nil { return } } diff --git a/cmd/survey/main.go b/cmd/survey/main.go index a4d5612..78158d3 100644 --- a/cmd/survey/main.go +++ b/cmd/survey/main.go @@ -32,9 +32,9 @@ func main() { } func init() { - task.RegisterInterface("tui", tui.NewTui()) - task.RegisterInterface("web", web.NewWeb()) - task.RegisterInterface("repl", repl.NewRepl()) + task.RegisterInterface("tui", tui.New()) + task.RegisterInterface("web", web.New()) + task.RegisterInterface("repl", repl.New()) task.RegisterTask("create_issue", func(app *service.App) task.Tasker { return tasks.NewCreateIssueTask(app) diff --git a/cmd/survey/tasks/backlogRefinement.go b/cmd/survey/tasks/backlogRefinement.go index aaec36a..6fce225 100644 --- a/cmd/survey/tasks/backlogRefinement.go +++ b/cmd/survey/tasks/backlogRefinement.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -26,19 +23,19 @@ Focus on making the backlog a reliable source of upcoming work.` type BacklogRefinementTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewBacklogRefinementTask(app *service.App) *BacklogRefinementTask { +func NewBacklogRefinementTask(app *App) *BacklogRefinementTask { return &BacklogRefinementTask{app: app, done: false} } -func (t *BacklogRefinementTask) Config() task.Config { +func (t *BacklogRefinementTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/refinement-task-stats.json") } -func (t *BacklogRefinementTask) Details() taskui.TaskDetails { +func (t *BacklogRefinementTask) Details() TaskDetails { return BaseDetails(). WithTitle("Backlog Refinement Task"). WithDescription(backlogRefinementDescription). @@ -46,7 +43,7 @@ func (t *BacklogRefinementTask) Details() taskui.TaskDetails { WithDifficulty("Medium") } -func (t *BacklogRefinementTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *BacklogRefinementTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -66,42 +63,42 @@ func (t *BacklogRefinementTask) Setup(ctx context.Context) error { } refinementIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Old feature request: Fax integration"). WithDescription("Allow sending reports via fax. DEPRECATED - nobody uses fax anymore"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("User profile page"). WithDescription("Create page for users to view profile. DUPLICATE of user-management epic"). WithPriority(2). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Mobile app redesign"). WithDescription("Redesign mobile interface with modern UI patterns. Still relevant, needs clarity"). WithPriority(1). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Legacy data export tool"). WithDescription("Tool for exporting data in old format. OBSOLETE - format no longer supported"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("API v1 documentation"). WithDescription("Document old API version. DEPRECATED - migrating to v2"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Customer feedback system"). WithDescription("Build system for collecting user feedback. HIGH VALUE - prioritize"). WithPriority(2). @@ -114,7 +111,7 @@ func (t *BacklogRefinementTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Backlog Refinement Session"). WithDescription(backlogRefinementDescription). Build() diff --git a/cmd/survey/tasks/base.go b/cmd/survey/tasks/base.go index 6b5538c..dafae93 100644 --- a/cmd/survey/tasks/base.go +++ b/cmd/survey/tasks/base.go @@ -7,15 +7,27 @@ import ( "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/pkg/repl" "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/LazyBachelor/LazyPM/pkg/tui" "github.com/LazyBachelor/LazyPM/pkg/web" "github.com/charmbracelet/huh" ) +type App = service.App +type Config = models.Config type ValidationFeedback = models.ValidationFeedback -type InterfaceType = models.InterfaceType + +type Issue = models.Issue +type IssueFilter = models.IssueFilter + +type Questions = models.Questions +type TaskDetails = models.TaskDetails + type Interface = task.Interface +type InterfaceType = models.InterfaceType + +func NewIssueBuilder() *models.IssueBuilder { + return models.NewIssueBuilder() +} const ( InterfaceTypeCLI = models.InterfaceTypeCLI @@ -37,8 +49,8 @@ func InterfaceToType(it Interface) InterfaceType { } } -func BaseDetails() taskui.TaskDetails { - return taskui.TaskDetails{ +func BaseDetails() TaskDetails { + return TaskDetails{ Title: "Base Task", Description: "This is a base task.", TimeToComplete: "10m", @@ -46,17 +58,17 @@ func BaseDetails() taskui.TaskDetails { } } -func BaseConfig() task.Config { +func BaseConfig() Config { return models.BaseConfig } -func ClearIssues(app *service.App) error { +func ClearIssues(app *App) error { return app.Issues.DeleteIssues() } -func BaseQuestions(interfaceType task.InterfaceType) taskui.Questions { +func BaseQuestions(interfaceType InterfaceType) Questions { var taskRating int - return taskui.Questions{ + return Questions{ huh.NewGroup( huh.NewConfirm(). Title("Did you complete the task?"), @@ -78,21 +90,21 @@ func Question(fields ...huh.Field) *huh.Group { return huh.NewGroup(fields...) } -func ReplQuestion(interfaceType task.InterfaceType, fields ...huh.Field) *huh.Group { +func ReplQuestion(interfaceType InterfaceType, fields ...huh.Field) *huh.Group { if interfaceType != InterfaceTypeREPL { return nil } return huh.NewGroup(fields...) } -func WebQuestion(interfaceType task.InterfaceType, fields ...huh.Field) *huh.Group { +func WebQuestion(interfaceType InterfaceType, fields ...huh.Field) *huh.Group { if interfaceType != InterfaceTypeWeb { return nil } return huh.NewGroup(fields...) } -func TUIQuestion(interfaceType task.InterfaceType, fields ...huh.Field) *huh.Group { +func TUIQuestion(interfaceType InterfaceType, fields ...huh.Field) *huh.Group { if interfaceType != InterfaceTypeTUI { return nil } diff --git a/cmd/survey/tasks/codingTask.go b/cmd/survey/tasks/codingTask.go index fea4be5..d086612 100644 --- a/cmd/survey/tasks/codingTask.go +++ b/cmd/survey/tasks/codingTask.go @@ -4,10 +4,7 @@ import ( "context" "os" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -35,22 +32,22 @@ Please write your code below this line! type CodingTask struct { done bool - app *service.App + app *App } -func NewCodingTask(app *service.App) *CodingTask { +func NewCodingTask(app *App) *CodingTask { return &CodingTask{app: app, done: false} } -func (t *CodingTask) Config() task.Config { +func (t *CodingTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/coding-task-stats.json") } -func (t *CodingTask) Details() taskui.TaskDetails { +func (t *CodingTask) Details() TaskDetails { return BaseDetails().WithTitle("Coding Task").WithDescription(codingDescription) } -func (t *CodingTask) Questions(interfaceType task.InterfaceType) (questions taskui.Questions) { +func (t *CodingTask) Questions(interfaceType InterfaceType) (questions Questions) { return BaseQuestions(interfaceType). With( ReplQuestion(interfaceType, diff --git a/cmd/survey/tasks/createIssue.go b/cmd/survey/tasks/createIssue.go index aea8567..3907997 100644 --- a/cmd/survey/tasks/createIssue.go +++ b/cmd/survey/tasks/createIssue.go @@ -4,11 +4,7 @@ import ( "context" "fmt" - "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" ) const description = `You are tasked with creating a new issue in the project management system. @@ -26,23 +22,23 @@ Make sure to fill out all the necessary details to help others understand the wo type CreateIssueTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewCreateIssueTask(app *service.App) *CreateIssueTask { +func NewCreateIssueTask(app *App) *CreateIssueTask { return &CreateIssueTask{app: app, done: false} } -func (t *CreateIssueTask) Config() task.Config { +func (t *CreateIssueTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/create-issue-stats.json") } -func (t *CreateIssueTask) Details() taskui.TaskDetails { +func (t *CreateIssueTask) Details() TaskDetails { return BaseDetails().WithTitle("Create Issue Task").WithDescription(description) } -func (t *CreateIssueTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *CreateIssueTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType) } @@ -51,7 +47,7 @@ func (t *CreateIssueTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Create a New Issue"). WithDescription(description). Build() diff --git a/cmd/survey/tasks/dependencyManagement.go b/cmd/survey/tasks/dependencyManagement.go index 8c0dc23..6816f27 100644 --- a/cmd/survey/tasks/dependencyManagement.go +++ b/cmd/survey/tasks/dependencyManagement.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -25,19 +22,19 @@ Resolving dependencies in the right order is critical for efficient team workflo type DependencyManagementTask struct { done bool - app *service.App + app *App setupIssue *models.Issue } -func NewDependencyManagementTask(app *service.App) *DependencyManagementTask { +func NewDependencyManagementTask(app *App) *DependencyManagementTask { return &DependencyManagementTask{app: app, done: false} } -func (t *DependencyManagementTask) Config() task.Config { +func (t *DependencyManagementTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/dependency-task-stats.json") } -func (t *DependencyManagementTask) Details() taskui.TaskDetails { +func (t *DependencyManagementTask) Details() TaskDetails { return BaseDetails(). WithTitle("Dependency Management Task"). WithDescription(dependencyManagementDescription). @@ -45,7 +42,7 @@ func (t *DependencyManagementTask) Details() taskui.TaskDetails { WithDifficulty("Hard") } -func (t *DependencyManagementTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *DependencyManagementTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). diff --git a/cmd/survey/tasks/gitTask.go b/cmd/survey/tasks/gitTask.go index bbcfe3d..a474169 100644 --- a/cmd/survey/tasks/gitTask.go +++ b/cmd/survey/tasks/gitTask.go @@ -8,8 +8,6 @@ import ( "github.com/LazyBachelor/LazyPM/internal/models" "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" "github.com/go-git/go-git/v6" ) @@ -35,19 +33,19 @@ type GitTask struct { app *service.App } -func NewGitTask(app *service.App) *GitTask { +func NewGitTask(app *App) *GitTask { return &GitTask{app: app, done: false} } -func (t *GitTask) Config() task.Config { +func (t *GitTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/git-task-stats.json") } -func (t *GitTask) Details() taskui.TaskDetails { +func (t *GitTask) Details() TaskDetails { return BaseDetails().WithTitle("Git Task").WithDescription(gitTaskDescription) } -func (t *GitTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *GitTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[string]().Title("What Git Interface did you use?"). @@ -72,8 +70,7 @@ func (t *GitTask) Setup(ctx context.Context) error { } os.WriteFile("./task/README.md", - []byte("This is a Git task. Please perform a Git operation here."), - 0o644) + []byte("This is a Git task. Please perform a Git operation here."), 0o644) t.setupIssue = models.NewIssueBuilder(). WithTitle("Git Task Setup Issue"). diff --git a/cmd/survey/tasks/issueTriage.go b/cmd/survey/tasks/issueTriage.go index cf2de89..f6cdce4 100644 --- a/cmd/survey/tasks/issueTriage.go +++ b/cmd/survey/tasks/issueTriage.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -25,19 +22,19 @@ Make decisions quickly but thoughtfully. Not everything is high priority!` type IssueTriageTask struct { done bool - app *service.App + app *App setupIssue *models.Issue } -func NewIssueTriageTask(app *service.App) *IssueTriageTask { +func NewIssueTriageTask(app *App) *IssueTriageTask { return &IssueTriageTask{app: app, done: false} } -func (t *IssueTriageTask) Config() task.Config { +func (t *IssueTriageTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/triage-task-stats.json") } -func (t *IssueTriageTask) Details() taskui.TaskDetails { +func (t *IssueTriageTask) Details() TaskDetails { return BaseDetails(). WithTitle("Issue Triage Task"). WithDescription(issueTriageDescription). @@ -45,7 +42,7 @@ func (t *IssueTriageTask) Details() taskui.TaskDetails { WithDifficulty("Medium") } -func (t *IssueTriageTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *IssueTriageTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). diff --git a/cmd/survey/tasks/milestoneTracking.go b/cmd/survey/tasks/milestoneTracking.go index 130fb1d..483ef8b 100644 --- a/cmd/survey/tasks/milestoneTracking.go +++ b/cmd/survey/tasks/milestoneTracking.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -26,19 +23,19 @@ The milestone deadline is 2 weeks away. Some issues have dependencies that need type MilestoneTrackingTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewMilestoneTrackingTask(app *service.App) *MilestoneTrackingTask { +func NewMilestoneTrackingTask(app *App) *MilestoneTrackingTask { return &MilestoneTrackingTask{app: app, done: false} } -func (t *MilestoneTrackingTask) Config() task.Config { +func (t *MilestoneTrackingTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/milestone-task-stats.json") } -func (t *MilestoneTrackingTask) Details() taskui.TaskDetails { +func (t *MilestoneTrackingTask) Details() TaskDetails { return BaseDetails(). WithTitle("Milestone Tracking Task"). WithDescription(milestoneTrackingDescription). @@ -46,7 +43,7 @@ func (t *MilestoneTrackingTask) Details() taskui.TaskDetails { WithDifficulty("Easy") } -func (t *MilestoneTrackingTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *MilestoneTrackingTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -66,35 +63,35 @@ func (t *MilestoneTrackingTask) Setup(ctx context.Context) error { } milestoneIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Core API endpoints"). WithDescription("Implement REST API for core functionality. COMPLETED"). WithPriority(1). WithStatus(models.StatusClosed). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Frontend dashboard"). WithDescription("Create main dashboard UI. In progress - 80% complete"). WithPriority(1). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("User management module"). WithDescription("Depends on Core API. Add user CRUD operations. Currently blocked"). WithPriority(2). WithStatus(models.StatusBlocked). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Analytics reporting"). WithDescription("Generate usage analytics reports. Not started yet"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Email notifications"). WithDescription("Setup email service for alerts. 50% complete"). WithPriority(2). @@ -107,7 +104,7 @@ func (t *MilestoneTrackingTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Q1 Release Milestone Tracking"). WithDescription(milestoneTrackingDescription). Build() diff --git a/cmd/survey/tasks/priorityManagement.go b/cmd/survey/tasks/priorityManagement.go index 325eae1..2313b54 100644 --- a/cmd/survey/tasks/priorityManagement.go +++ b/cmd/survey/tasks/priorityManagement.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -26,19 +23,19 @@ The production database is experiencing intermittent connection failures affecti type PriorityManagementTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewPriorityManagementTask(app *service.App) *PriorityManagementTask { +func NewPriorityManagementTask(app *App) *PriorityManagementTask { return &PriorityManagementTask{app: app, done: false} } -func (t *PriorityManagementTask) Config() task.Config { +func (t *PriorityManagementTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/priority-task-stats.json") } -func (t *PriorityManagementTask) Details() taskui.TaskDetails { +func (t *PriorityManagementTask) Details() TaskDetails { return BaseDetails(). WithTitle("Priority Management Task"). WithDescription(priorityManagementDescription). @@ -46,18 +43,19 @@ func (t *PriorityManagementTask) Details() taskui.TaskDetails { WithDifficulty("Easy") } -func (t *PriorityManagementTask) Questions(interfaceType task.InterfaceType) taskui.Questions { - return BaseQuestions(interfaceType).With( - huh.NewGroup( - huh.NewSelect[int](). - Title("How many issues did you reprioritize or comment on?"). - Options( - huh.NewOption("1-2", 1), - huh.NewOption("3-4", 2), - huh.NewOption("5+", 3), - ), - ), - ) +func (t *PriorityManagementTask) Questions(interfaceType InterfaceType) Questions { + return BaseQuestions(interfaceType). + With( + huh.NewGroup( + huh.NewSelect[int](). + Title("How many issues did you reprioritize or comment on?"). + Options( + huh.NewOption("1-2", 1), + huh.NewOption("3-4", 2), + huh.NewOption("5+", 3), + ), + ), + ) } func (t *PriorityManagementTask) Setup(ctx context.Context) error { @@ -66,35 +64,35 @@ func (t *PriorityManagementTask) Setup(ctx context.Context) error { } priorityIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Database connection failures"). WithDescription("PRODUCTION CRITICAL: Intermittent DB connection failures affecting all users. Needs immediate attention."). WithPriority(1). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("UI theme updates"). WithDescription("Update color scheme per new brand guidelines. Currently in progress but can wait."). WithPriority(1). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Feature: Dark mode"). WithDescription("Add dark mode toggle to settings. Nice to have, can be deferred."). WithPriority(2). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("API rate limiting"). WithDescription("Add rate limiting to public API endpoints. Security enhancement."). WithPriority(2). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Documentation updates"). WithDescription("Update API documentation for v2 endpoints. Can be deferred."). WithPriority(3). @@ -107,7 +105,7 @@ func (t *PriorityManagementTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Priority Rebalancing"). WithDescription(priorityManagementDescription). Build() diff --git a/cmd/survey/tasks/reportGeneration.go b/cmd/survey/tasks/reportGeneration.go index 6745c6e..d5d4c43 100644 --- a/cmd/survey/tasks/reportGeneration.go +++ b/cmd/survey/tasks/reportGeneration.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -26,19 +23,19 @@ Add summary comments to at least 3 key issues that stakeholders should know abou type ReportGenerationTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewReportGenerationTask(app *service.App) *ReportGenerationTask { +func NewReportGenerationTask(app *App) *ReportGenerationTask { return &ReportGenerationTask{app: app, done: false} } -func (t *ReportGenerationTask) Config() task.Config { +func (t *ReportGenerationTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/report-task-stats.json") } -func (t *ReportGenerationTask) Details() taskui.TaskDetails { +func (t *ReportGenerationTask) Details() TaskDetails { return BaseDetails(). WithTitle("Status Report Generation"). WithDescription(reportGenerationDescription). @@ -46,7 +43,7 @@ func (t *ReportGenerationTask) Details() taskui.TaskDetails { WithDifficulty("Easy") } -func (t *ReportGenerationTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *ReportGenerationTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -66,35 +63,35 @@ func (t *ReportGenerationTask) Setup(ctx context.Context) error { } reportIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("User login feature"). WithDescription("Allow users to login with email/password."). WithPriority(1). WithStatus(models.StatusClosed). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Password reset"). WithDescription("Email-based password reset flow. In Progress"). WithPriority(2). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Database optimization"). WithDescription("Optimize slow queries identified in profiling."). WithPriority(1). WithStatus(models.StatusBlocked). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Mobile responsive design"). WithDescription("Make UI work on mobile devices."). WithPriority(2). WithStatus(models.StatusClosed). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Third-party API integration"). WithDescription("Waiting for vendor API documentation."). WithPriority(1). @@ -103,13 +100,11 @@ func (t *ReportGenerationTask) Setup(ctx context.Context) error { Build(), } - for _, issue := range reportIssues { - if err := t.app.Issues.CreateIssue(ctx, issue, ""); err != nil { - return err - } + if err := t.app.Issues.CreateIssues(ctx, reportIssues, ""); err != nil { + return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Weekly Status Report"). WithDescription(reportGenerationDescription). Build() diff --git a/cmd/survey/tasks/sprintPlanning.go b/cmd/survey/tasks/sprintPlanning.go index 05175cb..409521d 100644 --- a/cmd/survey/tasks/sprintPlanning.go +++ b/cmd/survey/tasks/sprintPlanning.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -27,19 +24,19 @@ The goal is to create a realistic sprint plan that delivers value while respecti type SprintPlanningTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewSprintPlanningTask(app *service.App) *SprintPlanningTask { +func NewSprintPlanningTask(app *App) *SprintPlanningTask { return &SprintPlanningTask{app: app, done: false} } -func (t *SprintPlanningTask) Config() task.Config { +func (t *SprintPlanningTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/sprint-planning-stats.json") } -func (t *SprintPlanningTask) Details() taskui.TaskDetails { +func (t *SprintPlanningTask) Details() TaskDetails { return BaseDetails(). WithTitle("Sprint Planning Task"). WithDescription(sprintPlanningDescription). @@ -47,7 +44,7 @@ func (t *SprintPlanningTask) Details() taskui.TaskDetails { WithDifficulty("Medium") } -func (t *SprintPlanningTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *SprintPlanningTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -67,35 +64,35 @@ func (t *SprintPlanningTask) Setup(ctx context.Context) error { } backlogIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Implement user authentication"). WithDescription("Add login/logout functionality. Priority: High"). WithPriority(1). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Design database schema"). WithDescription("Create tables for users and orders. Priority: High"). WithPriority(1). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Setup CI/CD pipeline"). WithDescription("Configure automated testing and deployment. Currently blocked by server setup"). WithPriority(2). WithStatus(models.StatusBlocked). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Create API documentation"). WithDescription("Document all REST endpoints. Priority: Low"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Implement search functionality"). WithDescription("Depends on database schema. Priority: Medium"). WithPriority(2). @@ -108,7 +105,7 @@ func (t *SprintPlanningTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Sprint Planning - Week 1"). WithDescription(sprintPlanningDescription). Build() diff --git a/cmd/survey/tasks/stakeholderUpdate.go b/cmd/survey/tasks/stakeholderUpdate.go index 7cc4290..1507cbf 100644 --- a/cmd/survey/tasks/stakeholderUpdate.go +++ b/cmd/survey/tasks/stakeholderUpdate.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -27,19 +24,19 @@ The stakeholder is interested in the Dashboard Enhancement and Export Features s type StakeholderUpdateTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewStakeholderUpdateTask(app *service.App) *StakeholderUpdateTask { +func NewStakeholderUpdateTask(app *App) *StakeholderUpdateTask { return &StakeholderUpdateTask{app: app, done: false} } -func (t *StakeholderUpdateTask) Config() task.Config { +func (t *StakeholderUpdateTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/stakeholder-task-stats.json") } -func (t *StakeholderUpdateTask) Details() taskui.TaskDetails { +func (t *StakeholderUpdateTask) Details() TaskDetails { return BaseDetails(). WithTitle("Stakeholder Update Task"). WithDescription(stakeholderUpdateDescription). @@ -47,7 +44,7 @@ func (t *StakeholderUpdateTask) Details() taskui.TaskDetails { WithDifficulty("Easy") } -func (t *StakeholderUpdateTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *StakeholderUpdateTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -68,28 +65,28 @@ func (t *StakeholderUpdateTask) Setup(ctx context.Context) error { } stakeholderIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Dashboard Enhancement - Charts"). WithDescription("Add interactive charts to the main dashboard (stakeholder request). COMPLETED"). WithPriority(1). WithStatus(models.StatusClosed). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Dashboard Enhancement - Filters"). WithDescription("Add date range filters to dashboard (stakeholder request). In Progress"). WithPriority(2). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Export to PDF"). WithDescription("Allow exporting reports to PDF format (stakeholder request). In Progress"). WithPriority(1). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Export to Excel"). WithDescription("Allow exporting data to Excel format (stakeholder request). BLOCKED - waiting for library approval"). WithPriority(2). @@ -102,7 +99,7 @@ func (t *StakeholderUpdateTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Stakeholder Update Preparation"). WithDescription(stakeholderUpdateDescription). Build() diff --git a/cmd/survey/tasks/teamCapacity.go b/cmd/survey/tasks/teamCapacity.go index 73dd842..a95c21e 100644 --- a/cmd/survey/tasks/teamCapacity.go +++ b/cmd/survey/tasks/teamCapacity.go @@ -4,10 +4,7 @@ import ( "context" "github.com/LazyBachelor/LazyPM/internal/models" - "github.com/LazyBachelor/LazyPM/internal/service" "github.com/LazyBachelor/LazyPM/internal/utils" - "github.com/LazyBachelor/LazyPM/pkg/task" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" "github.com/charmbracelet/huh" ) @@ -26,19 +23,19 @@ Team member Alice is on vacation next week (mentioned in her issues). Bob can on type TeamCapacityTask struct { done bool - app *service.App - setupIssue *models.Issue + app *App + setupIssue *Issue } -func NewTeamCapacityTask(app *service.App) *TeamCapacityTask { +func NewTeamCapacityTask(app *App) *TeamCapacityTask { return &TeamCapacityTask{app: app, done: false} } -func (t *TeamCapacityTask) Config() task.Config { +func (t *TeamCapacityTask) Config() Config { return BaseConfig().WithStatisticsStoragePath("./.pm/capacity-task-stats.json") } -func (t *TeamCapacityTask) Details() taskui.TaskDetails { +func (t *TeamCapacityTask) Details() TaskDetails { return BaseDetails(). WithTitle("Team Capacity Management"). WithDescription(teamCapacityDescription). @@ -46,7 +43,7 @@ func (t *TeamCapacityTask) Details() taskui.TaskDetails { WithDifficulty("Medium") } -func (t *TeamCapacityTask) Questions(interfaceType task.InterfaceType) taskui.Questions { +func (t *TeamCapacityTask) Questions(interfaceType InterfaceType) Questions { return BaseQuestions(interfaceType).With( huh.NewGroup( huh.NewSelect[int](). @@ -66,42 +63,42 @@ func (t *TeamCapacityTask) Setup(ctx context.Context) error { } capacityIssues := []*models.Issue{ - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Authentication module"). WithDescription("Implement OAuth2 flow. Assigned to: Alice (on vacation next week)"). WithPriority(1). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Payment integration"). WithDescription("Integrate Stripe API. Assigned to: Alice (on vacation next week)"). WithPriority(1). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Dashboard widgets"). WithDescription("Create reusable widget components. Assigned to: Bob (50% capacity)"). WithPriority(2). WithStatus(models.StatusInProgress). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("API rate limiting"). WithDescription("Add rate limiting middleware. Assigned to: Bob (50% capacity)"). WithPriority(2). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Data migration"). WithDescription("Migrate legacy data to new schema. Assigned to: Charlie (full capacity)"). WithPriority(3). WithStatus(models.StatusOpen). WithIssueType(models.TypeTask). Build(), - models.NewIssueBuilder(). + NewIssueBuilder(). WithTitle("Bug fixes batch"). WithDescription("Fix reported bugs from QA. Assigned to: Diana (full capacity)"). WithPriority(1). @@ -114,7 +111,7 @@ func (t *TeamCapacityTask) Setup(ctx context.Context) error { return err } - t.setupIssue = models.NewBaseIssue(). + t.setupIssue = NewIssueBuilder(). WithTitle("Team Capacity Planning"). WithDescription(teamCapacityDescription). Build() diff --git a/cmd/tui/main.go b/cmd/tui/main.go index ec31695..23f7049 100644 --- a/cmd/tui/main.go +++ b/cmd/tui/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - if err := tui.NewTui().Run(context.Background(), models.BaseConfig); err != nil { + if err := tui.New().Run(context.Background(), models.BaseConfig); err != nil { return } } diff --git a/cmd/web/main.go b/cmd/web/main.go index cd8f4b5..252f6e5 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - if err := web.NewWeb().Run(context.Background(), models.BaseConfig); err != nil { + if err := web.New().Run(context.Background(), models.BaseConfig); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 4ef5c12..b64da96 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -18,7 +18,7 @@ type CLI struct { RootCmd *cobra.Command } -func NewCli(rootCmd *cobra.Command) *CLI { +func New(rootCmd *cobra.Command) *CLI { return &CLI{ RootCmd: rootCmd, } diff --git a/pkg/repl/repl.go b/pkg/repl/repl.go index 46e616e..bf6d460 100644 --- a/pkg/repl/repl.go +++ b/pkg/repl/repl.go @@ -30,15 +30,15 @@ You can also run shell commands directly. Type 'exit' or 'quit' to leave.` ) type REPL struct { - feedbackChan chan task.ValidationFeedback + feedbackChan chan ValidationFeedback quitChan chan bool app *App - currentFeedback task.ValidationFeedback + currentFeedback ValidationFeedback exitRequested bool } -func NewRepl() *REPL { +func New() *REPL { return &REPL{} } diff --git a/pkg/task/ui/questionnaire.go b/pkg/task/questionnaire.go similarity index 99% rename from pkg/task/ui/questionnaire.go rename to pkg/task/questionnaire.go index 55a7a9d..09f8490 100644 --- a/pkg/task/ui/questionnaire.go +++ b/pkg/task/questionnaire.go @@ -1,4 +1,4 @@ -package taskui +package task import ( "charm.land/lipgloss/v2" diff --git a/pkg/task/register.go b/pkg/task/register.go index 37067fa..503a615 100644 --- a/pkg/task/register.go +++ b/pkg/task/register.go @@ -2,8 +2,6 @@ package task import ( "fmt" - - "github.com/LazyBachelor/LazyPM/internal/service" ) var interfaceRegistry = make(map[string]Interface) @@ -31,16 +29,16 @@ func ListInterfaces() []string { return names } -var taskRegistry = make(map[string]func(*service.App) Tasker) +var taskRegistry = make(map[string]func(*App) Tasker) -func RegisterTask(name string, constructor func(*service.App) Tasker) { +func RegisterTask(name string, constructor func(*App) Tasker) { if _, exists := taskRegistry[name]; exists { panic(fmt.Sprintf("task %q already registered", name)) } taskRegistry[name] = constructor } -func GetTask(name string, app *service.App) (Tasker, error) { +func GetTask(name string, app *App) (Tasker, error) { constructor, ok := taskRegistry[name] if !ok { return nil, fmt.Errorf("task %q not found", name) diff --git a/pkg/task/runner.go b/pkg/task/runner.go index ab0cad8..a9c4389 100644 --- a/pkg/task/runner.go +++ b/pkg/task/runner.go @@ -6,10 +6,10 @@ import ( "time" "github.com/LazyBachelor/LazyPM/internal/models" - taskui "github.com/LazyBachelor/LazyPM/pkg/task/ui" tea "github.com/charmbracelet/bubbletea" ) +type App = models.App type Config = models.Config type Tasker = models.Tasker @@ -43,7 +43,7 @@ func RunTask(ctx context.Context, t Tasker, i Interface, iType InterfaceType) er } // Show task intro - detailsScreen := taskui.NewTaskModel(t.Details()) + detailsScreen := NewTaskModel(t.Details()) model, err := tea.NewProgram(detailsScreen, tea.WithAltScreen()).Run() if err != nil { return err @@ -79,7 +79,7 @@ func RunTask(ctx context.Context, t Tasker, i Interface, iType InterfaceType) er // Show questionnaire questions := t.Questions(iType) - questionare := taskui.NewQuestionnaireModel(questions) + questionare := NewQuestionnaireModel(questions) model, err = tea.NewProgram(questionare, tea.WithAltScreen()).Run() if err != nil { return err diff --git a/pkg/task/ui/task.go b/pkg/task/taskui.go similarity index 99% rename from pkg/task/ui/task.go rename to pkg/task/taskui.go index 9c250a4..cfdbea0 100644 --- a/pkg/task/ui/task.go +++ b/pkg/task/taskui.go @@ -1,4 +1,4 @@ -package taskui +package task import ( "fmt" diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index 7cd99f5..cfed482 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -17,7 +17,7 @@ type Tui struct { quitChan chan bool } -func NewTui() *Tui { +func New() *Tui { return &Tui{} } diff --git a/pkg/web/web.go b/pkg/web/web.go index bc419d4..e5e0fff 100644 --- a/pkg/web/web.go +++ b/pkg/web/web.go @@ -24,7 +24,7 @@ type Web struct { quitChan chan bool } -func NewWeb() *Web { +func New() *Web { return &Web{} }