mirror of
https://github.com/documize/community.git
synced 2025-08-10 16:05:34 +02:00
Trello board rendering
This commit is contained in:
parent
20e70f52d0
commit
d697e7926b
6 changed files with 346 additions and 104 deletions
|
@ -1,40 +0,0 @@
|
||||||
package section
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type code struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
sectionsMap["code"] = &code{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*code) Meta() TypeMeta {
|
|
||||||
section := TypeMeta{}
|
|
||||||
|
|
||||||
section.ID = "4f6f2b02-8397-483d-9bb9-eea1fef13304"
|
|
||||||
section.Title = "Code"
|
|
||||||
section.Description = "Code snippets supporting 50+ languages"
|
|
||||||
section.ContentType = "code"
|
|
||||||
section.IconFontLigature = "code"
|
|
||||||
section.Order = 9997
|
|
||||||
|
|
||||||
return section
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command stub.
|
|
||||||
func (*code) Command(w http.ResponseWriter, r *http.Request) {
|
|
||||||
writeEmpty(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render just sends back HMTL as-is.
|
|
||||||
func (*code) Render(config, data string) string {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh just sends back data as-is.
|
|
||||||
func (*code) Refresh(config, data string) string {
|
|
||||||
return data
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
config: {},
|
config: {},
|
||||||
boards: null,
|
boards: null,
|
||||||
lists: null,
|
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
let config = {};
|
let config = {};
|
||||||
|
@ -24,8 +23,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
appKey: "",
|
appKey: "",
|
||||||
token: "",
|
token: "",
|
||||||
board: null,
|
board: null,
|
||||||
list: null,
|
lists: []
|
||||||
cards: null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +45,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
let board = this.get('config.board');
|
let board = this.get('config.board');
|
||||||
this.set('waiting', true);
|
this.set('waiting', true);
|
||||||
|
|
||||||
if (board === null) {
|
if (is.null(board)) {
|
||||||
if (boards.length) {
|
if (boards.length) {
|
||||||
board = boards[0];
|
board = boards[0];
|
||||||
this.set('config.board', board);
|
this.set('config.board', board);
|
||||||
|
@ -56,7 +54,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
this.set('config.board', boards.findBy('id', board.id));
|
this.set('config.board', boards.findBy('id', board.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Trello.get(`boards/${board.id}/lists/open`,
|
Trello.get(`boards/${board.id}/lists/open?fields=id,name,url`,
|
||||||
function(lists) {
|
function(lists) {
|
||||||
let savedLists = self.get('config.lists');
|
let savedLists = self.get('config.lists');
|
||||||
if (savedLists === null) {
|
if (savedLists === null) {
|
||||||
|
@ -74,8 +72,6 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
|
|
||||||
self.set('config.lists', lists);
|
self.set('config.lists', lists);
|
||||||
self.set('waiting', false);
|
self.set('waiting', false);
|
||||||
|
|
||||||
// self.getListCards();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -155,25 +151,31 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
|
||||||
this.getBoardLists();
|
this.getBoardLists();
|
||||||
},
|
},
|
||||||
|
|
||||||
// onListChange(list) {
|
|
||||||
// this.set('config.list', list);
|
|
||||||
// this.getListCards();
|
|
||||||
// },
|
|
||||||
|
|
||||||
onCancel() {
|
onCancel() {
|
||||||
this.attrs.onCancel();
|
this.attrs.onCancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
onAction(title) {
|
onAction(title) {
|
||||||
|
this.set('waiting', false);
|
||||||
|
|
||||||
|
let self = this;
|
||||||
let page = this.get('page');
|
let page = this.get('page');
|
||||||
let meta = this.get('meta');
|
let meta = this.get('meta');
|
||||||
page.set('title', title);
|
page.set('title', title);
|
||||||
// meta.set('rawBody', JSON.stringify(this.get("items")));
|
|
||||||
meta.set('rawBody', '');
|
meta.set('rawBody', '');
|
||||||
meta.set('config', JSON.stringify(this.get('config')));
|
meta.set('config', JSON.stringify(this.get('config')));
|
||||||
meta.set('externalSource', true);
|
meta.set('externalSource', true);
|
||||||
|
|
||||||
this.attrs.onAction(page, meta);
|
this.get('sectionService').fetch(page, "cards", this.get('config'))
|
||||||
|
.then(function(response) {
|
||||||
|
console.log(response);
|
||||||
|
meta.set('rawBody', JSON.stringify(response));
|
||||||
|
self.set('waiting', false);
|
||||||
|
self.attrs.onAction(page, meta);
|
||||||
|
}, function(reason) { //jshint ignore: line
|
||||||
|
self.set('waiting', false);
|
||||||
|
self.attrs.onAction(page, meta);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -1,18 +1,18 @@
|
||||||
<style>
|
<style>
|
||||||
.board {
|
.trello-board {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: auto
|
overflow: auto
|
||||||
}
|
}
|
||||||
|
|
||||||
.board-title {
|
.trello-board-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.trello-list {
|
||||||
background-color: #e2e4e6;
|
background-color: #e2e4e6;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
@ -20,19 +20,19 @@
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-title {
|
.trello-list-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #4c4c4c;
|
color: #4c4c4c;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-checkbox {
|
.trello-list-checkbox {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{{#section/base-editor document=document folder=folder page=page busy=waiting tip="Trello, yellow, mellow" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}}
|
{{#section/base-editor document=document folder=folder page=page busy=waiting tip="Trello is the visual way to manage your projects and organize anything (https://trello.com)" isDirty=(action 'isDirty') onCancel=(action 'onCancel') onAction=(action 'onAction')}}
|
||||||
|
|
||||||
<div class="pull-left width-45">
|
<div class="pull-left width-45">
|
||||||
<div class="input-form">
|
<div class="input-form">
|
||||||
|
@ -73,18 +73,16 @@
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Lists</label>
|
<label>Lists</label>
|
||||||
<div class="tip">Select lists to include</div>
|
<div class="tip">Select lists to include</div>
|
||||||
<div class="board" style="background-color:{{config.board.prefs.backgroundColor}};">
|
<div class="trello-board" style="background-color:{{config.board.prefs.backgroundColor}};">
|
||||||
<div class="board-title">{{config.board.name}}</div>
|
<div class="trello-board-title">{{config.board.name}}</div>
|
||||||
{{#each config.lists as |list|}}
|
{{#each config.lists as |list|}}
|
||||||
<div class="list" {{action 'onListCheckbox' list.id}}>
|
<div class="trello-list" {{action 'onListCheckbox' list.id}}>
|
||||||
{{#if list.included}}
|
{{#if list.included}}
|
||||||
<i class="material-icons widget-checkbox checkbox-gray list-checkbox" >check_box</i>
|
<i class="material-icons widget-checkbox checkbox-gray trello-list-checkbox" >check_box</i>
|
||||||
{{else}}
|
{{else}}
|
||||||
<i class="material-icons widget-checkbox checkbox-gray list-checkbox">check_box_outline_blank</i>
|
<i class="material-icons widget-checkbox checkbox-gray trello-list-checkbox">check_box_outline_blank</i>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span class="list-title">{{list.name}}</span>
|
<span class="trello-list-title">{{list.name}}</span>
|
||||||
{{!--<input type="checkbox" id="trello-list-{{list.id}}" checked={{list.included}} />--}}
|
|
||||||
{{!--<label class="list-title" for="trello-list-{{list.id}}">{{list.name}}</label>--}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<div class="clearfix" />
|
<div class="clearfix" />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<style>
|
<style>
|
||||||
.board {
|
.trello-board {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -7,7 +7,13 @@
|
||||||
overflow: auto
|
overflow: auto
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.trello-board-title {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trello-list {
|
||||||
background-color: #e2e4e6;
|
background-color: #e2e4e6;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
@ -16,17 +22,18 @@
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: auto
|
overflow: auto;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-title {
|
.trello-list-title {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #4c4c4c;
|
color: #4c4c4c;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 0 10px 10px 0;
|
margin: 0 10px 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.trello-card {
|
||||||
color: #4c4c4c;
|
color: #4c4c4c;
|
||||||
border-bottom: 1px solid #CDD2D4;
|
border-bottom: 1px solid #CDD2D4;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
@ -39,6 +46,8 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
"github.com/documize/community/wordsmith/log"
|
"github.com/documize/community/wordsmith/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sectionName = "gemini"
|
|
||||||
|
|
||||||
// the HTML that is rendered by this section.
|
// the HTML that is rendered by this section.
|
||||||
const renderTemplate = `
|
const renderTemplate = `
|
||||||
<p class="margin-left-20">The Gemini workspace <a href="{{.Config.URL}}/workspace/{{.Config.WorkspaceID}}/items">{{.Config.WorkspaceName}}</a> contains {{.Config.ItemCount}} items.</p>
|
<p class="margin-left-20">The Gemini workspace <a href="{{.Config.URL}}/workspace/{{.Config.WorkspaceID}}/items">{{.Config.WorkspaceName}}</a> contains {{.Config.ItemCount}} items.</p>
|
||||||
|
@ -47,17 +45,16 @@ type gemini struct {
|
||||||
|
|
||||||
// Register ourselves.
|
// Register ourselves.
|
||||||
func init() {
|
func init() {
|
||||||
sectionsMap[sectionName] = &gemini{}
|
sectionsMap["gemini"] = &gemini{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meta describes this section type.
|
// Meta describes this section type.
|
||||||
func (*gemini) Meta() TypeMeta {
|
func (*gemini) Meta() TypeMeta {
|
||||||
section := TypeMeta{}
|
section := TypeMeta{}
|
||||||
|
|
||||||
section.ID = "23b133f9-4020-4616-9291-a98fb939735f"
|
section.ID = "23b133f9-4020-4616-9291-a98fb939735f"
|
||||||
section.Title = "Gemini"
|
section.Title = "Gemini"
|
||||||
section.Description = "Display work items and tickets from Gemini workspaces"
|
section.Description = "Display work items and tickets from Gemini workspaces"
|
||||||
section.ContentType = sectionName
|
section.ContentType = "gemini"
|
||||||
section.IconFontLigature = ""
|
section.IconFontLigature = ""
|
||||||
section.IconFilePath = "sections/gemini.png"
|
section.IconFilePath = "sections/gemini.png"
|
||||||
|
|
||||||
|
@ -93,7 +90,7 @@ func (*gemini) Command(w http.ResponseWriter, r *http.Request) {
|
||||||
method := query.Get("method")
|
method := query.Get("method")
|
||||||
|
|
||||||
if len(method) == 0 {
|
if len(method) == 0 {
|
||||||
writeMessage(w, sectionName, "missing method name")
|
writeMessage(w, "gemini", "missing method name")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +219,7 @@ func auth(w http.ResponseWriter, r *http.Request) {
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,24 +227,24 @@ func auth(w http.ResponseWriter, r *http.Request) {
|
||||||
err = json.Unmarshal(body, &config)
|
err = json.Unmarshal(body, &config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Clean()
|
config.Clean()
|
||||||
|
|
||||||
if len(config.URL) == 0 {
|
if len(config.URL) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing URL value")
|
writeMessage(w, "gemini", "Missing URL value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.Username) == 0 {
|
if len(config.Username) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing Username value")
|
writeMessage(w, "gemini", "Missing Username value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.APIKey) == 0 {
|
if len(config.APIKey) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing APIKey value")
|
writeMessage(w, "gemini", "Missing APIKey value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +258,7 @@ func auth(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +275,7 @@ func auth(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +287,7 @@ func workspace(w http.ResponseWriter, r *http.Request) {
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,29 +295,29 @@ func workspace(w http.ResponseWriter, r *http.Request) {
|
||||||
err = json.Unmarshal(body, &config)
|
err = json.Unmarshal(body, &config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Clean()
|
config.Clean()
|
||||||
|
|
||||||
if len(config.URL) == 0 {
|
if len(config.URL) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing URL value")
|
writeMessage(w, "gemini", "Missing URL value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.Username) == 0 {
|
if len(config.Username) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing Username value")
|
writeMessage(w, "gemini", "Missing Username value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.APIKey) == 0 {
|
if len(config.APIKey) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing APIKey value")
|
writeMessage(w, "gemini", "Missing APIKey value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.UserID == 0 {
|
if config.UserID == 0 {
|
||||||
writeMessage(w, sectionName, "Missing UserId value")
|
writeMessage(w, "gemini", "Missing UserId value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +331,7 @@ func workspace(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +360,7 @@ func items(w http.ResponseWriter, r *http.Request) {
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,24 +368,24 @@ func items(w http.ResponseWriter, r *http.Request) {
|
||||||
err = json.Unmarshal(body, &config)
|
err = json.Unmarshal(body, &config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeMessage(w, sectionName, "Bad payload")
|
writeMessage(w, "gemini", "Bad payload")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Clean()
|
config.Clean()
|
||||||
|
|
||||||
if len(config.URL) == 0 {
|
if len(config.URL) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing URL value")
|
writeMessage(w, "gemini", "Missing URL value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.Username) == 0 {
|
if len(config.Username) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing Username value")
|
writeMessage(w, "gemini", "Missing Username value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(config.APIKey) == 0 {
|
if len(config.APIKey) == 0 {
|
||||||
writeMessage(w, sectionName, "Missing APIKey value")
|
writeMessage(w, "gemini", "Missing APIKey value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +394,7 @@ func items(w http.ResponseWriter, r *http.Request) {
|
||||||
filter, err := json.Marshal(config.Filter)
|
filter, err := json.Marshal(config.Filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +408,7 @@ func items(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +425,7 @@ func items(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
writeError(w, sectionName, err)
|
writeError(w, "gemini", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
package section
|
package section
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type trello struct {
|
type trello struct {
|
||||||
|
@ -13,7 +19,6 @@ func init() {
|
||||||
|
|
||||||
func (*trello) Meta() TypeMeta {
|
func (*trello) Meta() TypeMeta {
|
||||||
section := TypeMeta{}
|
section := TypeMeta{}
|
||||||
|
|
||||||
section.ID = "c455a552-202e-441c-ad79-397a8152920b"
|
section.ID = "c455a552-202e-441c-ad79-397a8152920b"
|
||||||
section.Title = "Trello"
|
section.Title = "Trello"
|
||||||
section.Description = "Trello boards"
|
section.Description = "Trello boards"
|
||||||
|
@ -25,15 +30,286 @@ func (*trello) Meta() TypeMeta {
|
||||||
|
|
||||||
// Command stub.
|
// Command stub.
|
||||||
func (*trello) Command(w http.ResponseWriter, r *http.Request) {
|
func (*trello) Command(w http.ResponseWriter, r *http.Request) {
|
||||||
writeEmpty(w)
|
query := r.URL.Query()
|
||||||
|
method := query.Get("method")
|
||||||
|
|
||||||
|
if len(method) == 0 {
|
||||||
|
writeMessage(w, "trello", "missing method name")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch method {
|
||||||
|
case "cards":
|
||||||
|
cards(w, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render just sends back HMTL as-is.
|
// Render just sends back HMTL as-is.
|
||||||
func (*trello) Render(config, data string) string {
|
func (*trello) Render(config, data string) string {
|
||||||
return data
|
raw := []trelloListCards{}
|
||||||
|
payload := trelloRender{}
|
||||||
|
var c = trelloConfig{}
|
||||||
|
|
||||||
|
json.Unmarshal([]byte(data), &raw)
|
||||||
|
json.Unmarshal([]byte(config), &c)
|
||||||
|
|
||||||
|
payload.Board = c.Board
|
||||||
|
payload.Data = raw
|
||||||
|
payload.ListCount = len(raw)
|
||||||
|
|
||||||
|
for _, list := range raw {
|
||||||
|
payload.CardCount += len(list.Cards)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := template.New("trello")
|
||||||
|
t, _ = t.Parse(trelloTemplate)
|
||||||
|
|
||||||
|
buffer := new(bytes.Buffer)
|
||||||
|
t.Execute(buffer, payload)
|
||||||
|
|
||||||
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh just sends back data as-is.
|
// Refresh just sends back data as-is.
|
||||||
func (*trello) Refresh(config, data string) string {
|
func (*trello) Refresh(config, data string) string {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
func cards(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer r.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeMessage(w, "trello", "Bad body")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = trelloConfig{}
|
||||||
|
err = json.Unmarshal(body, &config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, "trello", err)
|
||||||
|
// writeMessage(w, "trello", "Bad payload")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Clean()
|
||||||
|
|
||||||
|
if len(config.AppKey) == 0 {
|
||||||
|
writeMessage(w, "trello", "Missing appKey")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Token) == 0 {
|
||||||
|
writeMessage(w, "trello", "Missing token")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
render := []trelloListCards{}
|
||||||
|
|
||||||
|
for _, list := range config.Lists {
|
||||||
|
|
||||||
|
if !list.Included {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/lists/%s/cards?key=%s&token=%s", list.ID, config.AppKey, config.Token), nil)
|
||||||
|
client := &http.Client{}
|
||||||
|
res, err := client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
writeError(w, "trello", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusOK {
|
||||||
|
writeForbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
var cards []trelloCard
|
||||||
|
|
||||||
|
dec := json.NewDecoder(res.Body)
|
||||||
|
err = dec.Decode(&cards)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
writeError(w, "trello", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := trelloListCards{}
|
||||||
|
data.Cards = cards
|
||||||
|
data.List = list
|
||||||
|
|
||||||
|
render = append(render, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJSON(w, render)
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloConfig struct {
|
||||||
|
AppKey string `json:"appKey"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
Board trelloBoard `json:"board"`
|
||||||
|
Lists []trelloList `json:"lists"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *trelloConfig) Clean() {
|
||||||
|
c.AppKey = strings.TrimSpace(c.AppKey)
|
||||||
|
c.Token = strings.TrimSpace(c.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloBoard struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
DescData struct {
|
||||||
|
Emoji struct{} `json:"emoji"`
|
||||||
|
} `json:"descData"`
|
||||||
|
Closed bool `json:"closed"`
|
||||||
|
OrganizationID string `json:"idOrganization"`
|
||||||
|
Pinned bool `json:"pinned"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
ShortURL string `json:"shortUrl"`
|
||||||
|
Prefs struct {
|
||||||
|
PermissionLevel string `json:"permissionLevel"`
|
||||||
|
Voting string `json:"voting"`
|
||||||
|
Comments string `json:"comments"`
|
||||||
|
Invitations string `json:"invitations"`
|
||||||
|
SelfJoin bool `json:"selfjoin"`
|
||||||
|
CardCovers bool `json:"cardCovers"`
|
||||||
|
CardAging string `json:"cardAging"`
|
||||||
|
CalendarFeedEnabled bool `json:"calendarFeedEnabled"`
|
||||||
|
Background string `json:"background"`
|
||||||
|
BackgroundColor string `json:"backgroundColor"`
|
||||||
|
BackgroundImage string `json:"backgroundImage"`
|
||||||
|
BackgroundImageScaled []trelloBoardBackground `json:"backgroundImageScaled"`
|
||||||
|
BackgroundTile bool `json:"backgroundTile"`
|
||||||
|
BackgroundBrightness string `json:"backgroundBrightness"`
|
||||||
|
CanBePublic bool `json:"canBePublic"`
|
||||||
|
CanBeOrg bool `json:"canBeOrg"`
|
||||||
|
CanBePrivate bool `json:"canBePrivate"`
|
||||||
|
CanInvite bool `json:"canInvite"`
|
||||||
|
} `json:"prefs"`
|
||||||
|
LabelNames struct {
|
||||||
|
Red string `json:"red"`
|
||||||
|
Orange string `json:"orange"`
|
||||||
|
Yellow string `json:"yellow"`
|
||||||
|
Green string `json:"green"`
|
||||||
|
Blue string `json:"blue"`
|
||||||
|
Purple string `json:"purple"`
|
||||||
|
} `json:"labelNames"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloBoardBackground struct {
|
||||||
|
width int `json:"width"`
|
||||||
|
height int `json:"height"`
|
||||||
|
url string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloList struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Closed bool `json:"closed"`
|
||||||
|
BoardID string `json:"idBoard"`
|
||||||
|
Pos float32 `json:"pos"`
|
||||||
|
Included bool `json:"included"` // indicates whether we display cards from this list
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloCard struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
ShortID int `json:"idShort"`
|
||||||
|
AttachmentCoverID string `json:"idAttachmentCover"`
|
||||||
|
CheckListsID []string `json:"idCheckLists"`
|
||||||
|
BoardID string `json:"idBoard"`
|
||||||
|
ListID string `json:"idList"`
|
||||||
|
MembersID []string `json:"idMembers"`
|
||||||
|
MembersVotedID []string `json:"idMembersVoted"`
|
||||||
|
ManualCoverAttachment bool `json:"manualCoverAttachment"`
|
||||||
|
Closed bool `json:"closed"`
|
||||||
|
Pos float32 `json:"pos"`
|
||||||
|
ShortLink string `json:"shortLink"`
|
||||||
|
DateLastActivity string `json:"dateLastActivity"`
|
||||||
|
ShortURL string `json:"shortUrl"`
|
||||||
|
Subscribed bool `json:"subscribed"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Due string `json:"due"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
DescData struct {
|
||||||
|
Emoji struct{} `json:"emoji"`
|
||||||
|
} `json:"descData"`
|
||||||
|
CheckItemStates []struct {
|
||||||
|
CheckItemID string `json:"idCheckItem"`
|
||||||
|
State string `json:"state"`
|
||||||
|
} `json:"checkItemStates"`
|
||||||
|
Badges struct {
|
||||||
|
Votes int `json:"votes"`
|
||||||
|
ViewingMemberVoted bool `json:"viewingMemberVoted"`
|
||||||
|
Subscribed bool `json:"subscribed"`
|
||||||
|
Fogbugz string `json:"fogbugz"`
|
||||||
|
CheckItems int `json:"checkItems"`
|
||||||
|
CheckItemsChecked int `json:"checkItemsChecked"`
|
||||||
|
Comments int `json:"comments"`
|
||||||
|
Attachments int `json:"attachments"`
|
||||||
|
Description bool `json:"description"`
|
||||||
|
Due string `json:"due"`
|
||||||
|
} `json:"badges"`
|
||||||
|
Labels []struct {
|
||||||
|
Color string `json:"color"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"labels"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloListCards struct {
|
||||||
|
List trelloList
|
||||||
|
Cards []trelloCard
|
||||||
|
}
|
||||||
|
|
||||||
|
type trelloRender struct {
|
||||||
|
Board trelloBoard
|
||||||
|
Data []trelloListCards
|
||||||
|
CardCount int
|
||||||
|
ListCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
// the HTML that is rendered by this section
|
||||||
|
const trelloTemplate = `
|
||||||
|
<p>There are {{ .CardCount }} cards across {{ .ListCount }} lists for board <a href="{{ .Board.URL }}">{{.Board.Name}}.</a></p>
|
||||||
|
<div class="trello-board" style="background-color: {{.Board.Prefs.BackgroundColor}}">
|
||||||
|
<a href="{{ .Board.URL }}"><div class="trello-board-title">{{.Board.Name}}</div></a>
|
||||||
|
{{range $data := .Data}}
|
||||||
|
<div class="trello-list">
|
||||||
|
<div class="trello-list-title">{{ $data.List.Name }}</div>
|
||||||
|
{{range $card := $data.Cards}}
|
||||||
|
<a href="{{ $card.URL }}">
|
||||||
|
<div class="trello-card">
|
||||||
|
{{ $card.Name }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
refresh method
|
||||||
|
|
||||||
|
does server side load up all data? YES!!??
|
||||||
|
|
||||||
|
we need method to use different trello accounts
|
||||||
|
- does this mean logout button?
|
||||||
|
- does this only work on add section phase?
|
||||||
|
|
||||||
|
is appKey is global?
|
||||||
|
- where stored?
|
||||||
|
- how access?
|
||||||
|
- does section.go ask config to give us saved json
|
||||||
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue