798 lines
20 KiB
Smalltalk
798 lines
20 KiB
Smalltalk
Smalltalk current createPackage: 'Hubboard' properties: #{}!
|
|
Widget subclass: #HBDialog
|
|
instanceVariableNames: 'modal minWidth draggable elementId position maxHeight'
|
|
category: 'Hubboard'!
|
|
|
|
!HBDialog methodsFor: 'accessors'!
|
|
|
|
elementId
|
|
^ ('#', elementId).
|
|
!
|
|
|
|
asJQuery
|
|
^ self elementId asJQuery.
|
|
! !
|
|
|
|
!HBDialog methodsFor: 'dialog-helpers'!
|
|
|
|
becomeDialog
|
|
^ self becomeDialog: [].
|
|
!
|
|
|
|
becomeDialog: aBlockCallback
|
|
self asJQuery dialog: #{
|
|
'modal' -> modal.
|
|
'minWidth' -> minWidth.
|
|
'maxHeight' -> maxHeight.
|
|
'draggable' -> draggable.
|
|
'position' -> position.
|
|
'close' -> [ :event :ui |
|
|
self asJQuery remove.
|
|
]}.
|
|
aBlockCallback value.
|
|
! !
|
|
|
|
!HBDialog methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
super initialize.
|
|
modal := true.
|
|
minWidth := 500.
|
|
maxHeight := 500.
|
|
draggable := false.
|
|
position := 'center'.
|
|
! !
|
|
|
|
!HBDialog class methodsFor: 'not yet classified'!
|
|
|
|
show
|
|
" Creates and adds the DOM elements to the body tag "
|
|
| dialog |
|
|
dialog := super new.
|
|
dialog appendToJQuery: ('body' asJQuery).
|
|
! !
|
|
|
|
Object subclass: #HubboardApp
|
|
instanceVariableNames: 'token issueMap issueApi userApi knownRepos userData refreshIntervalId currentProject refreshInterval sortedRepos assignedProjects alphasortedRepos'
|
|
category: 'Hubboard'!
|
|
|
|
!HubboardApp methodsFor: 'accessors'!
|
|
|
|
inProgress: arrayOfLabels
|
|
"Return true if we find the 'in-progress' label"
|
|
arrayOfLabels ifNil: [ ^ false ].
|
|
|
|
arrayOfLabels do: [ :label |
|
|
(label at: 'name') = 'in-progress' ifTrue: [ ^ true ].
|
|
].
|
|
^ false.
|
|
!
|
|
|
|
knownRepos
|
|
^ knownRepos.
|
|
!
|
|
|
|
issueMap
|
|
^ issueMap.
|
|
!
|
|
|
|
user
|
|
^ userData.
|
|
!
|
|
|
|
currentProject
|
|
^ currentProject.
|
|
!
|
|
|
|
sortedRepos
|
|
" Return an Array of repos (owner/reponame) sorted by the most recently updated "
|
|
^ sortedRepos ifNil: [
|
|
| names |
|
|
names := knownRepos keys.
|
|
sortedRepos := names sort: [ :left :right |
|
|
((knownRepos at: left) at: 'updated_at') > ((knownRepos at: right) at: 'updated_at')
|
|
].
|
|
].
|
|
!
|
|
|
|
setKnownRepos: newKnownRepos
|
|
" Ideally, this method should not really be used outside of test cases "
|
|
knownRepos := newKnownRepos.
|
|
!
|
|
|
|
assignedProjects
|
|
^ assignedProjects.
|
|
!
|
|
|
|
issueApi
|
|
^ issueApi.
|
|
!
|
|
|
|
alphasortedRepos
|
|
" Return an Array of repos (owner/reponame) sorted by the most recently updated "
|
|
^ alphasortedRepos ifNil: [
|
|
| names |
|
|
names := knownRepos keys.
|
|
alphasortedRepos := names sort: [ :left :right |
|
|
((knownRepos at: left) at: 'name') asLowercase < ((knownRepos at: right) at: 'name') asLowercase
|
|
].
|
|
].
|
|
! !
|
|
|
|
!HubboardApp methodsFor: 'actions'!
|
|
|
|
handleDrop: theEvent with: aWidget
|
|
" This function should handle the initial drop of one IssueTile onto a new column "
|
|
| tile currentParent newParent issueId |
|
|
issueId := ((aWidget draggable at: 0) at: 'id').
|
|
tile := issueMap at: (((issueId split: 'issuetile_') at: 2) asNumber).
|
|
"jQuery is going to give this to us in an array, how annoying"
|
|
currentParent := (tile asJQuery parent at: 0) at: 'id'.
|
|
newParent := theEvent target at: 'id'.
|
|
|
|
tile asJQuery css: 'position' is:'static'.
|
|
|
|
"We will receive drag events onto the same column, don't do anything in that case"
|
|
currentParent = newParent ifTrue: [ ^ true ].
|
|
('#', newParent) asJQuery append: (tile asJQuery detach).
|
|
|
|
tile moveTo: newParent.
|
|
!
|
|
|
|
refresh
|
|
self flushColumns.
|
|
issueApi issues: [ :issue |
|
|
| tile issueId |
|
|
issueId := issue issueId.
|
|
tile := issueMap at: issueId ifAbsent: [ IssueTile new ].
|
|
tile withModel: issue.
|
|
assignedProjects add: (issue projectName).
|
|
issueMap at: issueId put: tile.
|
|
(self inProgress: (issue labels))
|
|
ifFalse: [ tile setOpen. tile appendToJQuery: ('#openissues' asJQuery) ]
|
|
ifTrue: [ tile setInProgress. tile appendToJQuery: ('#inprogressissues' asJQuery) ].
|
|
currentProject ifNotNil: [
|
|
currentProject = (issue projectName) ifFalse: [tile asJQuery hide].
|
|
].
|
|
self updateFilter.
|
|
] finally: [ self hideSpinner ].
|
|
|
|
issueApi recentlyClosed: [ :issue |
|
|
| tile issueId |
|
|
issueId := issue issueId.
|
|
tile := issueMap at: issueId ifAbsent: [ IssueTile new ].
|
|
tile withModel: issue.
|
|
tile setClosed.
|
|
tile appendToJQuery: ('#closedissues' asJQuery).
|
|
currentProject ifNotNil: [
|
|
currentProject = (issue projectName) ifFalse: [tile asJQuery hide].
|
|
]
|
|
] loadAll: false.
|
|
!
|
|
|
|
updateFilter
|
|
| element |
|
|
" If we have a currently selected project, no sense in running the rest of this code "
|
|
currentProject ifNotNil: [ ^ true ].
|
|
|
|
element := '.projectselect' asJQuery.
|
|
element change: [ :event |
|
|
| project |
|
|
project := element val.
|
|
project = 'All'
|
|
ifTrue: [ self showAll ]
|
|
ifFalse: [ self showOnly: project ].
|
|
].
|
|
element empty.
|
|
|
|
[ :html | html option value: 'All'; with: 'View All Projects' ] appendToJQuery: element.
|
|
self issueMap values do: [ :issue | assignedProjects add: (issue model projectName) ].
|
|
assignedProjects do: [ :project |
|
|
[ :html | html option value: project; with: project ] appendToJQuery: element.
|
|
].
|
|
!
|
|
|
|
startRefreshTimer
|
|
refreshIntervalId ifNil: [
|
|
refreshIntervalId := window setInterval: [ self refresh ] every: refreshInterval.
|
|
].
|
|
!
|
|
|
|
stopRefreshTimer
|
|
refreshIntervalId ifNotNil: [
|
|
window clearInterval: refreshIntervalId.
|
|
refreshIntervalId := nil.
|
|
].
|
|
! !
|
|
|
|
!HubboardApp methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
token := window at: 'github_access_token'.
|
|
issueMap := Dictionary new.
|
|
knownRepos := Dictionary new.
|
|
assignedProjects := Set new.
|
|
refreshInterval := 300000.
|
|
!
|
|
|
|
bootstrap
|
|
issueApi := Issues new setToken: token.
|
|
userApi := Users new setToken: token.
|
|
self showSpinner.
|
|
userApi fetchCurrent: [ :data |
|
|
| allRepos |
|
|
allRepos := Array new.
|
|
userData := data.
|
|
'#logout-username' asJQuery text: ('(', (data at: 'login'), ')').
|
|
" Once we have information about the user, let's fire up our repo backfill "
|
|
Repo fetchReposForToken: token withEachDo: [ :result | (result at: 'has_issues') ifTrue: [ allRepos add: result ] ]
|
|
finally: [
|
|
allRepos do: [ :item |
|
|
| owner |
|
|
owner := ((item at: 'owner') at: 'login').
|
|
knownRepos at: (owner, '/', (item at: 'name')) put: item.
|
|
].
|
|
':input[name=create_issue]' asJQuery removeAttr: 'disabled'.
|
|
self sortedRepos. "Pre-sort our repos just to make things easier on the user"
|
|
].
|
|
].
|
|
self refresh.
|
|
self startRefreshTimer.
|
|
'.issuecolumn' asJQuery droppable: #{
|
|
'tolerance' -> 'pointer'.
|
|
'accept' -> '.issuetile'.
|
|
'drop' -> [ :event :ui | self handleDrop: event with: ui]}.
|
|
! !
|
|
|
|
!HubboardApp methodsFor: 'ui'!
|
|
|
|
showAll
|
|
"Make sure all issue tiles are visible"
|
|
currentProject := nil.
|
|
'.issuetile' asJQuery show.
|
|
!
|
|
|
|
showOnly: aProjectName
|
|
"Only show tiles with data-project=aProjectName"
|
|
currentProject := aProjectName.
|
|
'.issuetile' asJQuery hide.
|
|
('.issuetile[data-project="', aProjectName, '"]') asJQuery show.
|
|
!
|
|
|
|
flushColumns
|
|
| clearBlock |
|
|
clearBlock := [ :index :element |
|
|
| item |
|
|
item := window jQuery: element.
|
|
item draggable: 'destroy'.
|
|
item remove removeData.
|
|
].
|
|
'#openissues > *' asJQuery each: clearBlock.
|
|
'#inprogressissues > *' asJQuery each: clearBlock.
|
|
'#closedissues > *' asJQuery each: clearBlock.
|
|
!
|
|
|
|
showSpinner
|
|
'#spinner' asJQuery show.
|
|
!
|
|
|
|
hideSpinner
|
|
'#spinner' asJQuery hide.
|
|
! !
|
|
|
|
HubboardApp class instanceVariableNames: 'current'!
|
|
|
|
!HubboardApp class methodsFor: 'not yet classified'!
|
|
|
|
current
|
|
^ current ifNil: [ current := super new ].
|
|
! !
|
|
|
|
Widget subclass: #IssueTile
|
|
instanceVariableNames: 'raw title body issueId number project projectOwner issueStatus comments fullProjectName elementId model'
|
|
category: 'Hubboard'!
|
|
|
|
!IssueTile methodsFor: 'accessors'!
|
|
|
|
elementId
|
|
^ elementId ifNil: [ elementId := 'issuetile_', (model issueId asString) ].
|
|
!
|
|
|
|
model
|
|
^ model.
|
|
!
|
|
|
|
asJQuery
|
|
^ ('#', self elementId) asJQuery.
|
|
! !
|
|
|
|
!IssueTile methodsFor: 'actions'!
|
|
|
|
setOpen
|
|
"Set this issue as an open issue"
|
|
issueStatus := #open.
|
|
!
|
|
|
|
setInProgress
|
|
"Set this issue as an inprogress issue"
|
|
issueStatus := #inprogress.
|
|
!
|
|
|
|
setClosed
|
|
"Set this issue as a closed issue, should not be draggable as a result"
|
|
issueStatus := #closed.
|
|
self asJQuery draggable: 'disable'.
|
|
!
|
|
|
|
viewIssue: onClickEvent
|
|
| dialog |
|
|
dialog := IssueDetailDialog new withIssue: model.
|
|
dialog appendToJQuery: 'body' asJQuery.
|
|
! !
|
|
|
|
!IssueTile methodsFor: 'initializers'!
|
|
|
|
withModel: anIssue
|
|
model := anIssue.
|
|
number := anIssue number.
|
|
! !
|
|
|
|
!IssueTile methodsFor: 'not yet classified'!
|
|
|
|
parseUrl: aUrl
|
|
"Return a Hash with the 'owner' and 'project' based on the given Issue URL"
|
|
| parts |
|
|
parts := <aUrl.split('/')>.
|
|
|
|
^ #{'owner' -> (parts at: 4).
|
|
'project' -> (parts at: 5)}.
|
|
!
|
|
|
|
moveTo: aColumnId
|
|
"Handle the invocation of the right callbacks when we move from one column to another
|
|
The lines blur a bit here on 'view' versus 'controller'"
|
|
| postData successBlock url |
|
|
postData := #{'project' -> model projectName }.
|
|
|
|
|
|
aColumnId = 'inprogressissues' ifTrue: [
|
|
url := '/issues/', number, '/label'.
|
|
successBlock := [ self setInProgress. ].
|
|
].
|
|
aColumnId = 'openissues' ifTrue: [
|
|
url := '/issues/', number, '/revert'.
|
|
successBlock := [ self setOpen ]
|
|
].
|
|
aColumnId = 'closedissues' ifTrue: [
|
|
url := '/issues/', number, '/close'.
|
|
successBlock := [ self setClosed ].
|
|
].
|
|
|
|
url ifNotNil: [
|
|
HubboardApp current showSpinner.
|
|
jQuery ajax: url
|
|
options: #{
|
|
'type' -> 'POST'.
|
|
'dataType' -> 'json'.
|
|
'data' -> postData asJSONString.
|
|
'success' -> [
|
|
successBlock ifNotNil: [ successBlock value ].
|
|
self updateHeaderClass.
|
|
HubboardApp current hideSpinner.
|
|
].
|
|
'error' -> [ HubboardApp current hideSpinner. console log: 'fail']
|
|
}.
|
|
^ true.
|
|
].
|
|
^ false.
|
|
! !
|
|
|
|
!IssueTile methodsFor: 'rendering'!
|
|
|
|
renderOn: html
|
|
html div
|
|
class: 'issuetile';
|
|
id: self elementId;
|
|
at: 'data-project' put: (model projectName);
|
|
at: 'data-issueid' put: (model issueId);
|
|
with: [
|
|
self renderHeader: html.
|
|
html div class: 'title'; with: (model title).
|
|
html div class: 'labels'; with: [ self renderLabels: html ]
|
|
].
|
|
self postRender.
|
|
!
|
|
|
|
numberClass
|
|
| numberClass |
|
|
numberClass := 'number'.
|
|
issueStatus = #open ifTrue: [ numberClass := numberClass, ' open' ].
|
|
issueStatus = #inprogress ifTrue: [ numberClass := numberClass, ' inprogress' ].
|
|
issueStatus = #closed ifTrue: [ numberClass := numberClass, ' closed'].
|
|
^ numberClass.
|
|
!
|
|
|
|
postRender
|
|
"Run actions after we've rendered the DOM elements "
|
|
|
|
"Make the tile draggable"
|
|
issueStatus = #closed ifFalse: [ self asJQuery draggable: #{'zIndex' -> '10000'. 'snap' -> true }].
|
|
|
|
"Make ourselves double-clickable"
|
|
self asJQuery dblclick: [ :event | self viewIssue: event ].
|
|
!
|
|
|
|
updateHeaderClass
|
|
|element |
|
|
element := ('#', self elementId, ' > div.number') asJQuery.
|
|
element removeClass.
|
|
element addClass: (self numberClass).
|
|
!
|
|
|
|
addComment: clickEvent
|
|
| dialog |
|
|
dialog := CommentDialog new withIssue: model.
|
|
dialog appendToJQuery: 'body' asJQuery.
|
|
!
|
|
|
|
renderHeader: html
|
|
html div
|
|
class: self numberClass;
|
|
with: [
|
|
html a href: (model url); target: '_blank'; with: ('#', (model number) asString); onClick: [ :event | self viewIssue: event. event preventDefault ].
|
|
html with: ' in '.
|
|
html a href: ('https://github.com/', (model projectOwner)); target: '_blank'; with: (model projectOwner).
|
|
html with: ' / '.
|
|
html a href: ('https://github.com/', (model projectName)); target: '_blank'; with: (model project).
|
|
html div
|
|
style: 'float:right;';
|
|
class: 'comments';
|
|
with: [
|
|
model pullRequest ifNotNil: [
|
|
html span
|
|
class: 'pull_req';
|
|
with: [
|
|
html a target: '_blank'; href: (model pullRequest); with: [ html img src: '/images/pull_request.png' ].
|
|
html with: 'Code Attached'.
|
|
].
|
|
].
|
|
html span with: (model comments asString, ' comments').
|
|
html button
|
|
class: 'add_comment';
|
|
title: 'Add Comment';
|
|
with: '+';
|
|
onClick: [ :event | self addComment: event ].
|
|
].
|
|
].
|
|
!
|
|
|
|
renderLabels: html
|
|
" Render any labels other than our own 'in-progress' label"
|
|
| rendered |
|
|
rendered := false.
|
|
(model labels size) = 0 ifTrue: [ ^ false ].
|
|
|
|
model labels do: [ :label |
|
|
| labelName |
|
|
labelName := label at: 'name'.
|
|
labelName = 'in-progress' ifFalse: [
|
|
rendered := true.
|
|
html li with: [
|
|
html span
|
|
style: 'background-color: #', (label at: 'color');
|
|
with: labelName
|
|
].
|
|
].
|
|
].
|
|
rendered ifTrue: [ html br at: 'clear' put: 'left' ].
|
|
! !
|
|
|
|
HBDialog subclass: #NewIssueDialog
|
|
instanceVariableNames: ''
|
|
category: 'Hubboard'!
|
|
|
|
!NewIssueDialog methodsFor: 'actions'!
|
|
|
|
submit
|
|
"Take the values out of the form and actually submit them"
|
|
| data |
|
|
data := #{
|
|
'title' -> ':input[name=title]' asJQuery val.
|
|
'assignee' -> ':input[name=assignee]' asJQuery val.
|
|
'project' -> ':input[name=project]' asJQuery val.
|
|
'body' -> ':input[name=body]' asJQuery val
|
|
}.
|
|
|
|
((data at: 'title') size) = 0 ifTrue: [ window alert: 'You should probably add a title'. ^ false ].
|
|
|
|
jQuery ajax: '/issues/create' options: #{'type' -> 'POST'.
|
|
'dataType' -> 'json'.
|
|
'contentType' -> 'text/json'.
|
|
'data' -> data asJSONString.
|
|
'success' -> [ self asJQuery dialog: 'close'. HubboardApp current refresh.]}.
|
|
! !
|
|
|
|
!NewIssueDialog methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
super initialize.
|
|
minWidth := 450.
|
|
elementId := 'new_issue'.
|
|
! !
|
|
|
|
!NewIssueDialog methodsFor: 'rendering'!
|
|
|
|
renderOn: html
|
|
| currentUser |
|
|
currentUser := HubboardApp current user at: 'login'.
|
|
|
|
html div
|
|
at: 'title' put: 'Create a new issue';
|
|
id: elementId;
|
|
with: [
|
|
html form name: 'new_issue_form'; onSubmit: [ :event | self submit. event preventDefault ]; with: [
|
|
html label for: 'assignee'; with: 'Assign to: '.
|
|
html select name: 'assignee';
|
|
with: [ html option value: currentUser; with: currentUser. ].
|
|
html br.
|
|
html label for: 'project'; with: 'Project: '.
|
|
html select
|
|
name: 'project';
|
|
onChange: [ :event | self updateCollaborators ];
|
|
with: [
|
|
HubboardApp current alphasortedRepos do: [ :repo |
|
|
(HubboardApp current currentProject) = repo
|
|
ifTrue: [ html option value: repo; with: repo; at: 'selected' put: 'true' ]
|
|
ifFalse: [html option value: repo; with: repo ].
|
|
]
|
|
].
|
|
html br.
|
|
html label for: 'title'; with: 'Title: '.
|
|
html input name: 'title'; at: 'size' put: '40'.
|
|
html br.
|
|
html a with: 'Add body'; class: 'dialog-add-body'; onClick: [ '#dialog-body' asJQuery show ].
|
|
html br.
|
|
html div
|
|
id: 'dialog-body';
|
|
style: 'display: none;';
|
|
with: [
|
|
html with: (MarkdownTextArea new setName: 'body'; setColumns: 40; setRows: 8).
|
|
html br.
|
|
].
|
|
html button style: 'float: right;'; type: 'submit'; with: 'Create'.
|
|
]
|
|
].
|
|
|
|
self becomeDialog: [ ':input[name=title]' asJQuery focus ].
|
|
!
|
|
|
|
updateCollaborators
|
|
" Update the <select/> with collaborators from the API"
|
|
| project assignee |
|
|
project := ':input[name=project]' asJQuery val.
|
|
assignee := ':input[name=assignee]' asJQuery.
|
|
|
|
project ifNil: [ ^ false ].
|
|
|
|
Repo collaboratorsFor: project with: [ :results |
|
|
| currentUser |
|
|
currentUser := HubboardApp current user at: 'login'.
|
|
assignee empty.
|
|
[ :html |
|
|
results do: [ :result |
|
|
| userName |
|
|
userName := result at: 'login'.
|
|
html option value: userName; with: userName.
|
|
].
|
|
] appendToJQuery: assignee.
|
|
" Select ourselves after we update the list "
|
|
assignee val: currentUser.
|
|
].
|
|
! !
|
|
|
|
HBDialog subclass: #IssueDetailDialog
|
|
instanceVariableNames: 'model'
|
|
category: 'Hubboard'!
|
|
|
|
!IssueDetailDialog methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
super initialize.
|
|
minWidth := 650.
|
|
elementId := 'issue_detail'.
|
|
model := nil.
|
|
draggable := true.
|
|
position := 'top'.
|
|
!
|
|
|
|
withIssue: anIssue
|
|
model := anIssue.
|
|
^ self.
|
|
! !
|
|
|
|
!IssueDetailDialog methodsFor: 'rendering'!
|
|
|
|
renderOn: html
|
|
html div
|
|
at: 'title' put: '#', (model number), ' - ', (model title);
|
|
id: elementId;
|
|
with: [
|
|
| body |
|
|
body := model body.
|
|
(body size) = 0
|
|
ifTrue: [ body := 'No description given'.]
|
|
ifFalse: [ body := Markdown asTagBrush: (model body asString) ].
|
|
html div style: 'max-height: 400px; overflow: auto;'; with: body.
|
|
html div
|
|
id: 'comments_container';
|
|
style: 'display: none;';
|
|
with: [
|
|
html hr.
|
|
html strong with: 'Comments:'.
|
|
html hr.
|
|
html div id: 'comments'; style: 'overflow: auto; max-height: 300px'.
|
|
].
|
|
html div
|
|
style: 'float: right;';
|
|
with: [ html a href: (model url); target: '_blank'; with: 'View on GitHub'].
|
|
html div
|
|
style: 'float: right; margin-right: 10px;';
|
|
with: [ html a href: '#'; id: 'dialog_add_comment'; with: 'Add Comment'; onClick: [
|
|
| dialog |
|
|
dialog := CommentDialog new withIssue: model; finally: [ self loadComments ].
|
|
dialog appendToJQuery: 'body' asJQuery.
|
|
]].
|
|
].
|
|
|
|
self becomeDialog: [ '#dialog_add_comment' asJQuery focus ].
|
|
self loadComments.
|
|
!
|
|
|
|
renderComment: comment onto: html
|
|
|
|
html div
|
|
class: 'comment_detail';
|
|
with: [
|
|
html strong with: 'By: ', (comment login).
|
|
html with: (Markdown asTagBrush: (comment body)).
|
|
].
|
|
|
|
html hr.
|
|
|
|
'#comments_container' asJQuery show.
|
|
!
|
|
|
|
loadComments
|
|
" Empty out the comments container and dump some fresh comments into there "
|
|
| container |
|
|
container := '#comments' asJQuery.
|
|
container empty.
|
|
|
|
model loadComments: [ :comments |
|
|
comments reversed do: [ :comment |
|
|
[ :html | self renderComment: comment onto: html ] appendToJQuery: container
|
|
]
|
|
].
|
|
! !
|
|
|
|
HBDialog subclass: #CommentDialog
|
|
instanceVariableNames: 'model closingBlock'
|
|
category: 'Hubboard'!
|
|
|
|
!CommentDialog methodsFor: 'actions'!
|
|
|
|
submit
|
|
"Take the values out of the form and actually submit them"
|
|
| data |
|
|
data := #{
|
|
'project' -> model projectName.
|
|
'body' -> ':input[name=body]' asJQuery val
|
|
}.
|
|
|
|
((data at: 'body') size) = 0 ifTrue: [ window alert: 'You should probably add a comment'. ^ false ].
|
|
|
|
jQuery ajax: '/issues/', (model number), '/comment' options: #{'type' -> 'POST'.
|
|
'dataType' -> 'json'.
|
|
'contentType' -> 'text/json'.
|
|
'data' -> data asJSONString.
|
|
'success' -> [
|
|
self asJQuery dialog: 'close'. HubboardApp current refresh.
|
|
closingBlock ifNotNil: [ closingBlock value ].
|
|
]}.
|
|
!
|
|
|
|
finally: aClosingBlock
|
|
closingBlock := aClosingBlock.
|
|
! !
|
|
|
|
!CommentDialog methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
super initialize.
|
|
minWidth := 450.
|
|
elementId := 'new_comment'.
|
|
!
|
|
|
|
withIssue: anIssue
|
|
model := anIssue.
|
|
! !
|
|
|
|
!CommentDialog methodsFor: 'rendering'!
|
|
|
|
renderOn: html
|
|
html div
|
|
at: 'title' put: 'Add a comment to issue #', (model number);
|
|
id: elementId;
|
|
with: [
|
|
html form name: 'new_comment_form'; onSubmit: [ :event | self submit. event preventDefault ]; with: [
|
|
html input type: 'hidden'; name: 'number'; value: (model number).
|
|
html div
|
|
id: 'dialog-body';
|
|
with: [
|
|
html with: (MarkdownTextArea new setName: 'body'; setColumns: 45; setRows: 8).
|
|
html br.
|
|
].
|
|
html button style: 'float: right;'; type: 'submit'; with: 'Add Comment'.
|
|
]
|
|
].
|
|
|
|
self becomeDialog: [ ':input[name=body]' asJQuery focus ].
|
|
! !
|
|
|
|
HBDialog subclass: #AboutDialog
|
|
instanceVariableNames: ''
|
|
category: 'Hubboard'!
|
|
|
|
!AboutDialog methodsFor: 'initializers'!
|
|
|
|
initialize
|
|
super initialize.
|
|
modal := true.
|
|
elementId := 'about_dialog'.
|
|
! !
|
|
|
|
!AboutDialog methodsFor: 'rendering'!
|
|
|
|
renderOn: html
|
|
html div
|
|
id: elementId;
|
|
with: [
|
|
html img src: '/images/logo.png'.
|
|
html p with: 'Hub board is a fairly straight-foward kan ban board, built on top of the GitHub v3 API . '.
|
|
html p with: 'The goal of Hub board is to help you rapidly interact with issues assigned to you in the various repositories you may work with.'.
|
|
].
|
|
|
|
self becomeDialog.
|
|
! !
|
|
|
|
HBDialog subclass: #IssueNavigatorDialog
|
|
instanceVariableNames: ''
|
|
category: 'Hubboard'!
|
|
|
|
!IssueNavigatorDialog methodsFor: 'not yet classified'!
|
|
|
|
initialize
|
|
super initialize.
|
|
minWidth := 500.
|
|
elementId := 'issue_navigator'.
|
|
!
|
|
|
|
renderOn: html
|
|
html div
|
|
id: elementId;
|
|
at: 'title' put: 'Find Issues';
|
|
with: [
|
|
html with: 'hello'.
|
|
].
|
|
|
|
self becomeDialog.
|
|
! !
|
|
|
|
!String methodsFor: '*Hubboard'!
|
|
|
|
split: aDelimiter
|
|
"Split the string based on the delimiter into an Array of sub-strings"
|
|
^ <self.split(aDelimiter);>.
|
|
! !
|
|
|