Fix pykban to make working version

master
Alex Selimov 4 weeks ago
parent 14ec441322
commit 893b5e9473

@ -19,7 +19,9 @@ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Environment :: Console" "Environment :: Console"
] ]
dependencies = [
"textual"
]
[project.urls] [project.urls]
Homepage = "https://alexselimov.com/git/aselimov/pykanban" Homepage = "https://alexselimov.com/git/aselimov/pykanban"
Issues = "https://github.com/aselimov/PyKanban/issues" Issues = "https://github.com/aselimov/PyKanban/issues"

@ -0,0 +1,19 @@
columns:
- To Do
- In Progress
- Review
- Done
tasks:
- column: To Do
description: "We want to be able to retire some done tickets \nwithout having to\
\ delete them."
score: '5'
summary: Work out some way to handle sprints
- column: To Do
description: 'I want to add footers which describe the key shortcuts,
Additionally this should be disabledable via a command line argument
'
score: '5'
summary: 'Add some footers for the key shortcuts '

@ -3,24 +3,32 @@ from textual.widgets import Static, Label, ListItem, ListView, TextArea, Input
from textual.containers import Horizontal, Vertical from textual.containers import Horizontal, Vertical
from textual.screen import Screen from textual.screen import Screen
from textual.binding import Binding from textual.binding import Binding
from board import Board, Task from .board import Board, Task
def run_tui():
kb = KanbanForm()
kb.run()
class TaskList(ListView): class TaskList(ListView):
""" """
Inherited widget from Listview to use as the kanban board columns Inherited widget from Listview to use as the kanban board columns
""" """
# Keybinds # Keybinds
BINDINGS = [ BINDINGS = [
Binding("k", "cursor_up", "Cursor Up", show=False, priority=True), Binding("k", "cursor_up", "Cursor Up", show=False, priority=True),
Binding("j", "cursor_down", "Cursor Down", show=False, priority=True), Binding("j", "cursor_down", "Cursor Down", show=False, priority=True),
] ]
class EditTaskScreen(Screen): class EditTaskScreen(Screen):
""" """
This is a screen used to edit the name of a task This is a screen used to edit the name of a task
""" """
CSS="""
CSS = """
Label{ Label{
width:50%; width:50%;
background: #282828; background: #282828;
@ -47,10 +55,11 @@ class EditTaskScreen(Screen):
} }
""" """
BINDINGS = [ BINDINGS = [
Binding('ctrl+s', 'save', 'Save Changes', priority=True), Binding("ctrl+s", "save", "Save Changes", priority=True),
Binding('escape', 'exit', 'Exit Without Changes', priority=True), Binding("escape", "exit", "Exit Without Changes", priority=True),
] ]
def __init__(self,text):
def __init__(self, text):
""" """
Initialize the screen Initialize the screen
""" """
@ -61,19 +70,18 @@ class EditTaskScreen(Screen):
""" """
Compose the widgets on the screen, this screen doesn't need dynamic layout changes Compose the widgets on the screen, this screen doesn't need dynamic layout changes
""" """
yield Label('Task Name:') yield Label("Task Name:")
yield Input(value=self.text.summary) yield Input(value=self.text.summary)
yield Label('Score:') yield Label("Score:")
if self.text.score: if self.text.score:
yield Input(value=self.text.score) yield Input(value=self.text.score)
else: else:
yield Input(value="") yield Input(value="")
yield Label('Description:') yield Label("Description:")
if self.text.description: if self.text.description:
yield TextArea(self.text.description, language='markdown') yield TextArea(self.text.description, language="markdown")
else: else:
yield TextArea(language='markdown') yield TextArea(language="markdown")
def action_save(self): def action_save(self):
query = self.query(selector=Input) query = self.query(selector=Input)
@ -86,11 +94,13 @@ class EditTaskScreen(Screen):
def action_exit(self): def action_exit(self):
self.dismiss(None) self.dismiss(None)
class EditColScreen(Screen): class EditColScreen(Screen):
""" """
This is a screen used to edit the name of a task This is a screen used to edit the name of a task
""" """
CSS="""
CSS = """
Label{ Label{
width:50%; width:50%;
background: #282828; background: #282828;
@ -104,10 +114,11 @@ class EditColScreen(Screen):
} }
""" """
BINDINGS = [ BINDINGS = [
Binding('ctrl+s', 'save', 'Save Changes', priority=True), Binding("ctrl+s", "save", "Save Changes", priority=True),
Binding('enter', 'save', 'Save Changes', priority=True), Binding("enter", "save", "Save Changes", priority=True),
] ]
def __init__(self,text):
def __init__(self, text):
""" """
Initialize the screen Initialize the screen
""" """
@ -118,67 +129,94 @@ class EditColScreen(Screen):
""" """
Compose the widgets on the screen, this screen doesn't need dynamic layout changes Compose the widgets on the screen, this screen doesn't need dynamic layout changes
""" """
yield Label('Column Name:') yield Label("Column Name:")
yield Input(value=self.text) yield Input(value=self.text)
def action_save(self): def action_save(self):
query = self.query(selector=Input) query = self.query(selector=Input)
self.dismiss(query.nodes[0].value) self.dismiss(query.nodes[0].value)
class KanbanForm(App): class KanbanForm(App):
CSS_PATH = 'layout.tcss' CSS_PATH = "layout.tcss"
BINDINGS = [ BINDINGS = [
Binding("a", "new_task", "Add New Task", show=False, ), Binding(
Binding("l", "fnext", "Focus Next", show=False, ), "a",
Binding("h", "fprev", "Focus Prev", show=False, ), "new_task",
"Add New Task",
show=False,
),
Binding(
"l",
"fnext",
"Focus Next",
show=False,
),
Binding(
"h",
"fprev",
"Focus Prev",
show=False,
),
Binding("L", "move_up", "Focus Next", show=False), Binding("L", "move_up", "Focus Next", show=False),
Binding("H", "move_down", "Focus Prev", show=False), Binding("H", "move_down", "Focus Prev", show=False),
Binding("e", "edit_task", "Edit Task", show=False,), Binding(
Binding("r", "edit_column", "Edit Column Name", show=False,), "e",
Binding("d", "delete_task", "Delete Task", show=False,), "edit_task",
Binding('q', 'exit', "Exit") "Edit Task",
] show=False,
),
Binding(
"r",
"edit_column",
"Edit Column Name",
show=False,
),
Binding(
"x",
"delete_task",
"Delete Task",
show=False,
),
Binding("q", "exit", "Exit"),
]
def compose(self): def compose(self):
""" """
Initialization function for form Initialization function for form
""" """
# Initialize our board class # Initialize our board class
self.board = Board(file = '.board.yaml') self.board = Board(file=".board.yaml")
self.cols = list() self.cols = list()
self.col_widgets = list() self.col_widgets = list()
with Horizontal(): with Horizontal():
for i,col in enumerate(self.board.get_columns()): for i, col in enumerate(self.board.get_columns()):
if i < len(self.board.get_columns())-1: if i < len(self.board.get_columns()) - 1:
col_class = 'column' col_class = "column"
else: else:
col_class = 'last-column' col_class = "last-column"
with Vertical(classes=col_class): with Vertical(classes=col_class):
if i == 0: if i == 0:
yield Static(col, classes='header-focused') yield Static(col, classes="header-focused")
else: else:
yield Static(col, classes='header') yield Static(col, classes="header")
yield TaskList( yield TaskList(
*[ListItem(Label(task.summary)) for task in self.board.get_tasks()[i]]) *[ListItem(Label(task.summary)) for task in self.board.get_tasks()[i]]
)
def action_fnext(self): def action_fnext(self):
""" Focus next column""" """Focus next column"""
query = self.query(selector=Static) query = self.query(selector=Static)
query = [node for node in query.nodes if str(node) == 'Static()'] query = [node for node in query.nodes if str(node) == "Static()"]
icol, _ = self.get_col_task() icol, _ = self.get_col_task()
query[icol].classes="header" query[icol].classes = "header"
self.children[0].focus_next() self.children[0].focus_next()
try: try:
query[icol+1].classes="header-focused" query[icol + 1].classes = "header-focused"
except IndexError: except IndexError:
query[0].classes="header-focused" query[0].classes = "header-focused"
def action_move_up(self): def action_move_up(self):
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
@ -187,23 +225,22 @@ class KanbanForm(App):
if moved: if moved:
query = self.query(selector=TaskList) query = self.query(selector=TaskList)
self.focused.highlighted_child.remove() self.focused.highlighted_child.remove()
query.nodes[icol+1].append(ListItem(Label(text))) query.nodes[icol + 1].append(ListItem(Label(text)))
self.focused.action_cursor_down() self.focused.action_cursor_down()
self.action_fnext() self.action_fnext()
self.focused.action_cursor_down() self.focused.action_cursor_down()
def action_fprev(self): def action_fprev(self):
""" Focus previous column """ """Focus previous column"""
query = self.query(selector=Static) query = self.query(selector=Static)
query = [node for node in query.nodes if str(node) == 'Static()'] query = [node for node in query.nodes if str(node) == "Static()"]
icol, _ = self.get_col_task() icol, _ = self.get_col_task()
query[icol].classes="header" query[icol].classes = "header"
self.children[0].focus_previous() self.children[0].focus_previous()
try: try:
query[icol-1].classes="header-focused" query[icol - 1].classes = "header-focused"
except IndexError: except IndexError:
query[-1].classes="header-focused" query[-1].classes = "header-focused"
def action_move_down(self): def action_move_down(self):
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
@ -212,7 +249,7 @@ class KanbanForm(App):
if moved: if moved:
query = self.query(selector=TaskList) query = self.query(selector=TaskList)
self.focused.highlighted_child.remove() self.focused.highlighted_child.remove()
query.nodes[icol-1].append(ListItem(Label(text))) query.nodes[icol - 1].append(ListItem(Label(text)))
self.focused.action_cursor_down() self.focused.action_cursor_down()
self.action_fprev() self.action_fprev()
self.focused.action_cursor_down() self.focused.action_cursor_down()
@ -221,9 +258,9 @@ class KanbanForm(App):
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
task = self.board.get_task(icol, itask) task = self.board.get_task(icol, itask)
self.push_screen(EditTaskScreen(task), self.update_task) self.push_screen(EditTaskScreen(task), self.update_task)
def action_new_task(self): def action_new_task(self):
self.push_screen(EditTaskScreen(Task(None,None,None)), self.new_task) self.push_screen(EditTaskScreen(Task(None, None, None)), self.new_task)
def action_edit_column(self): def action_edit_column(self):
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
@ -233,25 +270,23 @@ class KanbanForm(App):
def action_delete_task(self): def action_delete_task(self):
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
self.focused.highlighted_child.remove() self.focused.highlighted_child.remove()
self.board.del_task(icol,itask) self.board.del_task(icol, itask)
def update_col(self, text): def update_col(self, text):
""" Update the column """Update the column"""
"""
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
query = self.query(selector=Static) query = self.query(selector=Static)
query = [node for node in query.nodes if str(node) == 'Static()'] query = [node for node in query.nodes if str(node) == "Static()"]
query[icol].update(text) query[icol].update(text)
self.board.get_columns()[icol] = text self.board.get_columns()[icol] = text
def action_exit(self): def action_exit(self):
""" Exit the application """ """Exit the application"""
self.board.write_yaml(file='.board.yaml') self.board.write_yaml(file=".board.yaml")
self.exit() self.exit()
def get_col_task(self): def get_col_task(self):
""" """
This function gets the relevant column and task from the Board object for the current This function gets the relevant column and task from the Board object for the current
selected item in the tui. selected item in the tui.
""" """
@ -267,15 +302,15 @@ class KanbanForm(App):
to_move = focused_col.highlighted_child to_move = focused_col.highlighted_child
task_index = None task_index = None
for i, child in enumerate(focused_col.children): for i, child in enumerate(focused_col.children):
if to_move == child: if to_move == child:
task_index = i task_index = i
return col_index, task_index return col_index, task_index
def update_task(self, task): def update_task(self, task):
""" This function gets the text inputted in the edit screen and updates the underlying """This function gets the text inputted in the edit screen and updates the underlying
task and the board class task and the board class
""" """
if task: if task:
icol, itask = self.get_col_task() icol, itask = self.get_col_task()
@ -283,20 +318,9 @@ class KanbanForm(App):
self.board.update_task(icol, itask, task) self.board.update_task(icol, itask, task)
def new_task(self, task): def new_task(self, task):
""" This function adds a new task to our board """This function adds a new task to our board"""
"""
if task: if task:
icol,_ = self.get_col_task() icol, _ = self.get_col_task()
self.focused.mount(ListItem(Label(task.summary))) self.focused.mount(ListItem(Label(task.summary)))
self.board.add_task(icol, task) self.board.add_task(icol, task)
self.focused.action_cursor_down() self.focused.action_cursor_down()
# def on_key(self):
# with open('log','a') as f:
# f.write("{}".format(self.children[0].focus_next))
if __name__ == "__main__":
kb = KanbanForm()
kb.run()