diff --git a/_site/content/posts/modules/trello.md b/_site/content/posts/modules/trello.md new file mode 100644 index 000000000..c8649b69c --- /dev/null +++ b/_site/content/posts/modules/trello.md @@ -0,0 +1,87 @@ +--- +title: "Trello" +date: 2018-05-10T10:44:35-07:00 +draft: false +--- + +Displays all Trello cards on specified lists. + +trello screenshot + +## Source Code + +```bash +wtf/trello/ +``` + +## Required ENV Variables + +Key: `WTF_TRELLO_APP_KEY`
+Value: Your Trello App Key.
+Key: `WTF_TRELLO_ACCESS_TOKEN`
+Value: Your Trello Access Token.
+ +_You can get your API key at: trello.com/app-key._ + +## Keyboard Commands + +None. + +## Configuration + +### Single Trello List + +```yaml +trello: + board: Main + enabled: true + list: "Todo" + position: + height: 1 + left: 2 + top: 0 + width: 1 + refreshInterval: 3600 + username: myname +``` + +### Multiple Trello Lists + +If you want to monitor multiple Trello lists, use the following +configuration (note the difference in `list`): + +```yaml +trello: + board: Main + enabled: true + list: ["Todo", "Done"] + position: + height: 1 + left: 2 + top: 0 + width: 1 + refreshInterval: 3600 + username: myname +``` + +### Attributes + +`board`
+The name of the Trello board.
+ +`enabled`
+Determines whether or not this module is executed and if its data displayed onscreen.
+Values: `true`, `false`. + +`list`
+The Trello lists to fetch cards from.
+ +`refreshInterval`
+How often, in seconds, this module will update its data.
+Values: A positive integer, `0..n`. + +`username`
+Your Trello username.
+ +`position`
+Where in the grid this module's widget will be displayed.
diff --git a/_site/static/imgs/modules/trello.png b/_site/static/imgs/modules/trello.png new file mode 100644 index 000000000..79fa69651 Binary files /dev/null and b/_site/static/imgs/modules/trello.png differ diff --git a/trello/card.go b/trello/card.go new file mode 100644 index 000000000..e1487c941 --- /dev/null +++ b/trello/card.go @@ -0,0 +1,8 @@ +package trello + +type TrelloCard struct { + ID string + Name string + List string + Description string +} diff --git a/trello/client.go b/trello/client.go new file mode 100644 index 000000000..dcccaf55e --- /dev/null +++ b/trello/client.go @@ -0,0 +1,98 @@ +package trello + +import ( + "fmt" + + "github.com/adlio/trello" + "github.com/senorprogrammer/wtf/wtf" +) + +func GetCards(client *trello.Client, lists map[string]string) (*SearchResult, error) { + boardID, err := getBoardID(client) + if err != nil { + return nil, err + } + + lists, err = getListIDs(client, boardID, lists) + if err != nil { + return nil, err + } + + searchResult := &SearchResult{Total: 0} + searchResult.TrelloCards = make(map[string][]TrelloCard) + + for listName, listID := range lists { + cards, err := getCardsOnList(client, listID) + if err != nil { + return nil, err + } + searchResult.Total = searchResult.Total + len(cards) + cardArray := make([]TrelloCard, 0) + for _, card := range cards { + trelloCard := TrelloCard{ + ID: card.ID, + List: listName, + Name: card.Name, + Description: card.Desc, + } + cardArray = append(cardArray, trelloCard) + } + searchResult.TrelloCards[listName] = cardArray + } + + return searchResult, nil +} + +func getBoardID(client *trello.Client) (string, error) { + member, err := client.GetMember(wtf.Config.UString("wtf.mods.trello.username"), trello.Defaults()) + if err != nil { + return "", err + } + + boards, err := member.GetBoards(trello.Defaults()) + if err != nil { + return "", err + } + + for _, board := range boards { + if board.Name == wtf.Config.UString("wtf.mods.trello.board") { + return board.ID, nil + } + } + + return "", fmt.Errorf("could not find board with name %s", wtf.Config.UString("wtf.mods.trello.board")) +} + +func getListIDs(client *trello.Client, boardID string, lists map[string]string) (map[string]string, error) { + board, err := client.GetBoard(boardID, trello.Defaults()) + if err != nil { + return nil, err + } + + boardLists, err := board.GetLists(trello.Defaults()) + if err != nil { + return nil, err + } + + for _, list := range boardLists { + if _, ok := lists[list.Name]; ok { + lists[list.Name] = list.ID + } + } + + return lists, nil +} + +func getCardsOnList(client *trello.Client, listID string) ([]*trello.Card, error) { + list, err := client.GetList(listID, trello.Defaults()) + if err != nil { + return nil, err + } + + cards, err := list.GetCards(trello.Defaults()) + if err != nil { + return nil, err + } + + return cards, nil +} diff --git a/trello/search_result.go b/trello/search_result.go new file mode 100644 index 000000000..44ca8dc77 --- /dev/null +++ b/trello/search_result.go @@ -0,0 +1,6 @@ +package trello + +type SearchResult struct { + Total int + TrelloCards map[string][]TrelloCard +} diff --git a/trello/widget.go b/trello/widget.go new file mode 100644 index 000000000..99c1b64a8 --- /dev/null +++ b/trello/widget.go @@ -0,0 +1,81 @@ +package trello + +import ( + "fmt" + "os" + + "github.com/adlio/trello" + "github.com/senorprogrammer/wtf/wtf" +) + +type Widget struct { + wtf.TextWidget +} + +func NewWidget() *Widget { + widget := Widget{ + TextWidget: wtf.NewTextWidget(" Trello ", "trello", false), + } + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +func (widget *Widget) Refresh() { + client := trello.NewClient(os.Getenv("WTF_TRELLO_APP_KEY"), os.Getenv("WTF_TRELLO_ACCESS_TOKEN")) + + // Get the cards + searchResult, err := GetCards(client, getLists()) + widget.UpdateRefreshedAt() + + if err != nil { + widget.View.SetWrap(true) + widget.View.SetTitle(fmt.Sprintf("%s", widget.Name)) + fmt.Fprintf(widget.View, "%v", err) + } else { + widget.View.SetWrap(false) + widget.View.SetTitle( + fmt.Sprintf( + "[white]%s: [green]%s ", + widget.Name, + wtf.Config.UString("wtf.mods.trello.board"), + ), + ) + widget.View.SetText(fmt.Sprintf("%s", widget.contentFrom(searchResult))) + } +} + +/* -------------------- Unexported Functions -------------------- */ +func (widget *Widget) contentFrom(searchResult *SearchResult) string { + str := "" + + for list, cardArray := range searchResult.TrelloCards { + str = fmt.Sprintf("%s [red]Cards in %s[white]\n", str, list) + for _, card := range cardArray { + str = fmt.Sprintf("%s [green]%s[white]\n", str, card.Name) + } + str = fmt.Sprintf("%s\n", str) + } + + return str +} + +func getLists() map[string]string { + list := make(map[string]string) + // see if project is set to a single string + configPath := "wtf.mods.trello.list" + singleList, err := wtf.Config.String(configPath) + if err == nil { + list[singleList] = "" + return list + } + // else, assume list + multiList := wtf.Config.UList(configPath) + for _, proj := range multiList { + if str, ok := proj.(string); ok { + list[str] = "" + } + } + return list +} diff --git a/wtf.go b/wtf.go index 3c89731ed..92450c0d6 100644 --- a/wtf.go +++ b/wtf.go @@ -38,6 +38,7 @@ import ( "github.com/senorprogrammer/wtf/system" "github.com/senorprogrammer/wtf/textfile" "github.com/senorprogrammer/wtf/todo" + "github.com/senorprogrammer/wtf/trello" "github.com/senorprogrammer/wtf/weatherservices/prettyweather" "github.com/senorprogrammer/wtf/weatherservices/weather" "github.com/senorprogrammer/wtf/wtf" @@ -213,6 +214,8 @@ func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) { Widgets = append(Widgets, textfile.NewWidget(app, pages)) case "todo": Widgets = append(Widgets, todo.NewWidget(app, pages)) + case "trello": + Widgets = append(Widgets, trello.NewWidget()) case "weather": Widgets = append(Widgets, weather.NewWidget(app, pages)) default: