mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
* Add Asana Module * Add Asana Module to the widget_maker * Asana Module - addressing linting concerns * Asana Module - ran go mod tidy
260 lines
5.2 KiB
Go
260 lines
5.2 KiB
Go
package asana
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/rivo/tview"
|
|
"github.com/wtfutil/wtf/utils"
|
|
"github.com/wtfutil/wtf/view"
|
|
)
|
|
|
|
type TaskType int
|
|
|
|
const (
|
|
TASK_TYPE TaskType = iota
|
|
TASK_SECTION
|
|
TASK_BREAK
|
|
)
|
|
|
|
type TaskItem struct {
|
|
name string
|
|
numSubtasks int32
|
|
dueOn string
|
|
id string
|
|
url string
|
|
taskType TaskType
|
|
completed bool
|
|
assignee string
|
|
}
|
|
|
|
type Widget struct {
|
|
view.ScrollableWidget
|
|
|
|
tasks []*TaskItem
|
|
|
|
mu sync.Mutex
|
|
err error
|
|
settings *Settings
|
|
tviewApp *tview.Application
|
|
}
|
|
|
|
func NewWidget(tviewApp *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
|
|
widget := &Widget{
|
|
ScrollableWidget: view.NewScrollableWidget(tviewApp, pages, settings.Common),
|
|
|
|
tviewApp: tviewApp,
|
|
settings: settings,
|
|
}
|
|
|
|
widget.SetRenderFunction(widget.Render)
|
|
widget.initializeKeyboardControls()
|
|
|
|
return widget
|
|
}
|
|
|
|
/* -------------------- Exported Functions -------------------- */
|
|
|
|
func (widget *Widget) Refresh() {
|
|
widget.tasks = nil
|
|
widget.err = nil
|
|
widget.SetItemCount(0)
|
|
|
|
widget.mu.Lock()
|
|
defer widget.mu.Unlock()
|
|
tasks, err := widget.Fetch(
|
|
widget.settings.workspaceId,
|
|
widget.settings.projectId,
|
|
widget.settings.mode,
|
|
widget.settings.sections,
|
|
widget.settings.allUsers,
|
|
)
|
|
if err != nil {
|
|
widget.err = err
|
|
} else {
|
|
widget.tasks = tasks
|
|
widget.SetItemCount(len(tasks))
|
|
}
|
|
|
|
widget.Render()
|
|
}
|
|
|
|
func (widget *Widget) Render() {
|
|
widget.Redraw(widget.content)
|
|
}
|
|
|
|
func (widget *Widget) Fetch(workspaceId, projectId, mode string, sections []string, allUsers bool) ([]*TaskItem, error) {
|
|
|
|
availableModes := map[string]interface{}{
|
|
"project": nil,
|
|
"project_sections": nil,
|
|
"workspace": nil,
|
|
}
|
|
|
|
if _, ok := availableModes[mode]; !ok {
|
|
return nil, fmt.Errorf("missing mode, or mode is invalid - please set to project, project_sections or workspace")
|
|
}
|
|
|
|
if widget.settings.apiKey != "" {
|
|
widget.settings.token = widget.settings.apiKey
|
|
} else {
|
|
widget.settings.token = os.Getenv("WTF_ASANA_TOKEN")
|
|
}
|
|
|
|
if widget.settings.token == "" {
|
|
return nil, fmt.Errorf("missing environment variable token or apikey config")
|
|
}
|
|
|
|
subMode := mode
|
|
if allUsers && mode != "workspace" {
|
|
subMode += "_all"
|
|
}
|
|
|
|
if projectId == "" && strings.HasPrefix(subMode, "project") {
|
|
return nil, fmt.Errorf("missing project id")
|
|
}
|
|
|
|
if workspaceId == "" && subMode == "workspace" {
|
|
return nil, fmt.Errorf("missing workspace id")
|
|
}
|
|
|
|
var tasks []*TaskItem
|
|
var err error
|
|
|
|
switch {
|
|
case strings.HasPrefix(subMode, "project_sections"):
|
|
tasks, err = fetchTasksFromProjectSections(widget.settings.token, projectId, sections, subMode)
|
|
case strings.HasPrefix(subMode, "project"):
|
|
tasks, err = fetchTasksFromProject(widget.settings.token, projectId, subMode)
|
|
case subMode == "workspace":
|
|
tasks, err = fetchTasksFromWorkspace(widget.settings.token, workspaceId, subMode)
|
|
default:
|
|
err = fmt.Errorf("no mode found")
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tasks, nil
|
|
|
|
}
|
|
|
|
/* -------------------- Unexported Functions -------------------- */
|
|
|
|
func (widget *Widget) content() (string, string, bool) {
|
|
|
|
title := widget.CommonSettings().Title
|
|
if widget.err != nil {
|
|
return title, widget.err.Error(), true
|
|
}
|
|
|
|
data := widget.tasks
|
|
if len(data) == 0 {
|
|
return title, "No data", false
|
|
}
|
|
|
|
var str string
|
|
|
|
for idx, taskItem := range data {
|
|
switch {
|
|
case taskItem.taskType == TASK_TYPE:
|
|
if widget.settings.hideComplete && taskItem.completed {
|
|
continue
|
|
}
|
|
|
|
rowColor := widget.RowColor(idx)
|
|
|
|
completed := "[ []"
|
|
if taskItem.completed {
|
|
completed = "[x[]"
|
|
}
|
|
|
|
row := ""
|
|
|
|
if widget.settings.allUsers && taskItem.assignee != "" {
|
|
row = fmt.Sprintf(
|
|
"[%s] %s %s: %s",
|
|
rowColor,
|
|
completed,
|
|
taskItem.assignee,
|
|
taskItem.name,
|
|
)
|
|
} else {
|
|
row = fmt.Sprintf(
|
|
"[%s] %s %s",
|
|
rowColor,
|
|
completed,
|
|
taskItem.name,
|
|
)
|
|
}
|
|
|
|
if taskItem.numSubtasks > 0 {
|
|
row += fmt.Sprintf(" (%d)", taskItem.numSubtasks)
|
|
}
|
|
|
|
if taskItem.dueOn != "" {
|
|
row += fmt.Sprintf(" due: %s", taskItem.dueOn)
|
|
}
|
|
|
|
row += " [white]"
|
|
|
|
str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
|
|
|
|
case taskItem.taskType == TASK_SECTION:
|
|
if idx > 1 {
|
|
row := "[white] "
|
|
|
|
str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
|
|
}
|
|
row := fmt.Sprintf(
|
|
"[white] %s [white]",
|
|
taskItem.name,
|
|
)
|
|
|
|
str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
|
|
|
|
row = "[white] "
|
|
|
|
str += utils.HighlightableHelper(widget.View, row, idx, len(taskItem.name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return title, str, false
|
|
|
|
}
|
|
|
|
func (widget *Widget) openTask() {
|
|
sel := widget.GetSelected()
|
|
|
|
if sel >= 0 && widget.tasks != nil && sel < len(widget.tasks) {
|
|
task := widget.tasks[sel]
|
|
if task.taskType == TASK_TYPE && task.url != "" {
|
|
utils.OpenFile(task.url)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (widget *Widget) toggleTaskCompletion() {
|
|
sel := widget.GetSelected()
|
|
|
|
if sel >= 0 && widget.tasks != nil && sel < len(widget.tasks) {
|
|
task := widget.tasks[sel]
|
|
if task.taskType == TASK_TYPE {
|
|
widget.mu.Lock()
|
|
|
|
err := toggleTaskCompletionById(widget.settings.token, task.id)
|
|
if err != nil {
|
|
widget.err = err
|
|
}
|
|
|
|
widget.mu.Unlock()
|
|
widget.Refresh()
|
|
}
|
|
}
|
|
}
|