Improve the task editing panes, swap the backend from an md file to a yaml file, add column editing functionality

feature/make_board_screen
Alex Selimov 1 year ago
parent b19fe10a0d
commit 779ddca11f

@ -1,18 +0,0 @@
#
## To Do
- Update the task information
- Task 2
## Review
-  Task 3
## Done
- Task 4

@ -1,5 +1,20 @@
""" This module contains classes and functions to contain the kanban board information """
import numpy as np
import yaml
class Task:
""" This class represents each task,
"""
def __init__(self, summary, score, description):
""" Initialize the task class
"""
# Each task has the following properties
self.summary = summary # Summary of the task
self.score = score # Score for ticket
self.description = description # Description of ticket
class Board:
def __init__(self, file = None):
""" Initialize the Board class, this class has three important class variables.
@ -13,59 +28,30 @@ class Board:
self.columns = list()
self.tasks = list()
self.file = ''
self.file = file
if file:
self.parse_md(file)
self.read_yaml(file)
def parse_md(self, file):
""" Upon starting the code we need to parse the markdown file which contains our board
information
def read_yaml(self, file='.board.yaml'):
""" Read the yaml file in and set up the data
Arguments:
file - the path to the markdown file containing the board information
Arguments:
file - yaml file to read in
"""
with open(file,'r') as f:
for line in f:
item_type = line.split(' ')[0]
# Assign sprint
if item_type == '#':
# If sprint has already been defined we should exit the loop
if self.sprint:
break
# Otherwise assign it
try:
self.sprint = ' '.join(line.split(' ')[1:])
except IndexError:
# If a sprint title is not defined we default it to ' ' which we process
# later
self.sprint=' '
# Define a new column and add a list to the tasks variable that corresponds to that
# column
elif item_type == "##":
self.columns.append(' '.join(line.split(' ')[1:]))
self.tasks.append(list())
# Now add the task to the list structures
elif item_type == "-":
# The tasks are a list of [col index, task name]
self.tasks[-1].append(' '.join(line.split(' ')[1:]).strip())
def write_md(self):
with open(self.file, 'w') as f:
f.write('#\n\n')
for i,col in enumerate(self.columns):
f.write('## {}\n\n'.format(col))
for task in self.tasks[i]:
f.write('- {}\n'.format(task))
f.write('\n')
# Read in the data
with open(file, 'r') as f:
data = yaml.safe_load(f)
# Assign the data to board variables
self.columns = data['columns']
self.tasks = [[] for col in self.columns]
for task in data['tasks']:
self.tasks[self.columns.index(task['column'])].append(
Task(task['summary'], task['score'], task['description']))
def move_task(self, col_index, task_index, direction):
@ -108,11 +94,11 @@ class Board:
""" Return a task based on column and task index"""
return self.tasks[icol][itask]
def update_task( self, icol, itask, text):
def update_task( self, icol, itask, task):
""" Update the task based on text """
self.tasks[icol][itask] = text
self.tasks[icol][itask] = task
def add_task( self, icol, text):
def add_task( self, icol, task):
"""Add a task to icol"""
self.tasks[icol].append(text)
self.tasks[icol].append(task)

@ -6,13 +6,19 @@ Screen {
background: $bg;
}
EditScreen {
EditTaskScreen {
align: center middle;
overflow-x: hidden;
layout: vertical;
background: #000000 25%;
}
EditColScreen {
align: center middle;
overflow-x: hidden;
layout: vertical;
background: #000000 25%;
}
.column {
width: 1fr;
height: 100%;

@ -3,7 +3,7 @@ from textual.widgets import Static, Label, ListItem, ListView, TextArea, Input
from textual.containers import Horizontal, Vertical
from textual.screen import Screen
from textual.binding import Binding
from board import Board
from board import Board, Task
class TaskList(ListView):
@ -16,20 +16,38 @@ class TaskList(ListView):
Binding("j", "cursor_down", "Cursor Down", show=False, priority=True),
]
class EditScreen(Screen):
class EditTaskScreen(Screen):
"""
This is a screen used to edit the name of a task
"""
CSS="""
Label{
width:50%;
background: #282828;
padding: 1;
}
Input{
width:50%;
background: #282828;
padding: 0 0;
border: #ebdbb9;
}
Input:focus{
border: #458588;
}
TextArea{
width: 50%;
height: 25%;
background: #282828;
border: #ebdbb9;
}
TextArea:focus{
border: #458588;
}
"""
BINDINGS = [
Binding('enter', 'save', 'Save Changes', priority=True)
Binding('ctrl+s', 'save', 'Save Changes', priority=True),
]
def __init__(self,text):
"""
@ -43,6 +61,60 @@ class EditScreen(Screen):
Compose the widgets on the screen, this screen doesn't need dynamic layout changes
"""
yield Label('Task Name:')
yield Input(value=self.text.summary)
yield Label('Score:')
if self.text.score:
yield Input(value=self.text.score)
else:
yield Input(value="")
yield Label('Description:')
if self.text.description:
yield TextArea(self.text.description, language='markdown')
else:
yield TextArea(language='markdown')
def action_save(self):
query = self.query(selector=Input)
self.text.summary = query.nodes[0].value
self.text.score = query.nodes[1].value
query = self.query(selector=TextArea)
self.text.description = query.nodes[0].text
self.dismiss(self.text)
class EditColScreen(Screen):
"""
This is a screen used to edit the name of a task
"""
CSS="""
Label{
width:50%;
background: #282828;
padding: 1;
}
Input{
width:50%;
background: #282828;
padding: 0 0;
border: #ebdbb9;
}
"""
BINDINGS = [
Binding('ctrl+s', 'save', 'Save Changes', priority=True),
Binding('enter', 'save', 'Save Changes', priority=True),
]
def __init__(self,text):
"""
Initialize the screen
"""
super().__init__()
self.text = text
def compose(self):
"""
Compose the widgets on the screen, this screen doesn't need dynamic layout changes
"""
yield Label('Column Name:')
yield Input(value=self.text)
@ -60,6 +132,7 @@ class KanbanForm(App):
Binding("L", "move_up", "Focus Next", show=False),
Binding("H", "move_down", "Focus Prev", show=False),
Binding("e", "edit_task", "Edit Task", show=False,),
Binding("r", "edit_column", "Edit Column Name", show=False,),
Binding('q', 'exit', "Exit")
]
@ -68,7 +141,7 @@ class KanbanForm(App):
Initialization function for form
"""
# Initialize our board class
self.board = Board(file = '.board.md')
self.board = Board(file = '.board.yaml')
self.cols = list()
self.col_widgets = list()
@ -83,7 +156,7 @@ class KanbanForm(App):
with Vertical(classes=col_class):
yield Static(col, classes='header')
yield TaskList(
*[ListItem(Label(task)) for task in self.board.get_tasks()[i]])
*[ListItem(Label(task.summary)) for task in self.board.get_tasks()[i]])
# Now make all TaskLists except the first have no highlights
def action_fnext(self):
@ -92,7 +165,7 @@ class KanbanForm(App):
def action_move_up(self):
icol, itask = self.get_col_task()
text = self.board.get_task(icol, itask)
text = self.board.get_task(icol, itask).summary
moved = self.board.move_task(icol, itask, 1)
if moved:
query = self.query(selector=TaskList)
@ -109,7 +182,7 @@ class KanbanForm(App):
def action_move_down(self):
icol, itask = self.get_col_task()
text = self.board.get_task(icol, itask)
text = self.board.get_task(icol, itask).summary
moved = self.board.move_task(icol, itask, -1)
if moved:
query = self.query(selector=TaskList)
@ -122,10 +195,25 @@ class KanbanForm(App):
def action_edit_task(self):
icol, itask = self.get_col_task()
task = self.board.get_task(icol, itask)
self.push_screen(EditScreen(task), self.update_task)
self.push_screen(EditTaskScreen(task), self.update_task)
def action_new_task(self):
self.push_screen(EditScreen(""), self.new_task)
self.push_screen(EditTaskScreen(Task(None,None,None)), self.new_task)
def action_edit_column(self):
icol, itask = self.get_col_task()
text = self.board.get_columns()[icol]
self.push_screen(EditColScreen(text), self.update_col)
def update_col(self, text):
""" Update the column
"""
icol, itask = self.get_col_task()
query = self.query(selector=Static)
query = [node for node in query.nodes if str(node) == 'Static()']
query[icol].update(text)
self.board.get_columns()[icol] = text
def action_exit(self):
""" Exit the application """
@ -153,21 +241,21 @@ class KanbanForm(App):
return col_index, task_index
def update_task(self, text):
def update_task(self, task):
""" This function gets the text inputted in the edit screen and updates the underlying
task and the board class
"""
icol, itask = self.get_col_task()
self.focused.highlighted_child.children[0].update(text)
self.board.update_task(icol, itask, text)
self.focused.highlighted_child.children[0].update(task.summary)
self.board.update_task(icol, itask, task)
def new_task(self, text):
def new_task(self, task):
""" This function adds a new task to our board
"""
icol,_ = self.get_col_task()
self.focused.mount(ListItem(Label(text)))
self.board.add_task(icol, text)
self.focused.mount(ListItem(Label(task.summary)))
self.board.add_task(icol, task)
self.focused.highlighted_child
# def on_key(self):