diff --git a/src/.board.md b/src/.board.md deleted file mode 100644 index 36668f2..0000000 --- a/src/.board.md +++ /dev/null @@ -1,18 +0,0 @@ -# - -## To Do - - -- Update the task information -- Task 2 - -## Review - - --  Task 3 - -## Done - - -- Task 4 - diff --git a/src/board.py b/src/board.py index 0047c2f..9c52fbe 100644 --- a/src/board.py +++ b/src/board.py @@ -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) diff --git a/src/layout.tcss b/src/layout.tcss index fcfb400..020bb11 100644 --- a/src/layout.tcss +++ b/src/layout.tcss @@ -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%; diff --git a/src/tui.py b/src/tui.py index befe595..b842057 100644 --- a/src/tui.py +++ b/src/tui.py @@ -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):