Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55970ab144 | ||
|
|
65bd30d026 | ||
|
|
6243a9bb68 | ||
|
|
3a5837ae5d | ||
|
|
dac83e00a1 | ||
| 86e1d830de | |||
| 0fff014307 | |||
| 6664d299b9 | |||
| 7f76ebd441 | |||
| 5d176075a7 | |||
| e18c923202 | |||
| 6ba98525d5 | |||
| 3894b81ebc |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
|||||||
*.swp
|
*.swp
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
|
tags
|
||||||
|
|
||||||
.state
|
.state
|
||||||
.oauth
|
.oauth
|
||||||
secrets.py
|
secrets.py
|
||||||
|
|||||||
36
cmdasana.py
36
cmdasana.py
@@ -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
102
ui.py
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user