diff --git a/app/app/components/section/trello/type-editor.js b/app/app/components/section/trello/type-editor.js index 87a6470d..9392f020 100644 --- a/app/app/components/section/trello/type-editor.js +++ b/app/app/components/section/trello/type-editor.js @@ -50,8 +50,7 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, token: "", user: null, board: null, - lists: [], - boards: [] + lists: [] }; } @@ -102,12 +101,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, this.set('noBoards', false); - if (is.undefined(self.get('initDateTimePicker'))) { - $.datetimepicker.setLocale('en'); - $('#trello-since').datetimepicker(); - self.set('initDateTimePicker', "Done"); - } - if (is.null(board) || is.undefined(board)) { if (boards.length) { board = boards[0]; @@ -117,34 +110,30 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, this.set('config.board', boards.findBy('id', board.id)); } - if (is.null(board.id) || is.undefined(board.id)) { - self.set('busy', false); - } else { - this.get('sectionService').fetch(page, "lists", self.get('config')) - .then(function (lists) { - let savedLists = self.get('config.lists'); - if (savedLists === null) { - savedLists = []; + this.get('sectionService').fetch(page, "lists", self.get('config')) + .then(function (lists) { + let savedLists = self.get('config.lists'); + if (savedLists === null) { + savedLists = []; + } + + lists.forEach(function (list) { + let saved = savedLists.findBy("id", list.id); + let included = true; + if (is.not.undefined(saved)) { + included = saved.included; } - - lists.forEach(function (list) { - let saved = savedLists.findBy("id", list.id); - let included = true; - if (is.not.undefined(saved)) { - included = saved.included; - } - list.included = included; - }); - - self.set('config.lists', lists); - self.set('busy', false); - }, function (error) { //jshint ignore: line - self.set('busy', false); - self.set('authenticated', false); - self.showNotification("Unable to fetch board lists"); - console.log(error); + list.included = included; }); - } + + self.set('config.lists', lists); + self.set('busy', false); + }, function (error) { //jshint ignore: line + self.set('busy', false); + self.set('authenticated', false); + self.showNotification("Unable to fetch board lists"); + console.log(error); + }); }, actions: { @@ -161,15 +150,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, } }, - onBoardCheckbox(id) { - let boards = this.get('config.boards'); - let board = boards.findBy('id', id); - - if (board !== null) { - Ember.set(board, 'included', !board.included); - } - }, - auth() { if (this.get('appKey') === "") { $("#trello-appkey").addClass('error').focus(); @@ -207,8 +187,6 @@ export default Ember.Component.extend(SectionMixin, NotifierMixin, TooltipMixin, self.get('sectionService').fetch(page, "boards", self.get('config')) .then(function (boards) { self.set('busy', false); - boards.unshift({ id: null, namePath: "< do not show >", backgroundColor: "white" }); // add the non-selection to the front - self.set('config.boards', boards); // save the boards in the config too self.set('boards', boards); self.getBoardLists(); }, function (error) { //jshint ignore: line diff --git a/app/app/styles/section/trello.scss b/app/app/styles/section/trello.scss index 5bbc380b..20bba3e8 100644 --- a/app/app/styles/section/trello.scss +++ b/app/app/styles/section/trello.scss @@ -1,103 +1,89 @@ -.section-trello-editor { - .section-trello-board { - width: 100%; - padding: 10px; - white-space: nowrap; - overflow: auto - } - - .section-trello-board-title { - font-weight: bold; - color: #fff; - font-size: 16px; - } - - .section-trello-list { - background-color: #e2e4e6; - padding: 10px; - border-radius: 3px; - margin: 10px 10px 0 0; - max-width: 300px; - } - - .section-trello-list-title { - font-weight: bold; - color: #4c4c4c; - font-size: 14px; - margin: 5px; - } - - .section-trello-list-checkbox { - vertical-align: text-bottom; - } - - .trello-list { - margin-bottom: 10px; - - i { - vertical-align: middle; - } - - .trello-label { - font-size: 11px; - color: #fff; - padding: 0 8px; - margin-right: 5px; - border-radius: 2px; - box-shadow: inset 0 -1px 0 rgba(0,0,0,.12); - display: inline-block; - line-height: 22px; - } - } - +.section-trello-board { + width: 100%; + padding: 10px; + white-space: nowrap; + overflow: auto } +.section-trello-board-title { + font-weight: bold; + color: #fff; + font-size: 16px; +} + +.section-trello-list { + background-color: #e2e4e6; + padding: 10px; + border-radius: 3px; + margin: 10px 10px 0 0; + max-width: 300px; +} + +.section-trello-list-title { + font-weight: bold; + color: #4c4c4c; + font-size: 14px; + margin: 5px; +} + +.section-trello-list-checkbox { + vertical-align: text-bottom; +} + + .section-trello-render { + > .trello-board { + width: 100%; + max-height: 600px; + padding: 10px; + white-space: nowrap; + overflow: auto; - a:hover { - text-decoration: underline; - } - - .heading { - - h3 { - font-size: 22px; - margin: 0; - font-family: "open_sanslight"; + > a { + > .trello-board-title { + font-weight: bold; + color: #fff; + font-size: 16px; + } } - } + > .trello-list { + background-color: #e2e4e6; + padding: 10px; + border-radius: 3px; + margin: 10px 10px 0 0; + width: 300px; + max-height: 500px; + display: inline-block; + white-space: nowrap; + overflow: auto; + vertical-align: top; - table.trello-single-board { - border: none!important; - text-align: left; - margin:0!important; - } - - .trello-single-board thead tr th { - padding: 15px 0; - border-bottom: 1px solid #e1e1e1; - text-transform: uppercase; - font-size: 14px; - - span { - color:#838d94; + > .trello-list-title { + font-weight: bold; + color: #4c4c4c; + font-size: 14px; + margin: 0 10px 10px 0; + } + + > a { + > .trello-card { + color: #4c4c4c; + border-bottom: 1px solid #CDD2D4; + background-color: #fff; + border-radius: 3px; + padding: 7px 7px; + margin: 5px 0; + font-size: 14px; + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + line-height: 18px; + overflow: hidden; + word-wrap: break-word; + white-space: normal; + cursor: pointer; + vertical-align: top; + } + } } - - } - - .trello-single-board tbody tr td { - border: none!important; - padding: 5px 20px 5px 20px !important; - } - - .trello-label { - color:white; - font-size: 11px; - padding: 4px 6px; - border-radius: 4px; - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.12); - margin-left: 14px; - } - -} + } +} \ No newline at end of file diff --git a/app/app/templates/components/section/trello/type-editor.hbs b/app/app/templates/components/section/trello/type-editor.hbs index 9dce5877..d98540dc 100644 --- a/app/app/templates/components/section/trello/type-editor.hbs +++ b/app/app/templates/components/section/trello/type-editor.hbs @@ -2,89 +2,52 @@ 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')}} -
- {{#if authenticated}} - {{#if noBoards}} + +
+ {{#if noBoards}}
You have no team boards to share - personal boards are never shown.
- {{else}} - -
+ {{else}}
- -
Select board
- {{ui-select id="boards-dropdown" content=boards action=(action 'onBoardChange') optionValuePath="id" optionLabelPath="namePath" selection=config.board}} + +
Choose lists to include from board
+ {{ui-select id="boards-dropdown" content=boards action=(action 'onBoardChange') optionValuePath="id" optionLabelPath="name" selection=config.board}}
- {{#if config.board.id}} -
- -
Select lists to include
-
-
{{config.board.name}}
- {{#each config.lists as |list|}} -
- {{#if list.included}} - check_box - {{else}} - check_box_outline_blank - {{/if}} - {{list.name}} -
- {{/each}} -
+
+ +
Select lists to include
+
+
{{config.board.name}}
+ {{#each config.lists as |list|}} +
+ {{#if list.included}} + check_box + {{else}} + check_box_outline_blank + {{/if}} + {{list.name}} +
+ {{/each}}
- {{/if}} -
- {{/if}} - {{else}} -
-
- -
Click to authenticate with Trello
-
-
Authenticate
+
+ {{/if}}
- {{/if}} -
-{{/section/base-editor}} + {{else}} + +
+
+
+
Authentication
+
Click to authenticate with Trello
+
+
Authenticate
+
+
+ + {{/if}} + +{{/section/base-editor}} \ No newline at end of file diff --git a/app/app/templates/components/section/trello/type-renderer.hbs b/app/app/templates/components/section/trello/type-renderer.hbs index 4831c672..24600468 100644 --- a/app/app/templates/components/section/trello/type-renderer.hbs +++ b/app/app/templates/components/section/trello/type-renderer.hbs @@ -1 +1,3 @@ -{{{page.body}}} +
+ {{{page.body}}} +
diff --git a/core/section/papertrail/papertrail.go b/core/section/papertrail/papertrail.go index 02675fe5..af11f6ec 100644 --- a/core/section/papertrail/papertrail.go +++ b/core/section/papertrail/papertrail.go @@ -27,7 +27,7 @@ import ( const me = "papertrail" -// Provider represents Gemini +// Provider represents Papertrail type Provider struct { } diff --git a/core/section/trello/activitytranslation.go b/core/section/trello/activitytranslation.go deleted file mode 100644 index 331b8ff7..00000000 --- a/core/section/trello/activitytranslation.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -var activityTranslation = map[string]string{ - "add checklist to card": "checklist added to card", - "add member to card": "member added to card", - "comment card": "commented on card", - "create card": "created card", - "create list": "created list", - "delete card": "deleted card", - "update board": "updated board", - "add to team board": "", - "create board": "", - "update card": "updated card", - "update check item state on card": "check item updated on card", - "update list": "updated list", - "add attachment to card": "attachment added to card", - "copy card": "copied card", - "copy comment card": "copied comment on card", -} diff --git a/core/section/trello/archive_template.go b/core/section/trello/archive_template.go deleted file mode 100644 index 7bcd4a03..00000000 --- a/core/section/trello/archive_template.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const archiveTemplate = ` -{{if false}} -
- - {{if gt (len .Boards) 0}} -
Deleted and Archived Cards
-

Changes since {{.Since}}.

-
- - - {{range $b := .Boards}} - - - - - {{end}} - -
- - {{$b.Board.Name}} - - - {{range $act := $b.Actions}} - {{if eq $act.Type "deleteCard" }} - Deleted: - {{$act.Data.List.Name}} - {{if ne $act.Data.Card.Name ""}} - : {{$act.Data.Card.Name}} - {{if ne $act.Data.Text ""}} - - {{$act.Data.Text}} - {{end}} - {{end}} -
- {{end}} - {{end}} - {{range $arch := $b.Archived}} - Archived: - {{$arch.Name}} - {{if ne $arch.Desc ""}} - - {{$arch.Desc}} - {{end}} -
- {{end}} -
-
- {{end}} -
-{{end}} -` diff --git a/core/section/trello/boards_template.go b/core/section/trello/boards_template.go deleted file mode 100644 index 3309b173..00000000 --- a/core/section/trello/boards_template.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const boardsTemplate = ` -
- {{if gt (len .Boards) 0}} -
Boards
-

There are {{len .Boards}} boards, {{.ListTotal}} lists, {{.CardTotal}} cards and {{len .MemberBoardAssign}} members. Activity since {{.Since}}

-
- - - {{range $b := .Boards}} - - - - - {{end}} - -
- -
- {{$b.Board.Name}} - {{$b.Board.OrgName}} -
-
-
-
- -
- - {{range $idx, $act := $b.ActionSummary}}{{if ne $idx 0}}{{- ","}} {{end}}{{$act.Count}} {{$act.Name -}}{{if ne 1 $act.Count}}{{"s" -}}{{end}}{{end}}{{if gt (len $b.Archived) 0}}, {{end}} - {{if gt (len $b.Archived) 0}} - {{len $b.Archived}} {{if eq 1 (len $b.Archived)}}card {{else}} cards {{end}}archived - {{else}} - {{if eq (len $b.ActionSummary) 0}} - no activity - {{end}} - {{end}} -
-
-
-
- {{end}} -
-` diff --git a/core/section/trello/graphs_template.go b/core/section/trello/graphs_template.go deleted file mode 100644 index cd1971ca..00000000 --- a/core/section/trello/graphs_template.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const graphsTemplate = ` -{{if false}} - -
Single Boards (graphs)
- {{range $b := .Boards}} -
-

There are {{ $b.CardCount }} cards across {{ $b.ListCount }} lists for board {{$b.Board.Name}}.

-
- {{range $data := $b.Data}} -
- {{ $data.List.Name }} -
- {{end}} -
-
- {{end}} - -{{end}} -` diff --git a/core/section/trello/labels_template.go b/core/section/trello/labels_template.go deleted file mode 100644 index febe8f5e..00000000 --- a/core/section/trello/labels_template.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const labelsTemplate = ` -
- {{if gt (len .SharedLabels) 0}} -
Labels
-

There are {{len .SharedLabels}} common labels across the boards.

-
- - - {{range $l := .SharedLabels}} - - - - - {{end}} - -
- {{ $l.Name }} ({{len $l.Boards}}) - - {{range $idx, $brd := $l.Boards}}{{if gt $idx 0}}, {{end}}{{$brd.OrgName}}/{{$brd.Name}}{{end}} -
-
- {{end}} -
-` diff --git a/core/section/trello/master_template.go b/core/section/trello/master_template.go deleted file mode 100644 index d3ce657f..00000000 --- a/core/section/trello/master_template.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const renderTemplate = ` -{{if eq .Since ""}} -

Preparing...

-{{else}} - -{{end}}` + - //labelsTemplate + - //boardsTemplate + - //graphsTemplate + - //membersTemplate + - //archiveTemplate + - tradTemplate + - `` diff --git a/core/section/trello/members_template.go b/core/section/trello/members_template.go deleted file mode 100644 index a209c39b..00000000 --- a/core/section/trello/members_template.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const membersTemplate = ` -
- {{if gt (len .Boards) 0}} -
Members
-

- There {{if eq 1 (len .MemberBoardAssign)}} is one member {{else}} are {{len .MemberBoardAssign}} members {{end}} assigned to {{.CardAssignTotal}} cards of the total {{.CardTotal}} cards across {{len .Boards}} boards. -

- -
- - - {{range $m := .MemberBoardAssign}} - - - - - {{end}} - -
- Member Avatar - -
{{$m.MemberName}}
-
- {{range $idx, $ac := $m.AssignCounts}}{{if gt $idx 0}}, {{end}}{{$ac.BoardName}} ({{$ac.Count}}){{end}} -
-
-
-
- {{end}} -
-` diff --git a/core/section/trello/model.go b/core/section/trello/model.go index a136b58f..d89c8332 100644 --- a/core/section/trello/model.go +++ b/core/section/trello/model.go @@ -11,25 +11,38 @@ package trello -import ( - "strings" - "time" -) +import "strings" + +const renderTemplate = ` +
+

There are {{ .CardCount }} cards across {{ .ListCount }} lists for board {{.Board.Name}}.

+
+
{{.Board.Name}}
+ {{range $data := .Data}} +
+
{{ $data.List.Name }}
+ {{range $card := $data.Cards}} + +
+ {{ $card.Name }} +
+
+ {{end}} +
+ {{end}} +
+
+` type secrets struct { Token string `json:"token"` } type trelloConfig struct { - AppKey string `json:"appKey"` - Token string `json:"token"` - Board trelloBoard `json:"board"` - Lists []trelloList `json:"lists"` - Boards []trelloBoard `json:"boards"` - Since string `json:"since,omitempty"` - SincePtr *time.Time `json:"-"` - - OrgByID map[string]trelloOrganization `json:"-"` + AppKey string `json:"appKey"` + Token string `json:"token"` + Board trelloBoard `json:"board"` + Lists []trelloList `json:"lists"` } func (c *trelloConfig) Clean() { @@ -38,73 +51,6 @@ func (c *trelloConfig) Clean() { } // Trello objects based upon https://github.com/VojtechVitek/go-trello - -type trelloOrganization struct { - ID string `json:"id"` - Name string `json:"name"` - DisplayName string `json:"displayName"` - Desc string `json:"desc"` - DescData string `json:"descData"` - URL string `json:"url"` - Website string `json:"website"` - LogoHash string `json:"logoHash"` - Products []string `json:"products"` - PowerUps []string `json:"powerUps"` -} - -type trelloAction struct { - ID string `json:"id"` - IDMemberCreator string `json:"idMemberCreator"` - Data struct { - DateLastEdited string `json:"dateLastEdited"` - ListBefore struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"listBefore"` - ListAfter struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"listAfter"` - CheckItem struct { - ID string `json:"id"` - State string `json:"state"` - Name string `json:"name"` - } `json:"checkItem"` - CheckList struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"checklist"` - List struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"list"` - TextData struct { - Emoji struct{} `json:"emoji"` - } `json:"textData"` - Board struct { - ID string `json:"id"` - Name string `json:"name"` - ShortLink string `json:"shortLink"` - } `json:"board"` - Card struct { - ID string `json:"id"` - Name string `json:"name"` - ShortLink string `json:"shortLink"` - IDShort int `json:"idShort"` - } `json:"card"` - Text string `json:"text"` - } `json:"data"` - Type string `json:"type"` - Date string `json:"date"` - MemberCreator struct { - ID string `json:"id"` - AvatarHash string `json:"avatarHash"` - FullName string `json:"fullName"` - Initials string `json:"initials"` - Username string `json:"username"` - } `json:"memberCreator"` -} - type trelloMember struct { ID string `json:"id"` AvatarHash string `json:"avatarHash"` @@ -147,7 +93,6 @@ type trelloBoard struct { Name string `json:"name"` Closed bool `json:"closed"` OrganizationID string `json:"idOrganization"` - OrgName string `json:"orgName"` Pinned bool `json:"pinned"` URL string `json:"url"` ShortURL string `json:"shortUrl"` @@ -183,8 +128,6 @@ type trelloBoard struct { Blue string `json:"blue"` Purple string `json:"purple"` } `json:"labelNames"` - Included bool `json:"included"` // indicates whether we display this board - NamePath string `json:"namePath"` // the "team / board" form } type trelloBoardBackground struct { @@ -253,48 +196,9 @@ type trelloListCards struct { Cards []trelloCard } -type trelloActionSummaryEntry struct { - Name string - Count int -} - -type trelloRenderBoard struct { - Board trelloBoard - Data []trelloListCards - CardCount int - ListCount int - Actions []trelloAction - ActionSummary []trelloActionSummaryEntry - Archived []trelloCard -} - -type trelloSharedLabel struct { - Name string - Color string - Boards []trelloBoard -} - -type trelloBoardAssignCount struct { - BoardName string - Count int -} - -type trelloBoardAssign struct { - AvatarHash string - MemberName string - AssignCounts []trelloBoardAssignCount -} - type trelloRender struct { - Boards []trelloRenderBoard - Since string - Detail trelloRenderBoard - - // items below are generated during the render phase - SharedLabels []trelloSharedLabel - MembersByID map[string]trelloMember - MemberBoardAssign []trelloBoardAssign - CardAssignTotal int - CardTotal int - ListTotal int + Board trelloBoard + Data []trelloListCards + CardCount int + ListCount int } diff --git a/core/section/trello/trad_template.go b/core/section/trello/trad_template.go deleted file mode 100644 index 9a95405a..00000000 --- a/core/section/trello/trad_template.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2016 Documize Inc. . All rights reserved. -// -// This software (Documize Community Edition) is licensed under -// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html -// -// You can operate outside the AGPL restrictions by purchasing -// Documize Enterprise Edition and obtaining a commercial license -// by contacting . -// -// https://documize.com - -package trello - -const tradTemplate = ` -
- {{if ne .Detail.Board.ID ""}} -
-

There are {{ .Detail.CardCount }} cards across {{ .Detail.ListCount }} lists on {{.Detail.Board.Name}} Board

-
-
-
- - {{range $data := .Detail.Data}} - - - - - - - - - {{range $card := $data.Cards}} - - - - - {{end}} - - {{end}} -
{{ $data.List.Name }} · {{len $data.Cards}} cards
- -
- {{ $card.Name }} -
-
-
- {{range $label := $card.Labels}} - {{$label.Name}} - {{end}} -
- -
-
- {{end}} -
- -` diff --git a/core/section/trello/trello.go b/core/section/trello/trello.go index 8e30f473..0a8fdb5c 100644 --- a/core/section/trello/trello.go +++ b/core/section/trello/trello.go @@ -18,10 +18,6 @@ import ( "html/template" "io/ioutil" "net/http" - "sort" - "strings" - "time" - "unicode" "github.com/documize/community/core/api/request" "github.com/documize/community/core/log" @@ -32,6 +28,7 @@ var meta provider.TypeMeta func init() { meta = provider.TypeMeta{} + meta.ID = "c455a552-202e-441c-ad79-397a8152920b" meta.Title = "Trello" meta.Description = "Embed cards from boards and lists" @@ -39,11 +36,11 @@ func init() { meta.PageType = "tab" } -// Provider represents Trello +// Provider represents GitHub type Provider struct { } -// Meta describes us +// Meta describes us. func (*Provider) Meta() provider.TypeMeta { return meta } @@ -103,7 +100,7 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R provider.WriteJSON(w, render) case "boards": - render, err := getBoards(&config) + render, err := getBoards(config) if err != nil { log.IfErr(err) @@ -152,32 +149,28 @@ func (*Provider) Command(ctx *provider.Context, w http.ResponseWriter, r *http.R log.IfErr(ctx.SaveSecrets(string(b))) } -// Render the payload using the template. +// Render just sends back HMTL as-is. func (*Provider) Render(ctx *provider.Context, config, data string) string { - var payload = trelloRender{} + raw := []trelloListCards{} + payload := trelloRender{} var c = trelloConfig{} - json.Unmarshal([]byte(data), &payload) + json.Unmarshal([]byte(data), &raw) json.Unmarshal([]byte(config), &c) - buildPayloadAnalysis(&c, &payload) + payload.Board = c.Board + payload.Data = raw + payload.ListCount = len(raw) + + for _, list := range raw { + payload.CardCount += len(list.Cards) + } t := template.New("trello") - var err error - t, err = t.Parse(renderTemplate) - - if err != nil { - log.IfErr(err) - return "" - } + t, _ = t.Parse(renderTemplate) buffer := new(bytes.Buffer) - err = t.Execute(buffer, payload) - - if err != nil { - log.IfErr(err) - return "" - } + t.Execute(buffer, payload) return buffer.String() } @@ -185,80 +178,15 @@ func (*Provider) Render(ctx *provider.Context, config, data string) string { // Refresh just sends back data as-is. func (*Provider) Refresh(ctx *provider.Context, config, data string) string { var c = trelloConfig{} - log.IfErr(json.Unmarshal([]byte(config), &c)) + json.Unmarshal([]byte(config), &c) - save := trelloRender{} - save.Boards = make([]trelloRenderBoard, 0, len(c.Boards)) + refreshed, err := getCards(c) - if len(c.Since) >= len("yyyy/mm/dd hh:ss") { - var since time.Time - tt := []byte("yyyy-mm-ddThh:mm:00Z") - for _, i := range []int{0, 1, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15} { - tt[i] = c.Since[i] - } - err := since.UnmarshalText(tt) - if err != nil { - log.ErrorString("Date unmarshall '" + c.Since + "'->'" + string(tt) + "' error: " + err.Error()) - } else { - c.SincePtr = &since - } - } - dateMessage := "" - if c.SincePtr == nil { - dateMessage = " (the last 7 days)" - since := time.Now().AddDate(0, 0, -7) - c.SincePtr = &since - c.Since = (*c.SincePtr).Format("2006/01/02 ") - } - save.Since = (*c.SincePtr).Format("January 2, 2006") + dateMessage - - c.AppKey = request.ConfigString(meta.ConfigHandle(), "appKey") - - if c.Board.ID != "" { // set up detail board - var err error - save.Detail.Board = c.Board - save.Detail.Data, err = getCards(c) - log.IfErr(err) - save.Detail.ListCount = len(save.Detail.Data) - for _, list := range save.Detail.Data { - save.Detail.CardCount += len(list.Cards) - } + if err != nil { + return data } - for _, board := range c.Boards { - if board.Included && board.ID != "" { - var payload = trelloRenderBoard{} - - c.Board = board - - lsts, err := getLists(c) - log.IfErr(err) - if err == nil { - c.Lists = lsts - } - - for l := range c.Lists { - c.Lists[l].Included = true - } - - refreshed, err := getCards(c) - log.IfErr(err) - - payload.Board = c.Board - payload.Data = refreshed - payload.ListCount = len(refreshed) - - for _, list := range refreshed { - payload.CardCount += len(list.Cards) - } - - payload.Actions, payload.Archived = fetchBoardActions(&c, &save, board.ID, c.Since) - - save.Boards = append(save.Boards, payload) - } - } - - j, err := json.Marshal(save) + j, err := json.Marshal(refreshed) if err != nil { log.Error("unable to marshall trello cards", err) @@ -269,48 +197,8 @@ func (*Provider) Refresh(ctx *provider.Context, config, data string) string { } // Helpers - -func getOrg(config *trelloConfig, orgID string) (*trelloOrganization, error) { - if config.OrgByID == nil { - config.OrgByID = make(map[string]trelloOrganization) - } - if org, found := config.OrgByID[orgID]; found { - return &org, nil - } - req, err := http.NewRequest("GET", fmt.Sprintf( - "https://api.trello.com/1/organizations/%s?fields=name,desc&key=%s&token=%s", - orgID, config.AppKey, config.Token), nil) - log.IfErr(err) - client := &http.Client{} - res, err := client.Do(req) - - if err != nil { - return nil, err - } - - if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("error: HTTP status code %d", res.StatusCode) - } - - b := trelloOrganization{} - - defer res.Body.Close() - dec := json.NewDecoder(res.Body) - err = dec.Decode(&b) - if err != nil { - fmt.Println(err) - return nil, err - } - - config.OrgByID[orgID] = b - return &b, nil -} - -func getBoards(config *trelloConfig) (boards []trelloBoard, err error) { - req, err := http.NewRequest("GET", fmt.Sprintf( - "https://api.trello.com/1/members/me/boards?fields=id,name,url,closed,prefs,idOrganization&key=%s&token=%s", - config.AppKey, config.Token), nil) - log.IfErr(err) +func getBoards(config trelloConfig) (boards []trelloBoard, err error) { + req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/members/me/boards?fields=id,name,url,closed,prefs,idOrganization&key=%s&token=%s", config.AppKey, config.Token), nil) client := &http.Client{} res, err := client.Do(req) @@ -327,45 +215,24 @@ func getBoards(config *trelloConfig) (boards []trelloBoard, err error) { defer res.Body.Close() dec := json.NewDecoder(res.Body) err = dec.Decode(&b) - if err != nil { - fmt.Println(err) - return nil, err - } // we only show open, team boards (not personal) for _, b := range b { if !b.Closed && len(b.OrganizationID) > 0 { - if o, e := getOrg(config, b.OrganizationID); e == nil { - b.OrgName = o.Name - b.NamePath = o.Name + " / " + b.Name - } else { - log.Error("failed to get organisation infomation", e) - } boards = append(boards, b) } } - for bx, bd := range boards { - for _, cd := range config.Boards { - if bd.ID == cd.ID { - boards[bx].Included = cd.Included // to pick up the previous selection or not - goto foundID - } - } - boards[bx].Included = false // don't include boards by default - foundID: + if err != nil { + fmt.Println(err) + return nil, err } return boards, nil } func getLists(config trelloConfig) (lists []trelloList, err error) { - if config.Board.ID == "" { - return - } - uri := fmt.Sprintf("https://api.trello.com/1/boards/%s/lists/open?key=%s&token=%s", config.Board.ID, config.AppKey, config.Token) - req, err := http.NewRequest("GET", uri, nil) - log.IfErr(err) + req, err := http.NewRequest("GET", fmt.Sprintf("https://api.trello.com/1/boards/%s/lists/open?key=%s&token=%s", config.Board.ID, config.AppKey, config.Token), nil) client := &http.Client{} res, err := client.Do(req) @@ -399,7 +266,6 @@ func getCards(config trelloConfig) (listCards []trelloListCards, err error) { } 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) - log.IfErr(err) client := &http.Client{} res, err := client.Do(req) @@ -430,257 +296,3 @@ func getCards(config trelloConfig) (listCards []trelloListCards, err error) { return listCards, nil } - -func fetchMember(config *trelloConfig, render *trelloRender, memberID string) (memberInfo trelloMember) { - memberInfo.FullName = "(unknown)" - - if render.MembersByID == nil { - render.MembersByID = make(map[string]trelloMember) - } - found := false - if memberInfo, found = render.MembersByID[memberID]; found { - return - } - render.MembersByID[memberID] = memberInfo // write unknown, so that we do not retry on errors - - if len(config.AppKey) == 0 { - config.AppKey = request.ConfigString(meta.ConfigHandle(), "appKey") - } - uri := fmt.Sprintf("https://api.trello.com/1/members/%s?key=%s&token=%s", memberID, config.AppKey, config.Token) - req, err := http.NewRequest("GET", uri, nil) - if err != nil { - log.IfErr(err) - return - } - client := &http.Client{} - res, err := client.Do(req) - if err != nil { - log.IfErr(err) - return - } - - if res.StatusCode != http.StatusOK { - log.ErrorString("Trello fetch member HTTP status not OK") - return - } - - defer res.Body.Close() - - dec := json.NewDecoder(res.Body) - err = dec.Decode(&memberInfo) - if err != nil { - log.IfErr(err) - return - } - - render.MembersByID[memberID] = memberInfo - - return -} - -func fetchBoardActions(config *trelloConfig, render *trelloRender, boardID string, since string) (actions []trelloAction, archived []trelloCard) { - - sinceString := since[:10] - - if len(config.AppKey) == 0 { - config.AppKey = request.ConfigString(meta.ConfigHandle(), "appKey") - } - - { - uri := fmt.Sprintf("https://api.trello.com/1/boards/%s/actions?limit=1000&since=%s&key=%s&token=%s", boardID, sinceString, config.AppKey, config.Token) - - req, err := http.NewRequest("GET", uri, nil) - if err != nil { - log.IfErr(err) - return - } - client := &http.Client{} - res, err := client.Do(req) - if err != nil { - log.IfErr(err) - return - } - - if res.StatusCode != http.StatusOK { - log.ErrorString("Trello fetch board actions HTTP status not OK") - return - } - - defer res.Body.Close() - - dec := json.NewDecoder(res.Body) - err = dec.Decode(&actions) - if err != nil { - log.IfErr(err) - return - } - } - - { - uri := fmt.Sprintf("https://api.trello.com/1/boards/%s/cards?filter=closed&since=%s&key=%s&token=%s", - boardID, sinceString, config.AppKey, config.Token) - req, err := http.NewRequest("GET", uri, nil) - if err != nil { - log.IfErr(err) - return - } - client := &http.Client{} - res, err := client.Do(req) - if err != nil { - log.IfErr(err) - return - } - - if res.StatusCode != http.StatusOK { - msg := "" - txt, err := ioutil.ReadAll(res.Body) - if err == nil { - msg = string(txt) - } else { - msg = err.Error() - } - log.ErrorString("Trello fetch board archived HTTP status not OK - " + msg) - return - } - - defer res.Body.Close() - - dec := json.NewDecoder(res.Body) - err = dec.Decode(&archived) - if err != nil { - log.IfErr(err) - return - } - } - - return -} - -func buildPayloadAnalysis(config *trelloConfig, render *trelloRender) { - - //totals - render.CardTotal = 0 - render.CardAssignTotal = 0 - render.ListTotal = 0 - - // pre-process labels - type labT struct { - color string - boards map[string]trelloBoard - } - labels := make(map[string]labT) - - // pre-process member stats - memberBoardCount := make(map[string]map[string]int) - - // main loop - for brdIdx, brd := range render.Boards { - for _, lst := range brd.Data { - render.ListTotal++ - for _, crd := range lst.Cards { - render.CardTotal++ - if len(crd.MembersID) > 0 { - render.CardAssignTotal++ - } - - // process labels - for _, lab := range crd.Labels { - if _, exists := labels[lab.Name]; !exists { - labels[lab.Name] = labT{color: lab.Color, boards: make(map[string]trelloBoard)} - } - labels[lab.Name].boards[brd.Board.URL+" / "+brd.Board.Name] = brd.Board - } - - // process member stats - for _, mem := range crd.MembersID { - if _, exists := memberBoardCount[mem]; !exists { - memberBoardCount[mem] = make(map[string]int) - } - memberBoardCount[mem][brd.Board.ID]++ - } - } - } - - // ActionSummary - actionSummaryMap := make(map[string]int) - - for _, act := range brd.Actions { - englishType := "" - for _, c := range act.Type { - if unicode.IsUpper(c) { - englishType += " " - englishType += string(unicode.ToLower(c)) - } else { - englishType += string(c) - } - } - englishType = strings.Replace(englishType, "organization", "team", -1) - if newTxt, found := activityTranslation[englishType]; found { - englishType = newTxt - } - if len(englishType) > 0 { - actionSummaryMap[englishType]++ - } - } - acts := make([]string, 0, len(actionSummaryMap)) - for a := range actionSummaryMap { - acts = append(acts, a) - } - sort.Strings(acts) - render.Boards[brdIdx].ActionSummary = make([]trelloActionSummaryEntry, len(acts)) - for k, v := range acts { - render.Boards[brdIdx].ActionSummary[k] = trelloActionSummaryEntry{Name: v, Count: actionSummaryMap[v]} - - } - - } - - //post-process labels - labs := make([]string, 0, len(labels)) - for lname := range labels { - labs = append(labs, lname) - } - sort.Strings(labs) - for _, lname := range labs { - thisLabel := labels[lname].boards - if l := len(thisLabel); l > 1 { - brds := make([]string, 0, l) - for bname := range thisLabel { - brds = append(brds, bname) - } - sort.Strings(brds) - lbrds := []trelloBoard{} - for _, h := range brds { - lbrds = append(lbrds, labels[lname].boards[h]) - } - render.SharedLabels = append(render.SharedLabels, trelloSharedLabel{ - Name: lname, Color: labels[lname].color, Boards: lbrds, - }) - } - } - - //post-process member stats - mNames := make([]string, 0, len(memberBoardCount)) - for mID := range memberBoardCount { - memInfo := fetchMember(config, render, mID) - mNames = append(mNames, memInfo.FullName) - } - sort.Strings(mNames) - for _, mNam := range mNames { - for mem, brdCounts := range memberBoardCount { - memInfo := fetchMember(config, render, mem) - if mNam == memInfo.FullName { - render.MemberBoardAssign = append(render.MemberBoardAssign, trelloBoardAssign{MemberName: mNam, AvatarHash: memInfo.AvatarHash}) - for _, b := range render.Boards { // these are already in order - if count, ok := brdCounts[b.Board.ID]; ok { - render.MemberBoardAssign[len(render.MemberBoardAssign)-1].AssignCounts = - append(render.MemberBoardAssign[len(render.MemberBoardAssign)-1].AssignCounts, - trelloBoardAssignCount{BoardName: b.Board.Name, Count: count}) - } - } - goto found - } - } - found: - } -}