github.com/wtfutil/wtf@v0.43.0/modules/asana/widget.go (about)

     1  package asana
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/rivo/tview"
    10  	"github.com/wtfutil/wtf/utils"
    11  	"github.com/wtfutil/wtf/view"
    12  )
    13  
    14  type TaskType int
    15  
    16  const (
    17  	TASK_TYPE TaskType = iota
    18  	TASK_SECTION
    19  	TASK_BREAK
    20  )
    21  
    22  type TaskItem struct {
    23  	name        string
    24  	numSubtasks int32
    25  	dueOn       string
    26  	id          string
    27  	url         string
    28  	taskType    TaskType
    29  	completed   bool
    30  	assignee    string
    31  }
    32  
    33  type Widget struct {
    34  	view.ScrollableWidget
    35  
    36  	tasks []*TaskItem
    37  
    38  	mu       sync.Mutex
    39  	err      error
    40  	settings *Settings
    41  	tviewApp *tview.Application
    42  }
    43  
    44  func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget {
    45  	widget := &Widget{
    46  		ScrollableWidget: view.NewScrollableWidget(tviewApp, redrawChan, pages, settings.Common),
    47  
    48  		tviewApp: tviewApp,
    49  		settings: settings,
    50  	}
    51  
    52  	widget.SetRenderFunction(widget.Render)
    53  	widget.initializeKeyboardControls()
    54  
    55  	return widget
    56  }
    57  
    58  /* -------------------- Exported Functions -------------------- */
    59  
    60  func (widget *Widget) Refresh() {
    61  	widget.tasks = nil
    62  	widget.err = nil
    63  	widget.SetItemCount(0)
    64  
    65  	widget.mu.Lock()
    66  	defer widget.mu.Unlock()
    67  	tasks, err := widget.Fetch(
    68  		widget.settings.workspaceId,
    69  		widget.settings.projectId,
    70  		widget.settings.mode,
    71  		widget.settings.sections,
    72  		widget.settings.allUsers,
    73  	)
    74  	if err != nil {
    75  		widget.err = err
    76  	} else {
    77  		widget.tasks = tasks
    78  		widget.SetItemCount(len(tasks))
    79  	}
    80  
    81  	widget.Render()
    82  }
    83  
    84  func (widget *Widget) Render() {
    85  	widget.Redraw(widget.content)
    86  }
    87  
    88  func (widget *Widget) Fetch(workspaceId, projectId, mode string, sections []string, allUsers bool) ([]*TaskItem, error) {
    89  
    90  	availableModes := map[string]interface{}{
    91  		"project":          nil,
    92  		"project_sections": nil,
    93  		"workspace":        nil,
    94  	}
    95  
    96  	if _, ok := availableModes[mode]; !ok {
    97  		return nil, fmt.Errorf("missing mode, or mode is invalid - please set to project, project_sections or workspace")
    98  	}
    99  
   100  	if widget.settings.apiKey != "" {
   101  		widget.settings.token = widget.settings.apiKey
   102  	} else {
   103  		widget.settings.token = os.Getenv("WTF_ASANA_TOKEN")
   104  	}
   105  
   106  	if widget.settings.token == "" {
   107  		return nil, fmt.Errorf("missing environment variable token or apikey config")
   108  	}
   109  
   110  	subMode := mode
   111  	if allUsers && mode != "workspace" {
   112  		subMode += "_all"
   113  	}
   114  
   115  	if projectId == "" && strings.HasPrefix(subMode, "project") {
   116  		return nil, fmt.Errorf("missing project id")
   117  	}
   118  
   119  	if workspaceId == "" && subMode == "workspace" {
   120  		return nil, fmt.Errorf("missing workspace id")
   121  	}
   122  
   123  	var tasks []*TaskItem
   124  	var err error
   125  
   126  	switch {
   127  	case strings.HasPrefix(subMode, "project_sections"):
   128  		tasks, err = fetchTasksFromProjectSections(widget.settings.token, projectId, sections, subMode)
   129  	case strings.HasPrefix(subMode, "project"):
   130  		tasks, err = fetchTasksFromProject(widget.settings.token, projectId, subMode)
   131  	case subMode == "workspace":
   132  		tasks, err = fetchTasksFromWorkspace(widget.settings.token, workspaceId, subMode)
   133  	default:
   134  		err = fmt.Errorf("no mode found")
   135  	}
   136  
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	return tasks, nil
   142  
   143  }
   144  
   145  /* -------------------- Unexported Functions -------------------- */
   146  
   147  func (widget *Widget) content() (string, string, bool) {
   148  
   149  	title := widget.CommonSettings().Title
   150  	if widget.err != nil {
   151  		return title, widget.err.Error(), true
   152  	}
   153  
   154  	data := widget.tasks
   155  	if len(data) == 0 {
   156  		return title, "No data", false
   157  	}
   158  
   159  	var str string
   160  
   161  	for idx, taskItem := range data {
   162  		switch {
   163  		case taskItem.taskType == TASK_TYPE:
   164  			if widget.settings.hideComplete && taskItem.completed {
   165  				continue
   166  			}
   167  
   168  			rowColor := widget.RowColor(idx)
   169  
   170  			completed := "[ []"
   171  			if taskItem.completed {
   172  				completed = "[x[]"
   173  			}
   174  
   175  			row := ""
   176  
   177  			if widget.settings.allUsers && taskItem.assignee != "" {
   178  				row = fmt.Sprintf(
   179  					"[%s]  %s %s: %s",
   180  					rowColor,
   181  					completed,
   182  					taskItem.assignee,
   183  					taskItem.name,
   184  				)
   185  			} else {
   186  				row = fmt.Sprintf(
   187  					"[%s]  %s %s",
   188  					rowColor,
   189  					completed,
   190  					taskItem.name,
   191  				)
   192  			}
   193  
   194  			if taskItem.numSubtasks > 0 {
   195  				row += fmt.Sprintf(" (%d)", taskItem.numSubtasks)
   196  			}
   197  
   198  			if taskItem.dueOn != "" {
   199  				row += fmt.Sprintf(" due: %s", taskItem.dueOn)
   200  			}
   201  
   202  			row += " [white]"
   203  
   204  			str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
   205  
   206  		case taskItem.taskType == TASK_SECTION:
   207  			if idx > 1 {
   208  				row := "[white] "
   209  
   210  				str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
   211  			}
   212  			row := fmt.Sprintf(
   213  				"[white] %s [white]",
   214  				taskItem.name,
   215  			)
   216  
   217  			str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
   218  
   219  			row = "[white] "
   220  
   221  			str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
   222  
   223  		}
   224  
   225  	}
   226  
   227  	return title, str, false
   228  
   229  }
   230  
   231  func (widget *Widget) openTask() {
   232  	sel := widget.GetSelected()
   233  
   234  	if sel >= 0 && widget.tasks != nil && sel < len(widget.tasks) {
   235  		task := widget.tasks[sel]
   236  		if task.taskType == TASK_TYPE && task.url != "" {
   237  			utils.OpenFile(task.url)
   238  		}
   239  	}
   240  }
   241  
   242  func (widget *Widget) toggleTaskCompletion() {
   243  	sel := widget.GetSelected()
   244  
   245  	if sel >= 0 && widget.tasks != nil && sel < len(widget.tasks) {
   246  		task := widget.tasks[sel]
   247  		if task.taskType == TASK_TYPE {
   248  			widget.mu.Lock()
   249  
   250  			err := toggleTaskCompletionById(widget.settings.token, task.id)
   251  			if err != nil {
   252  				widget.err = err
   253  			}
   254  
   255  			widget.mu.Unlock()
   256  			widget.Refresh()
   257  		}
   258  	}
   259  }