|
@@ -0,0 +1,590 @@
|
|
|
|
|
+package cmd
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "context"
|
|
|
|
|
+ "encoding/json"
|
|
|
|
|
+ "fmt"
|
|
|
|
|
+ "os"
|
|
|
|
|
+
|
|
|
|
|
+ "gogs.dmsc.dev/arp/arp_cli/client"
|
|
|
|
|
+ "gogs.dmsc.dev/arp/arp_cli/config"
|
|
|
|
|
+
|
|
|
|
|
+ "github.com/AlecAivazis/survey/v2"
|
|
|
|
|
+ "github.com/olekukonko/tablewriter"
|
|
|
|
|
+ "github.com/urfave/cli/v3"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// TaskCommand returns the task command
|
|
|
|
|
+func TaskCommand() *cli.Command {
|
|
|
|
|
+ return &cli.Command{
|
|
|
|
|
+ Name: "task",
|
|
|
|
|
+ Usage: "Manage tasks",
|
|
|
|
|
+ Description: `Manage ARP tasks. Tasks are work items that can be assigned to users.
|
|
|
|
|
+
|
|
|
|
|
+Tasks have statuses, priorities, and due dates. Use this command to
|
|
|
|
|
+create, list, update, and delete tasks. You can also watch for real-time task updates.`,
|
|
|
|
|
+ Commands: []*cli.Command{
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "list",
|
|
|
|
|
+ Aliases: []string{"ls"},
|
|
|
|
|
+ Usage: "List all tasks",
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.BoolFlag{
|
|
|
|
|
+ Name: "json",
|
|
|
|
|
+ Aliases: []string{"j"},
|
|
|
|
|
+ Usage: "Output as JSON",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ Action: taskList,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "get",
|
|
|
|
|
+ Usage: "Get a task by ID",
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "id",
|
|
|
|
|
+ Aliases: []string{"i"},
|
|
|
|
|
+ Usage: "Task ID",
|
|
|
|
|
+ Required: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.BoolFlag{
|
|
|
|
|
+ Name: "json",
|
|
|
|
|
+ Aliases: []string{"j"},
|
|
|
|
|
+ Usage: "Output as JSON",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ Action: taskGet,
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "create",
|
|
|
|
|
+ Usage: "Create a new task",
|
|
|
|
|
+ Action: taskCreate,
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "title",
|
|
|
|
|
+ Aliases: []string{"t"},
|
|
|
|
|
+ Usage: "Task title",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "content",
|
|
|
|
|
+ Aliases: []string{"c"},
|
|
|
|
|
+ Usage: "Task content",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "created-by",
|
|
|
|
|
+ Aliases: []string{"b"},
|
|
|
|
|
+ Usage: "Creator user ID",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "assignee",
|
|
|
|
|
+ Aliases: []string{"a"},
|
|
|
|
|
+ Usage: "Assignee user ID",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "status",
|
|
|
|
|
+ Aliases: []string{"s"},
|
|
|
|
|
+ Usage: "Status ID",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "due-date",
|
|
|
|
|
+ Aliases: []string{"d"},
|
|
|
|
|
+ Usage: "Due date",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "priority",
|
|
|
|
|
+ Aliases: []string{"p"},
|
|
|
|
|
+ Usage: "Priority (low, medium, high)",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "update",
|
|
|
|
|
+ Usage: "Update a task",
|
|
|
|
|
+ Action: taskUpdate,
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "id",
|
|
|
|
|
+ Aliases: []string{"i"},
|
|
|
|
|
+ Usage: "Task ID",
|
|
|
|
|
+ Required: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "title",
|
|
|
|
|
+ Aliases: []string{"t"},
|
|
|
|
|
+ Usage: "Task title",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "content",
|
|
|
|
|
+ Aliases: []string{"c"},
|
|
|
|
|
+ Usage: "Task content",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "assignee",
|
|
|
|
|
+ Aliases: []string{"a"},
|
|
|
|
|
+ Usage: "Assignee user ID",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "status",
|
|
|
|
|
+ Aliases: []string{"s"},
|
|
|
|
|
+ Usage: "Status ID",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "due-date",
|
|
|
|
|
+ Aliases: []string{"d"},
|
|
|
|
|
+ Usage: "Due date",
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "priority",
|
|
|
|
|
+ Aliases: []string{"p"},
|
|
|
|
|
+ Usage: "Priority",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "delete",
|
|
|
|
|
+ Usage: "Delete a task",
|
|
|
|
|
+ Action: taskDelete,
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "id",
|
|
|
|
|
+ Aliases: []string{"i"},
|
|
|
|
|
+ Usage: "Task ID",
|
|
|
|
|
+ Required: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ &cli.BoolFlag{
|
|
|
|
|
+ Name: "yes",
|
|
|
|
|
+ Aliases: []string{"y"},
|
|
|
|
|
+ Usage: "Skip confirmation",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ Name: "watch",
|
|
|
|
|
+ Usage: "Watch for real-time task updates",
|
|
|
|
|
+ Action: taskWatch,
|
|
|
|
|
+ Flags: []cli.Flag{
|
|
|
|
|
+ &cli.StringFlag{
|
|
|
|
|
+ Name: "event",
|
|
|
|
|
+ Aliases: []string{"e"},
|
|
|
|
|
+ Usage: "Event type (created, updated, deleted, all)",
|
|
|
|
|
+ Value: "all",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type Task struct {
|
|
|
|
|
+ ID string `json:"id"`
|
|
|
|
|
+ Title string `json:"title"`
|
|
|
|
|
+ Content string `json:"content"`
|
|
|
|
|
+ CreatedByID string `json:"createdById"`
|
|
|
|
|
+ CreatedBy *User `json:"createdBy"`
|
|
|
|
|
+ UpdatedByID string `json:"updatedById"`
|
|
|
|
|
+ UpdatedBy *User `json:"updatedBy"`
|
|
|
|
|
+ AssigneeID *string `json:"assigneeId"`
|
|
|
|
|
+ Assignee *User `json:"assignee"`
|
|
|
|
|
+ StatusID *string `json:"statusId"`
|
|
|
|
|
+ Status *TaskStatus `json:"status"`
|
|
|
|
|
+ DueDate *string `json:"dueDate"`
|
|
|
|
|
+ Priority string `json:"priority"`
|
|
|
|
|
+ CreatedAt string `json:"createdAt"`
|
|
|
|
|
+ UpdatedAt string `json:"updatedAt"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type TaskStatus struct {
|
|
|
|
|
+ ID string `json:"id"`
|
|
|
|
|
+ Code string `json:"code"`
|
|
|
|
|
+ Label string `json:"label"`
|
|
|
|
|
+ CreatedAt string `json:"createdAt"`
|
|
|
|
|
+ UpdatedAt string `json:"updatedAt"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskList(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c := client.New(cfg.ServerURL)
|
|
|
|
|
+ c.SetToken(cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ query := "query Tasks { tasks { id title priority createdBy { id email } assignee { id email } status { id code label } dueDate createdAt updatedAt } }"
|
|
|
|
|
+
|
|
|
|
|
+ resp, err := c.Query(query, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result struct {
|
|
|
|
|
+ Tasks []Task `json:"tasks"`
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if cmd.Bool("json") {
|
|
|
|
|
+ enc := json.NewEncoder(os.Stdout)
|
|
|
|
|
+ enc.SetIndent("", " ")
|
|
|
|
|
+ return enc.Encode(result.Tasks)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(result.Tasks) == 0 {
|
|
|
|
|
+ fmt.Println("No tasks found.")
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ table := tablewriter.NewWriter(os.Stdout)
|
|
|
|
|
+ table.Header([]string{"ID", "Title", "Priority", "Status", "Assignee", "Due Date"})
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ for _, t := range result.Tasks {
|
|
|
|
|
+ status := ""
|
|
|
|
|
+ if t.Status != nil {
|
|
|
|
|
+ status = t.Status.Label
|
|
|
|
|
+ }
|
|
|
|
|
+ assignee := ""
|
|
|
|
|
+ if t.Assignee != nil {
|
|
|
|
|
+ assignee = t.Assignee.Email
|
|
|
|
|
+ }
|
|
|
|
|
+ dueDate := ""
|
|
|
|
|
+ if t.DueDate != nil {
|
|
|
|
|
+ dueDate = *t.DueDate
|
|
|
|
|
+ }
|
|
|
|
|
+ table.Append([]string{t.ID, t.Title, t.Priority, status, assignee, dueDate})
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ table.Render()
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskGet(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c := client.New(cfg.ServerURL)
|
|
|
|
|
+ c.SetToken(cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ id := cmd.String("id")
|
|
|
|
|
+ query := "query Task($id: ID!) { task(id: $id) { id title content createdBy { id email } assignee { id email } status { id code label } dueDate priority createdAt updatedAt } }"
|
|
|
|
|
+
|
|
|
|
|
+ resp, err := c.Query(query, map[string]interface{}{"id": id})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result struct {
|
|
|
|
|
+ Task *Task `json:"task"`
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if result.Task == nil {
|
|
|
|
|
+ return fmt.Errorf("task not found")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if cmd.Bool("json") {
|
|
|
|
|
+ enc := json.NewEncoder(os.Stdout)
|
|
|
|
|
+ enc.SetIndent("", " ")
|
|
|
|
|
+ return enc.Encode(result.Task)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ t := result.Task
|
|
|
|
|
+ fmt.Printf("ID: %s\n", t.ID)
|
|
|
|
|
+ fmt.Printf("Title: %s\n", t.Title)
|
|
|
|
|
+ fmt.Printf("Content: %s\n", t.Content)
|
|
|
|
|
+ if t.CreatedBy != nil {
|
|
|
|
|
+ fmt.Printf("Created By: %s\n", t.CreatedBy.Email)
|
|
|
|
|
+ }
|
|
|
|
|
+ if t.Assignee != nil {
|
|
|
|
|
+ fmt.Printf("Assignee: %s\n", t.Assignee.Email)
|
|
|
|
|
+ }
|
|
|
|
|
+ if t.Status != nil {
|
|
|
|
|
+ fmt.Printf("Status: %s (%s)\n", t.Status.Label, t.Status.Code)
|
|
|
|
|
+ }
|
|
|
|
|
+ if t.DueDate != nil {
|
|
|
|
|
+ fmt.Printf("Due Date: %s\n", *t.DueDate)
|
|
|
|
|
+ }
|
|
|
|
|
+ fmt.Printf("Priority: %s\n", t.Priority)
|
|
|
|
|
+ fmt.Printf("Created At: %s\n", t.CreatedAt)
|
|
|
|
|
+ fmt.Printf("Updated At: %s\n", t.UpdatedAt)
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskCreate(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ title := cmd.String("title")
|
|
|
|
|
+ content := cmd.String("content")
|
|
|
|
|
+ createdBy := cmd.String("created-by")
|
|
|
|
|
+ assignee := cmd.String("assignee")
|
|
|
|
|
+ status := cmd.String("status")
|
|
|
|
|
+ dueDate := cmd.String("due-date")
|
|
|
|
|
+ priority := cmd.String("priority")
|
|
|
|
|
+
|
|
|
|
|
+ if title == "" {
|
|
|
|
|
+ prompt := &survey.Input{Message: "Title:"}
|
|
|
|
|
+ if err := survey.AskOne(prompt, &title, survey.WithValidator(survey.Required)); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if content == "" {
|
|
|
|
|
+ prompt := &survey.Multiline{Message: "Content:"}
|
|
|
|
|
+ if err := survey.AskOne(prompt, &content, survey.WithValidator(survey.Required)); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if createdBy == "" {
|
|
|
|
|
+ prompt := &survey.Input{Message: "Creator user ID:"}
|
|
|
|
|
+ if err := survey.AskOne(prompt, &createdBy, survey.WithValidator(survey.Required)); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if priority == "" {
|
|
|
|
|
+ prompt := &survey.Select{
|
|
|
|
|
+ Message: "Priority:",
|
|
|
|
|
+ Options: []string{"low", "medium", "high"},
|
|
|
|
|
+ Default: "medium",
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := survey.AskOne(prompt, &priority); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c := client.New(cfg.ServerURL)
|
|
|
|
|
+ c.SetToken(cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ mutation := `mutation CreateTask($input: NewTask!) { createTask(input: $input) { id title priority createdBy { id email } assignee { id email } status { id code label } dueDate createdAt updatedAt } }`
|
|
|
|
|
+
|
|
|
|
|
+ input := map[string]interface{}{
|
|
|
|
|
+ "title": title,
|
|
|
|
|
+ "content": content,
|
|
|
|
|
+ "createdById": createdBy,
|
|
|
|
|
+ "priority": priority,
|
|
|
|
|
+ }
|
|
|
|
|
+ if assignee != "" {
|
|
|
|
|
+ input["assigneeId"] = assignee
|
|
|
|
|
+ }
|
|
|
|
|
+ if status != "" {
|
|
|
|
|
+ input["statusId"] = status
|
|
|
|
|
+ }
|
|
|
|
|
+ if dueDate != "" {
|
|
|
|
|
+ input["dueDate"] = dueDate
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ resp, err := c.Mutation(mutation, map[string]interface{}{"input": input})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result struct {
|
|
|
|
|
+ CreateTask *Task `json:"createTask"`
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if result.CreateTask == nil {
|
|
|
|
|
+ return fmt.Errorf("failed to create task")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Task created successfully!\n")
|
|
|
|
|
+ fmt.Printf("ID: %s\n", result.CreateTask.ID)
|
|
|
|
|
+ fmt.Printf("Title: %s\n", result.CreateTask.Title)
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskUpdate(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ id := cmd.String("id")
|
|
|
|
|
+ title := cmd.String("title")
|
|
|
|
|
+ content := cmd.String("content")
|
|
|
|
|
+ assignee := cmd.String("assignee")
|
|
|
|
|
+ status := cmd.String("status")
|
|
|
|
|
+ dueDate := cmd.String("due-date")
|
|
|
|
|
+ priority := cmd.String("priority")
|
|
|
|
|
+
|
|
|
|
|
+ if title == "" && content == "" && assignee == "" && status == "" && dueDate == "" && priority == "" {
|
|
|
|
|
+ fmt.Println("No updates provided. Use flags to specify what to update.")
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c := client.New(cfg.ServerURL)
|
|
|
|
|
+ c.SetToken(cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ input := make(map[string]interface{})
|
|
|
|
|
+ if title != "" {
|
|
|
|
|
+ input["title"] = title
|
|
|
|
|
+ }
|
|
|
|
|
+ if content != "" {
|
|
|
|
|
+ input["content"] = content
|
|
|
|
|
+ }
|
|
|
|
|
+ if assignee != "" {
|
|
|
|
|
+ input["assigneeId"] = assignee
|
|
|
|
|
+ }
|
|
|
|
|
+ if status != "" {
|
|
|
|
|
+ input["statusId"] = status
|
|
|
|
|
+ }
|
|
|
|
|
+ if dueDate != "" {
|
|
|
|
|
+ input["dueDate"] = dueDate
|
|
|
|
|
+ }
|
|
|
|
|
+ if priority != "" {
|
|
|
|
|
+ input["priority"] = priority
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ mutation := `mutation UpdateTask($id: ID!, $input: UpdateTaskInput!) { updateTask(id: $id, input: $input) { id title priority status { id code label } createdAt updatedAt } }`
|
|
|
|
|
+
|
|
|
|
|
+ resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result struct {
|
|
|
|
|
+ UpdateTask *Task `json:"updateTask"`
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if result.UpdateTask == nil {
|
|
|
|
|
+ return fmt.Errorf("task not found")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Task updated successfully!\n")
|
|
|
|
|
+ fmt.Printf("ID: %s\n", result.UpdateTask.ID)
|
|
|
|
|
+ fmt.Printf("Title: %s\n", result.UpdateTask.Title)
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskDelete(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ id := cmd.String("id")
|
|
|
|
|
+ skipConfirm := cmd.Bool("yes")
|
|
|
|
|
+
|
|
|
|
|
+ if !skipConfirm {
|
|
|
|
|
+ confirm := false
|
|
|
|
|
+ prompt := &survey.Confirm{
|
|
|
|
|
+ Message: fmt.Sprintf("Are you sure you want to delete task %s?", id),
|
|
|
|
|
+ Default: false,
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := survey.AskOne(prompt, &confirm); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !confirm {
|
|
|
|
|
+ fmt.Println("Deletion cancelled.")
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ c := client.New(cfg.ServerURL)
|
|
|
|
|
+ c.SetToken(cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ mutation := `mutation DeleteTask($id: ID!) { deleteTask(id: $id) }`
|
|
|
|
|
+
|
|
|
|
|
+ resp, err := c.Mutation(mutation, map[string]interface{}{"id": id})
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var result struct {
|
|
|
|
|
+ DeleteTask bool `json:"deleteTask"`
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if result.DeleteTask {
|
|
|
|
|
+ fmt.Printf("Task %s deleted successfully.\n", id)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fmt.Printf("Failed to delete task %s.\n", id)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func taskWatch(ctx context.Context, cmd *cli.Command) error {
|
|
|
|
|
+ cfg, err := config.Load()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+ if err := RequireAuth(cfg); err != nil {
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ eventType := cmd.String("event")
|
|
|
|
|
+
|
|
|
|
|
+ wsClient := client.NewWebSocketClient(cfg.ServerURL, cfg.Token)
|
|
|
|
|
+
|
|
|
|
|
+ if err := wsClient.Connect(); err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to connect: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ defer wsClient.Close()
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("Watching for task events (type: %s)...\n", eventType)
|
|
|
|
|
+ fmt.Println("Press Ctrl+C to stop.")
|
|
|
|
|
+
|
|
|
|
|
+ var subscription string
|
|
|
|
|
+ switch eventType {
|
|
|
|
|
+ case "created":
|
|
|
|
|
+ subscription = "subscription { taskCreated { id title priority status { id code label } createdAt } }"
|
|
|
|
|
+ case "updated":
|
|
|
|
|
+ subscription = "subscription { taskUpdated { id title priority status { id code label } updatedAt } }"
|
|
|
|
|
+ case "deleted":
|
|
|
|
|
+ subscription = "subscription { taskDeleted { id title } }"
|
|
|
|
|
+ default:
|
|
|
|
|
+ subscription = "subscription { taskCreated { id title priority status { id code label } createdAt } taskUpdated { id title priority status { id code label } updatedAt } taskDeleted { id title } }"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if err := wsClient.Subscribe("1", subscription, nil); err != nil {
|
|
|
|
|
+ return fmt.Errorf("failed to subscribe: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for {
|
|
|
|
|
+ select {
|
|
|
|
|
+ case msg := <-wsClient.Messages():
|
|
|
|
|
+ fmt.Printf("Event: %s\n", string(msg))
|
|
|
|
|
+ case err := <-wsClient.Errors():
|
|
|
|
|
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
|
|
|
+ case <-wsClient.Done():
|
|
|
|
|
+ return nil
|
|
|
|
|
+ case <-ctx.Done():
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|