Skip to content

Commit

Permalink
First implementation of subprojects and subtasks, needs testing
Browse files Browse the repository at this point in the history
  • Loading branch information
d4r1us-drk committed Aug 15, 2024
1 parent ee212a0 commit d1714e6
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 88 deletions.
26 changes: 26 additions & 0 deletions cmd/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func init() {

editCmd.Flags().StringP("name", "n", "", "New name")
editCmd.Flags().StringP("description", "d", "", "New description")
editCmd.Flags().StringP("project", "p", "", "New parent project name or ID")
editCmd.Flags().StringP("task", "t", "", "New parent task ID for subtasks")
editCmd.Flags().StringP("due", "D", "", "New due date for task (format: YYYY-MM-DD HH:MM)")
editCmd.Flags().
IntP("priority", "r", 0, "New priority for task (1: High, 2: Medium, 3: Low, 4: None)")
Expand All @@ -63,13 +65,27 @@ func editProject(cmd *cobra.Command, repo *repository.Repository, id int) {

name, _ := cmd.Flags().GetString("name")
description, _ := cmd.Flags().GetString("description")
parentProjectIdentifier, _ := cmd.Flags().GetString("project")

if name != "" {
project.Name = name
}
if description != "" {
project.Description = description
}
if parentProjectIdentifier != "" {
if utils.IsNumeric(parentProjectIdentifier) {
parentID, _ := strconv.Atoi(parentProjectIdentifier)
project.ParentProjectId = &parentID
} else {
parentProject, err := repo.GetProjectByName(parentProjectIdentifier)
if err != nil || parentProject == nil {
fmt.Printf("Parent project '%s' not found.\n", parentProjectIdentifier)
return
}
project.ParentProjectId = &parentProject.ID
}
}

err = repo.UpdateProject(project)
if err != nil {
Expand All @@ -91,6 +107,7 @@ func editTask(cmd *cobra.Command, repo *repository.Repository, id int) {
description, _ := cmd.Flags().GetString("description")
dueDateStr, _ := cmd.Flags().GetString("due")
priority, _ := cmd.Flags().GetInt("priority")
parentTaskIdentifier, _ := cmd.Flags().GetString("task")

if name != "" {
task.Name = name
Expand All @@ -113,6 +130,15 @@ func editTask(cmd *cobra.Command, repo *repository.Repository, id int) {
fmt.Println("Invalid priority. Keeping the existing priority.")
}
}
if parentTaskIdentifier != "" {
if utils.IsNumeric(parentTaskIdentifier) {
parentID, _ := strconv.Atoi(parentTaskIdentifier)
task.ParentTaskId = &parentID
} else {
fmt.Println("Parent task must be identified by a numeric ID.")
return
}
}

err = repo.UpdateTask(task)
if err != nil {
Expand Down
156 changes: 118 additions & 38 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"strconv"
"strings"

"github.com/d4r1us-drk/clido/pkg/models"
"github.com/d4r1us-drk/clido/pkg/repository"
Expand All @@ -31,13 +32,14 @@ var listCmd = &cobra.Command{
defer repo.Close()

outputJSON, _ := cmd.Flags().GetBool("json")
treeView, _ := cmd.Flags().GetBool("tree")

switch args[0] {
case "projects":
listProjects(repo, outputJSON)
listProjects(repo, outputJSON, treeView)
case "tasks":
projectFilter, _ := cmd.Flags().GetString("project")
listTasks(repo, projectFilter, outputJSON)
listTasks(repo, projectFilter, outputJSON, treeView)
default:
fmt.Println("Invalid option. Use 'list projects' or 'list tasks'.")
}
Expand All @@ -48,9 +50,10 @@ func init() {
rootCmd.AddCommand(listCmd)
listCmd.Flags().StringP("project", "p", "", "Filter tasks by project name or ID")
listCmd.Flags().BoolP("json", "j", false, "Output list in JSON format")
listCmd.Flags().BoolP("tree", "t", false, "Display projects or tasks in a tree-like structure")
}

func listProjects(repo *repository.Repository, outputJSON bool) {
func listProjects(repo *repository.Repository, outputJSON bool, treeView bool) {
projects, err := repo.GetAllProjects()
if err != nil {
fmt.Printf("Error listing projects: %v\n", err)
Expand All @@ -64,25 +67,14 @@ func listProjects(repo *repository.Repository, outputJSON bool) {
return
}
fmt.Println(string(jsonData))
} else if treeView {
printProjectTree(repo, projects, nil, 0)
} else {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"ID", "Name", "Description"})
table.SetRowLine(true)

for _, project := range projects {
table.Append([]string{
strconv.Itoa(project.ID),
utils.WrapText(project.Name, 30),
utils.WrapText(project.Description, 50),
})
}

fmt.Println("Projects:")
table.Render()
printProjectTable(repo, projects)
}
}

func listTasks(repo *repository.Repository, projectFilter string, outputJSON bool) {
func listTasks(repo *repository.Repository, projectFilter string, outputJSON bool, treeView bool) {
var tasks []*models.Task
var err error

Expand Down Expand Up @@ -128,32 +120,120 @@ func listTasks(repo *repository.Repository, projectFilter string, outputJSON boo
return
}
fmt.Println(string(jsonData))
} else if treeView {
printTaskTree(repo, tasks, nil, 0)
} else {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{
"ID", "Name", "Description", "Due Date", "Completed", "Past Due", "Priority", "Project",
printTaskTable(repo, tasks)
}
}

func printProjectTable(repo *repository.Repository, projects []*models.Project) {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"ID", "Name", "Description", "Type", "Child Of"})
table.SetRowLine(true)

for _, project := range projects {
typeField := "Parent"
parentChildField := "None"
if project.ParentProjectId != nil {
typeField = "Child"
parentProject, _ := repo.GetProjectByID(*project.ParentProjectId)
if parentProject != nil {
parentChildField = parentProject.Name
}
} else {
subprojects, _ := repo.GetSubprojects(project.ID)
if len(subprojects) > 0 {
typeField = "Parent"
}
}

table.Append([]string{
strconv.Itoa(project.ID),
utils.WrapText(project.Name, 30),
utils.WrapText(project.Description, 50),
typeField,
parentChildField,
})
table.SetRowLine(true)
}

for _, task := range tasks {
project, _ := repo.GetProjectByID(task.ProjectID)
projectName := ""
if project != nil {
projectName = project.Name
fmt.Println("Projects:")
table.Render()
}

func printTaskTable(repo *repository.Repository, tasks []*models.Task) {
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{
"ID", "Name", "Description", "Due Date", "Completed", "Past Due", "Priority", "Project", "Type", "Parent/Child Of",
})
table.SetRowLine(true)

for _, task := range tasks {
typeField := "Parent"
parentChildField := "None"
if task.ParentTaskId != nil {
typeField = "Child"
parentTask, _ := repo.GetTaskByID(*task.ParentTaskId)
if parentTask != nil {
parentChildField = parentTask.Name
}
} else {
subtasks, _ := repo.GetSubtasks(task.ID)
if len(subtasks) > 0 {
typeField = "Parent"
}
}

project, _ := repo.GetProjectByID(task.ProjectID)
projectName := ""
if project != nil {
projectName = project.Name
}

table.Append([]string{
strconv.Itoa(task.ID),
utils.WrapText(task.Name, 20),
utils.WrapText(task.Description, 30),
utils.FormatDate(task.DueDate),
fmt.Sprintf("%v", task.TaskCompleted),
utils.ColoredPastDue(task.DueDate, task.TaskCompleted),
utils.GetPriorityString(task.Priority),
utils.WrapText(projectName, 20),
typeField,
parentChildField,
})
}

table.Append([]string{
strconv.Itoa(task.ID),
utils.WrapText(task.Name, 20),
utils.WrapText(task.Description, 30),
utils.FormatDate(task.DueDate),
fmt.Sprintf("%v", task.TaskCompleted),
utils.ColoredPastDue(task.DueDate, task.TaskCompleted),
utils.GetPriorityString(task.Priority),
utils.WrapText(projectName, 20),
})
table.Render()
}

func printProjectTree(repo *repository.Repository, projects []*models.Project, parentID *int, level int) {
indent := strings.Repeat("│ ", level)
for i, project := range projects {
if (parentID == nil && project.ParentProjectId == nil) || (parentID != nil && project.ParentProjectId != nil && *project.ParentProjectId == *parentID) {
prefix := "├──"
if i == len(projects)-1 {
prefix = "└──"
}
fmt.Printf("%s%s %s (ID: %d)\n", indent, prefix, project.Name, project.ID)
printProjectTree(repo, projects, &project.ID, level+1)
}
}
}

table.Render()
func printTaskTree(repo *repository.Repository, tasks []*models.Task, parentID *int, level int) {
indent := strings.Repeat("│ ", level)
for i, task := range tasks {
if (parentID == nil && task.ParentTaskId == nil) || (parentID != nil && task.ParentTaskId != nil && *task.ParentTaskId == *parentID) {
prefix := "├──"
if i == len(tasks)-1 {
prefix = "└──"
}
fmt.Printf("%s%s %s (ID: %d)\n", indent, prefix, task.Name, task.ID)
fmt.Printf("%s Description: %s\n", indent, task.Description)
fmt.Printf("%s Due Date: %s, Completed: %v, Priority: %s\n",
indent, utils.FormatDate(task.DueDate), task.TaskCompleted, utils.GetPriorityString(task.Priority))
printTaskTree(repo, tasks, &task.ID, level+1)
}
}
}
75 changes: 55 additions & 20 deletions cmd/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ func init() {

newCmd.Flags().StringP("name", "n", "", "Name of the project or task")
newCmd.Flags().StringP("description", "d", "", "Description of the project or task")
newCmd.Flags().StringP("project", "p", "", "Project name or ID for the task")
newCmd.Flags().StringP("project", "p", "", "Parent project name or ID for subprojects or tasks")
newCmd.Flags().StringP("task", "t", "", "Parent task ID for subtasks")
newCmd.Flags().StringP("due", "D", "", "Due date for the task (format: YYYY-MM-DD HH:MM)")
newCmd.Flags().
IntP("priority", "r", 4, "Priority of the task (1: High, 2: Medium, 3: Low, 4: None)")
Expand All @@ -53,15 +54,32 @@ func init() {
func createProject(cmd *cobra.Command, repo *repository.Repository) {
name, _ := cmd.Flags().GetString("name")
description, _ := cmd.Flags().GetString("description")
parentProjectIdentifier, _ := cmd.Flags().GetString("project")

if name == "" {
fmt.Println("Project name is required.")
return
}

var parentProjectID *int
if parentProjectIdentifier != "" {
if utils.IsNumeric(parentProjectIdentifier) {
id, _ := strconv.Atoi(parentProjectIdentifier)
parentProjectID = &id
} else {
parentProject, err := repo.GetProjectByName(parentProjectIdentifier)
if err != nil || parentProject == nil {
fmt.Printf("Parent project '%s' not found.\n", parentProjectIdentifier)
return
}
parentProjectID = &parentProject.ID
}
}

project := &models.Project{
Name: name,
Description: description,
Name: name,
Description: description,
ParentProjectId: parentProjectID,
}

err := repo.CreateProject(project)
Expand All @@ -77,27 +95,43 @@ func createTask(cmd *cobra.Command, repo *repository.Repository) {
name, _ := cmd.Flags().GetString("name")
description, _ := cmd.Flags().GetString("description")
projectIdentifier, _ := cmd.Flags().GetString("project")
parentTaskIdentifier, _ := cmd.Flags().GetString("task")
dueDateStr, _ := cmd.Flags().GetString("due")
priority, _ := cmd.Flags().GetInt("priority")

if name == "" || projectIdentifier == "" {
fmt.Println("Task name and project identifier are required.")
if name == "" {
fmt.Println("Task name is required.")
return
}

var project *models.Project
var err error
var projectID int
var parentTaskID *int

if utils.IsNumeric(projectIdentifier) {
projectID, _ := strconv.Atoi(projectIdentifier)
project, err = repo.GetProjectByID(projectID)
if projectIdentifier != "" {
if utils.IsNumeric(projectIdentifier) {
id, _ := strconv.Atoi(projectIdentifier)
projectID = id
} else {
project, err := repo.GetProjectByName(projectIdentifier)
if err != nil || project == nil {
fmt.Printf("Project '%s' not found.\n", projectIdentifier)
return
}
projectID = project.ID
}
} else {
project, err = repo.GetProjectByName(projectIdentifier)
fmt.Println("Task must be associated with a project.")
return
}

if err != nil || project == nil {
fmt.Printf("Project '%s' not found.\n", projectIdentifier)
return
if parentTaskIdentifier != "" {
if utils.IsNumeric(parentTaskIdentifier) {
id, _ := strconv.Atoi(parentTaskIdentifier)
parentTaskID = &id
} else {
fmt.Println("Parent task must be identified by a numeric ID.")
return
}
}

var dueDate *time.Time
Expand All @@ -111,14 +145,15 @@ func createTask(cmd *cobra.Command, repo *repository.Repository) {
}

task := &models.Task{
Name: name,
Description: description,
ProjectID: project.ID,
DueDate: dueDate,
Priority: priority,
Name: name,
Description: description,
ProjectID: projectID,
DueDate: dueDate,
Priority: priority,
ParentTaskId: parentTaskID,
}

err = repo.CreateTask(task)
err := repo.CreateTask(task)
if err != nil {
fmt.Printf("Error creating task: %v\n", err)
return
Expand Down
Loading

0 comments on commit d1714e6

Please sign in to comment.