13 Commits

Author SHA1 Message Date
Aaron Gutierrez
55970ab144 more WIP 2015-08-17 20:54:33 -07:00
Aaron Gutierrez
65bd30d026 Merge branch 'master' into subtask 2015-08-17 20:43:05 -07:00
Aaron Gutierrez
6243a9bb68 color project icons 2015-08-17 20:40:08 -07:00
Aaron Gutierrez
3a5837ae5d Enter opens parent task details. Fixes #45840013545374 2015-08-17 20:30:16 -07:00
Aaron Gutierrez
dac83e00a1 WIP subtasks 2015-08-17 20:17:53 -07:00
86e1d830de fix style problem if task name is empty 2015-08-07 12:33:43 -07:00
0fff014307 Show subtasks in details view 2015-08-06 23:16:42 -07:00
6664d299b9 Special case assignee typeahead in personal projects 2015-08-06 22:30:09 -07:00
7f76ebd441 Change project opening to be right, not left 2015-08-06 22:16:36 -07:00
5d176075a7 Details pane can scroll now. Fixes #44621775554616 2015-08-06 22:11:35 -07:00
e18c923202 Redraw screen after adding task 2015-08-06 22:11:04 -07:00
6ba98525d5 exclude tags file 2015-08-06 21:25:58 -07:00
3894b81ebc improved login prompt 2015-08-06 21:25:49 -07:00
3 changed files with 107 additions and 33 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,8 @@
*.swp *.swp
*.pyc *.pyc
tags
.state .state
.oauth .oauth
secrets.py secrets.py

View File

@@ -58,12 +58,13 @@ class CmdAsana:
}, },
) )
(url, state) = self.client.session.authorization_url() (url, state) = self.client.session.authorization_url()
print("Go to the following link and enter the code:")
print(url)
try: try:
import webbrowser import webbrowser
webbrowser.open(url) webbrowser.open(url)
except Exception: except Exception:
print("Go to the following link and enter the code:") pass
print(url)
code = sys.stdin.readline().strip() code = sys.stdin.readline().strip()
token = self.client.session.fetch_token(code=code) token = self.client.session.fetch_token(code=code)
@@ -134,6 +135,7 @@ class CmdAsana:
def update(task): def update(task):
task_list,_ = self.frame.contents[1] task_list,_ = self.frame.contents[1]
task_list.insertNewTask(task) task_list.insertNewTask(task)
self.loop.draw_screen()
thread = Thread(target=runInThread) thread = Thread(target=runInThread)
thread.start() thread.start()
@@ -169,12 +171,17 @@ class CmdAsana:
def userTypeAhead(self, text, callback): def userTypeAhead(self, text, callback):
def runInThread(): def runInThread():
users = self.client.workspaces.typeahead(self.state['workspace_id'], if self.state['workspace_id'] != PERSONAL:
{ users = self.client.workspaces \
'type': 'user', .typeahead(self.state['workspace_id'],
'query': text, {
'count': 5 'type': 'user',
}) 'query': text,
'count': 5
})
else:
users = [self.me]
callback(users) callback(users)
self.loop.draw_screen() self.loop.draw_screen()
@@ -263,10 +270,11 @@ class CmdAsana:
def runInThread(): def runInThread():
task = self.client.tasks.find_by_id(task_id) task = self.client.tasks.find_by_id(task_id)
stories = self.client.stories.find_by_task(task_id) stories = self.client.stories.find_by_task(task_id)
update(task, stories) subtasks = self.client.tasks.subtasks(task_id)
update(task, stories, subtasks)
def update(task, stories): def update(task, stories, subtasks):
task_details = ui.TaskDetails(task, stories) task_details = ui.TaskDetails(task, stories, subtasks)
self.connectDetailsSignals(task_details) self.connectDetailsSignals(task_details)
self.replaceBody(task_details) self.replaceBody(task_details)
@@ -294,6 +302,9 @@ class CmdAsana:
'updatetask', 'updatetask',
'usertypeahead', 'usertypeahead',
'assigntask', 'assigntask',
'complete',
'newtask',
'details',
]) ])
urwid.register_signal(ui.AssigneeTypeAhead, [ urwid.register_signal(ui.AssigneeTypeAhead, [
@@ -332,6 +343,9 @@ class CmdAsana:
urwid.connect_signal(task_details, 'updatetask', self.updateTask) urwid.connect_signal(task_details, 'updatetask', self.updateTask)
urwid.connect_signal(task_details, 'usertypeahead', self.userTypeAhead) urwid.connect_signal(task_details, 'usertypeahead', self.userTypeAhead)
urwid.connect_signal(task_details, 'assigntask', self.assignTask) urwid.connect_signal(task_details, 'assigntask', self.assignTask)
urwid.connect_signal(task_details, 'complete', self.completeTask)
urwid.connect_signal(task_details, 'newtask', self.newTask)
urwid.connect_signal(task_details, 'details', self.showDetails)
def handleInput(self, key): def handleInput(self, key):
if key in ('q', 'Q'): if key in ('q', 'Q'):

102
ui.py
View File

@@ -12,6 +12,7 @@ palette = [
('header', 'bold,light green', ''), ('header', 'bold,light green', ''),
('secondary', 'light gray', ''), ('secondary', 'light gray', ''),
('task', 'light green', ''), ('task', 'light green', ''),
('project', 'yellow', ''),
('section', 'white', 'dark green'), ('section', 'white', 'dark green'),
('workspace', 'white', 'dark blue'), ('workspace', 'white', 'dark blue'),
('pager', 'standout', ''), ('pager', 'standout', ''),
@@ -61,7 +62,7 @@ class ProjectIcon(urwid.SelectableIcon):
super(ProjectIcon, self).__init__(project['name']) super(ProjectIcon, self).__init__(project['name'])
def keypress(self, size, key): def keypress(self, size, key):
if key in ('enter', 'left', 'l'): if key in ('enter', 'right', 'l'):
self.onClick(self.project['id']) self.onClick(self.project['id'])
else: else:
return super(ProjectIcon, self).keypress(size, key) return super(ProjectIcon, self).keypress(size, key)
@@ -71,8 +72,8 @@ class ProjectList(urwid.ListBox):
self.projects = projects self.projects = projects
body = urwid.SimpleFocusListWalker( body = urwid.SimpleFocusListWalker(
[ProjectIcon({'name': 'My Tasks', 'id': None}, [urwid.AttrMap(ProjectIcon({'name': 'My Tasks', 'id': None},
self.loadProject), self.loadProject), 'project'),
None] None]
) )
super(ProjectList, self).__init__(body) super(ProjectList, self).__init__(body)
@@ -82,8 +83,8 @@ class ProjectList(urwid.ListBox):
self.body.pop() self.body.pop()
for i in range(50): for i in range(50):
try: try:
self.body.append(ProjectIcon(self.projects.next(), self.body.append(urwid.AttrMap(ProjectIcon(self.projects.next(),
self.loadProject)) self.loadProject), 'project'))
except StopIteration: except StopIteration:
return return
@@ -112,7 +113,8 @@ class TaskList(urwid.ListBox):
body = urwid.SimpleFocusListWalker([]) body = urwid.SimpleFocusListWalker([])
for task_widget,_ in task_widgets.contents: for task_widget,_ in task_widgets.contents:
self.connectSignals(task_widget) self.connectSignals(task_widget)
style = 'section' if task_widget.task['name'][-1] == ':' else 'task' style = 'section' if len(task_widget.task['name']) and \
task_widget.task['name'][-1] == ':' else 'task'
body.append(urwid.AttrMap(task_widget, style, focus_map='selected')) body.append(urwid.AttrMap(task_widget, style, focus_map='selected'))
super(TaskList, self).__init__(body) super(TaskList, self).__init__(body)
@@ -264,8 +266,37 @@ class AssigneeTypeAhead(urwid.Pile):
self.contents = [self.contents[0]] self.contents = [self.contents[0]]
self.edit.set_edit_text(user['name']) self.edit.set_edit_text(user['name'])
class TaskDetails(urwid.Pile): class ProjectTypeAhead(urwid.Pile):
def __init__(self, task, stories): def __init__(self, task):
body = [('pack', urwid.AttrMap(ProjectIcon(project, self.loadProject),
'project'))
for project in task['projects']]
self.edit = urwid.Edit('Add Project: ')
urwid.connect_signal(self.edit, 'change', self.typeAhead)
body.append(('pack', self.edit))
super(ProjecTypeAhead).__init__(body)
def typeAhead(self, widget, text):
urwid.emit_signal(self, 'projecttypeahead', text, self.updateTypeAhead)
def updateTypeAhead(self, projects):
projects = [(TypeAheadButton(p, self.add), ('pack', None))
for p in projects]
body = [('pack', urwid.AttrMap(ProjectIcon(project, self.loadProject),
'project'))
for project in self.task['projects']]
body.append(('pack', self.edit))
self.contents = body + projects
class TaskDetails(urwid.ListBox):
def __init__(self, task, stories, subtasks):
self.task = task self.task = task
self.stories = stories self.stories = stories
@@ -283,27 +314,54 @@ class TaskDetails(urwid.Pile):
urwid.connect_signal(assignee_type_ahead, 'usertypeahead', urwid.connect_signal(assignee_type_ahead, 'usertypeahead',
self.userTypeAhead) self.userTypeAhead)
urwid.connect_signal(assignee_type_ahead, 'assigntask', self.assignTask) urwid.connect_signal(assignee_type_ahead, 'assigntask', self.assignTask)
containers = []
projects = [('pack', ProjectIcon(project, self.loadProject)) if task['parent'] != None:
for project in task['projects']] parent = TaskEdit(task['parent'])
urwid.connect_signal(parent, 'updatetask', self.updateSubtask)
urwid.connect_signal(parent, 'details', self.showDetails)
body = projects + \ #Remap enter to load details of parent
urwid.connect_signal(parent, 'newtask', self.showDetails)
containers.append(parent)
all_subtasks = [t for t in subtasks]
subtask_list = TaskList(all_subtasks)
urwid.connect_signal(subtask_list, 'complete', self.completeTask)
urwid.connect_signal(subtask_list, 'newtask', self.newTask)
urwid.connect_signal(subtask_list, 'updatetask', self.updateSubtask)
urwid.connect_signal(subtask_list, 'details', self.showDetails)
body = containers + \
[ [
('pack', urwid.Divider('=')), urwid.Divider('='),
('pack', task_name_edit), task_name_edit,
('pack', assignee_type_ahead), assignee_type_ahead,
('pack', urwid.Divider('-')), urwid.Divider('-'),
('pack', self.description_edit), self.description_edit,
('pack', urwid.Divider('-')), urwid.Divider('-'),
urwid.BoxAdapter(subtask_list, len(all_subtasks)),
urwid.Divider('-'),
] + \ ] + \
[('pack', urwid.Text('[' + story['created_by']['name'] + '] ' + \ [urwid.Text('[' + story['created_by']['name'] + '] ' + \
story['text'])) for story in stories] + \ story['text']) for story in stories] + \
[ [comment_edit]
('weight', 1, urwid.Filler(comment_edit, 'bottom'))
]
super(TaskDetails, self).__init__(body) super(TaskDetails, self).__init__(body)
def completeTask(self, task_id):
urwid.emit_signal(self, 'complete', task_id)
def newTask(self, task_after_id=None):
urwid.emit_signal(self, 'newtask', task_after_id)
def updateSubtask(self, task_id, name):
urwid.emit_signal(self, 'updatetask', task_id, name)
def showDetails(self, task_id):
urwid.emit_signal(self, 'details', task_id)
def keypress(self, size, key): def keypress(self, size, key):
key = super(TaskDetails, self).keypress(size, key) key = super(TaskDetails, self).keypress(size, key)