home · contact · privacy
Improve todo accounting.
authorChristian Heller <c.heller@plomlompom.de>
Sun, 14 Jan 2024 20:08:13 +0000 (21:08 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 14 Jan 2024 20:08:13 +0000 (21:08 +0100)
todo.py
todo_templates/base.html
todo_templates/calendar.html
todo_templates/tagfilters.html
todo_templates/task.html
todo_templates/todo.html

diff --git a/todo.py b/todo.py
index e0bedaf37888e179f717654683419dee8020c8a0..171514f1f8bb1a6e01161b6e6b7f1840955a2f7e 100644 (file)
--- a/todo.py
+++ b/todo.py
@@ -69,9 +69,9 @@ class Task:
             ret = default_effort
         return ret
 
-    @property
-    def current_default_effort(self):
-        return self.default_effort_at(self.db.selected_date)
+    @property
+    def current_default_effort(self):
+        return self.default_effort_at(self.db.selected_date)
 
     def matches(self, search):
         if search is None:
@@ -213,9 +213,9 @@ class Day:
     def todos_sum(self):
         return self._todos_sum()
 
-    @property
-    def todos_sum2(self):
-        return self._todos_sum(True)
+    @property
+    def todos_sum2(self):
+        return self._todos_sum(True)
 
     # @property
     # def date(self):
@@ -232,7 +232,7 @@ class Day:
 class Todo:
 
     # def __init__(self, db, id_, task, done=False, day_effort=None, comment='', day_tags=None, importance=1.0, efforts=None):
-    def __init__(self, db, id_, task, done=False, comment='', day_tags=None, importance=1.0, efforts=None):
+    def __init__(self, db, id_, task, done=False, comment='', day_tags=None, importance=1.0, efforts=None, children=None):
         self.id_ = id_
         self.db = db 
         self.task = task 
@@ -242,6 +242,8 @@ class Todo:
         self.comment = comment
         self.day_tags = day_tags if day_tags else set()
         self.importance = importance
+        self.children = children if children else [] 
+        self.parent = None 
 
     @classmethod
     def from_dict(cls, db, d, id_):
@@ -250,6 +252,8 @@ class Todo:
         # todo._efforts = d['efforts'] if 'efforts' in d.keys() else None
         # todo = cls(db, id_, db.tasks[d['task']], d['done'], d['day_effort'], d['comment'], set(d['day_tags']), d['importance'], d['efforts'])
         todo = cls(db, id_, db.tasks[d['task']], d['done'], d['comment'], set(d['day_tags']), d['importance'], d['efforts'])
+        if 'children' in d:
+            todo.children = d['children']
         return todo
 
     # @classmethod
@@ -261,11 +265,11 @@ class Todo:
 
     def to_dict(self):
         # return {'task': self.task.id_, 'done': self.done, 'day_effort': self.day_effort, 'comment': self.comment, 'day_tags': list(self.day_tags), 'importance': self.importance, 'efforts': self.efforts}
-        return {'task': self.task.id_, 'done': self.done, 'comment': self.comment, 'day_tags': list(self.day_tags), 'importance': self.importance, 'efforts': self.efforts}
+        return {'task': self.task.id_, 'done': self.done, 'comment': self.comment, 'day_tags': list(self.day_tags), 'importance': self.importance, 'efforts': self.efforts, 'children': self.children}
 
     @property
     def default_effort(self):
-        return self.task.default_effort_at(self.day.date)
+        return self.task.default_effort_at(self.sorted_effort_dates[0])
 
     # @property
     # def effort(self):
@@ -283,6 +287,26 @@ class Todo:
     #     #         if v == self:
     #     #             return self.db.tasks[k]
 
+    def is_effort_removable(self, date):
+        if not date in self.efforts.keys():
+            return False
+        # if len(self.efforts) == 1:
+        #     return False
+        if self.efforts[date]:
+            return False
+        if self.done and date == self.sorted_effort_dates[-1]:
+            return False
+        return True
+
+    @property
+    def total_effort(self):
+        total = 0
+        for effort in self.efforts.values():
+            total += effort if effort else 0
+        if self.done:
+            total = max(total, self.task.default_effort_at(self.sorted_effort_dates[-1]))
+        return total
+
     def matches(self, search):
         if search is None:
             return False
@@ -291,14 +315,21 @@ class Todo:
 
     @property
     def title(self):
-        return self.task.title_at(self.day.date)
+        return self.task.title_at(self.sorted_effort_dates[0])
+
+    @property
+    def path(self):
+        path = ''
+        if self.parent:
+            path = f'{self.parent.path}{self.parent.title}:'
+        return path
 
     @property
     def tags(self):
         return self.day_tags | self.task.tags
 
-    def internals_empty(self):
-        return len(self.comment) == 0 and len(self.day_tags) == 0
+    def internals_empty(self):
+        return len(self.comment) == 0 and len(self.day_tags) == 0
 
     # def ensure_day_efforts_table(self):
     #     # We don't do this yet at __init__ because self.day.date is unknown, since Todo may be imported with Day, and during the import process the Day is not yet keyed in TodoDB.days.
@@ -313,13 +344,17 @@ class Todo:
     def day_effort(self):
         return self.efforts[self.db.selected_date]
 
+    @property
+    def sorted_effort_dates(self):
+        dates = list(self.efforts.keys())
+        dates.sort()
+        return dates
+
     @property
     def day(self):
         if len(self.efforts) == 0:
             return None
-        dates = list(self.efforts.keys())
-        dates.sort()
-        todo_start_date = dates[0]
+        todo_start_date = self.sorted_effort_dates[0]
         return self.db.days[todo_start_date]
 
     # @property
@@ -369,11 +404,31 @@ class TodoDB(PlomDB):
                 self.t_tags.add(tag)
         for date, day_dict in d['days'].items():
             self.add_day(dict_source=day_dict, date=date)
+        for todo in self.todos.values():
+            for child_id in todo.children:
+                self.todos[child_id].parent = todo
+            # if len(todo.efforts) == 0:
+            #     print("DEBUG", todo.id_, todo.task.title, todo.efforts)
+            for date in todo.efforts.keys():
+                if not date in self.days.keys():
+                    self.add_day(date)
+                if not todo in self.days[date].linked_todos_as_list:
+                    self.days[date].linked_todos_as_list += [todo]
+                    # print("DEBUG", todo.title, date)
+                # if type(todo.efforts[date]) == str:
+                #     todo.efforts[date] = float(todo.efforts[date])
+                #     print("DEBUG", todo.title, date, todo.efforts[date])
         # for todo in self.todos.values():
         # for day in self.days.values():
         #     for todo in day.todos.values():
         #         for tag in todo.day_tags:
         #             self.t_tags.add(tag)
+        # delete = None
+        # for todo in self.todos.values():
+        #     if len(todo.efforts) == 0:
+        #         print("DEBUG", todo.task.title)
+        #         delete = todo.id_ 
+        # self.delete_todo(delete)
         self.set_visibilities()
 
     def set_visibilities(self):
@@ -435,9 +490,17 @@ class TodoDB(PlomDB):
         else:
             return t
 
-    def add_todo(self, todo_dict, id_=None):
+    def add_todo(self, todo_dict=None, id_=None, task=None, efforts=None):
         id_ = id_ if id_ else str(uuid4())
-        todo = Todo.from_dict(self, todo_dict, id_)
+        if todo_dict:
+            todo = Todo.from_dict(self, todo_dict, id_)
+        elif task and efforts:
+            todo = Todo(self, id_, task, efforts=efforts)
+            children = []
+            for child_id in task.links:
+                child_task = self.tasks[child_id]
+                children += [self.add_todo(task=child_task, efforts=efforts)]
+            todo.children = [child.id_ for child in children]
         self.todos[id_] = todo 
         return todo
 
@@ -446,43 +509,43 @@ class TodoDB(PlomDB):
         self.days[date] = day 
         return day
 
-    def show_day(self, task_sort=None):
-        task_sort = task_sort if task_sort else 'title' 
-        current_date = datetime.strptime(self.selected_date, DATE_FORMAT)
-        prev_date = current_date - timedelta(days=1)
-        prev_date_str = prev_date.strftime(DATE_FORMAT)
-        next_date = current_date + timedelta(days=1)
-        next_date_str = next_date.strftime(DATE_FORMAT)
-        task_rows = []
-        for uuid, task in self.tasks.items():
-            if not task.visible:
-                continue
-            todo = None
-            if uuid in self.selected_day.todos.keys():
-                todo = self.selected_day.todos[uuid]
-                if not todo.visible:
-                    continue
-            task_rows += [{'uuid': uuid, 'task': task, 'todo': todo}] 
-        if task_sort == 'title':
-            task_rows.sort(key=lambda r: r['task'].title)
-        elif task_sort == 'default_effort':
-            task_rows.sort(key=lambda r: r['task'].default_effort, reverse=True)
-        elif task_sort == 'done':
-            task_rows.sort(key=lambda r: 0 if not r['todo'] else r['todo'].day_effort if r['todo'].day_effort else r['task'].default_effort if r['todo'].done else 0, reverse=True)
-        elif task_sort == 'importance':
-            task_rows.sort(key=lambda r: 0.0 if not r['todo'] else r['todo'].importance, reverse=True)
-        elif task_sort == 'chosen':
-            task_rows.sort(key=lambda r: False if not r['todo'] else True, reverse=True)
-        elif task_sort == 'comment':
-            task_rows.sort(key=lambda r: '' if not r['todo'] else r['todo'].comment, reverse=True)
-        done_tasks = []
-        for uuid, task in self.tasks.items():
-            if uuid in self.selected_day.todos.keys():
-                todo = self.selected_day.todos[uuid]
-                if todo.done:
-                    done_tasks += [todo]
-        done_tasks.sort(key=lambda t: t.effort, reverse=True)
-        return j2env.get_template('day.html').render(db=self, action=self.prefix+'/day', prev_date=prev_date_str, next_date=next_date_str, task_rows=task_rows, sort=task_sort, done_tasks=done_tasks)
+    def show_day(self, task_sort=None):
+        task_sort = task_sort if task_sort else 'title' 
+        current_date = datetime.strptime(self.selected_date, DATE_FORMAT)
+        prev_date = current_date - timedelta(days=1)
+        prev_date_str = prev_date.strftime(DATE_FORMAT)
+        next_date = current_date + timedelta(days=1)
+        next_date_str = next_date.strftime(DATE_FORMAT)
+        task_rows = []
+        for uuid, task in self.tasks.items():
+            if not task.visible:
+                continue
+            todo = None
+            if uuid in self.selected_day.todos.keys():
+                todo = self.selected_day.todos[uuid]
+                if not todo.visible:
+                    continue
+            task_rows += [{'uuid': uuid, 'task': task, 'todo': todo}] 
+        if task_sort == 'title':
+            task_rows.sort(key=lambda r: r['task'].title)
+        elif task_sort == 'default_effort':
+            task_rows.sort(key=lambda r: r['task'].default_effort, reverse=True)
+        elif task_sort == 'done':
+            task_rows.sort(key=lambda r: 0 if not r['todo'] else r['todo'].day_effort if r['todo'].day_effort else r['task'].default_effort if r['todo'].done else 0, reverse=True)
+        elif task_sort == 'importance':
+            task_rows.sort(key=lambda r: 0.0 if not r['todo'] else r['todo'].importance, reverse=True)
+        elif task_sort == 'chosen':
+            task_rows.sort(key=lambda r: False if not r['todo'] else True, reverse=True)
+        elif task_sort == 'comment':
+            task_rows.sort(key=lambda r: '' if not r['todo'] else r['todo'].comment, reverse=True)
+        done_tasks = []
+        for uuid, task in self.tasks.items():
+            if uuid in self.selected_day.todos.keys():
+                todo = self.selected_day.todos[uuid]
+                if todo.done:
+                    done_tasks += [todo]
+        done_tasks.sort(key=lambda t: t.effort, reverse=True)
+        return j2env.get_template('day.html').render(db=self, action=self.prefix+'/day', prev_date=prev_date_str, next_date=next_date_str, task_rows=task_rows, sort=task_sort, done_tasks=done_tasks)
 
     def neighbor_dates(self):
         current_date = datetime.strptime(self.selected_date, DATE_FORMAT)
@@ -494,22 +557,20 @@ class TodoDB(PlomDB):
 
     def show_do_day(self, sort_order=None):
         prev_date_str, next_date_str = self.neighbor_dates()
-        # current_date = datetime.strptime(self.selected_date, DATE_FORMAT)
-        # prev_date = current_date - timedelta(days=1)
-        # prev_date_str = prev_date.strftime(DATE_FORMAT)
-        # next_date = current_date + timedelta(days=1)
-        # next_date_str = next_date.strftime(DATE_FORMAT)
         todos = [t for t in self.selected_day.linked_todos_as_list if t.visible]
         if sort_order == 'title':
             todos.sort(key=lambda t: t.task.title)
         elif sort_order == 'done':
             todos.sort(key=lambda t: t.day_effort if t.day_effort else t.default_effort if t.done else 0, reverse=True)
         elif sort_order == 'default_effort':
-            todos.sort(key=lambda t: t.task.default_effort, reverse=True)
+            todos.sort(key=lambda t: t.default_effort, reverse=True)
         elif sort_order == 'importance':
             todos.sort(key=lambda t: t.importance, reverse=True)
         return j2env.get_template('do_day.html').render(
                 day=self.selected_day,
+                tags=self.t_tags,
+                filter_and=self.t_filter_and,
+                filter_not=self.t_filter_not,
                 prev_date=prev_date_str,
                 next_date=next_date_str,
                 todos=todos,
@@ -556,20 +617,27 @@ class TodoDB(PlomDB):
         #     todo = self.days[selected_date].todos[task_uuid]
         # else:
         #     todo = self.days[selected_date].add_todo(task_uuid)
-        return j2env.get_template('todo.html').render(db=self, todo=todo, action=self.prefix+'/todo', return_to=return_to)
-
-    def update_todo_mini(self, task_uuid, date, day_effort, done, importance):
-        if date not in self.days.keys():
-            self.days[date] = self.add_day(test_date=f'Y:{date}') 
-            # print("DEBUG update_todo_min", self.days[date].date)
-        if task_uuid in self.days[date].todos.keys():
-            todo = self.days[date].todos[task_uuid]
-        else:
-            todo = self.days[date].add_todo(task_uuid)
-        todo.day_effort = day_effort
-        todo.done = done
-        todo.importance = importance
-        return todo
+        linked_todos = [self.todos[c] for c in todo.children]
+        filtered_todos = [] #[t for t in self.todos.values() if t.visible and t != self and (t not in linked_todos) and (len(search) == 0 or t.matches(search))] 
+        return j2env.get_template('todo.html').render(
+                db=self,
+                todo=todo,
+                filtered_todos=filtered_todos,
+                linked_todos=linked_todos,
+                return_to=return_to)
+
+    # def update_todo_mini(self, task_uuid, date, day_effort, done, importance):
+    #     if date not in self.days.keys():
+    #         self.days[date] = self.add_day(test_date=f'Y:{date}') 
+    #         # print("DEBUG update_todo_min", self.days[date].date)
+    #     if task_uuid in self.days[date].todos.keys():
+    #         todo = self.days[date].todos[task_uuid]
+    #     else:
+    #         todo = self.days[date].add_todo(task_uuid)
+    #     todo.day_effort = day_effort
+    #     todo.done = done
+    #     todo.importance = importance
+    #     return todo
 
     def collect_tags(self, tags_joined, tags_checked):
         tags = set()
@@ -603,13 +671,18 @@ class TodoDB(PlomDB):
 
     def delete_todo(self, id_):
         todo = self.todos[id_]
+        dates_to_delete = []
         for date in todo.efforts.keys():
-            self.delete_effort(todo, date)
+            dates_to_delete += [date]
+        for date in dates_to_delete:
+            self.delete_effort(todo, date, force=True)
         del self.todos[id_]
 
-    def delete_effort(self, todo, date):
-        if todo in self.days[date].linked_todos_as_list:
-            self.days[date].linked_todos_as_list.remove(todo)
+    def delete_effort(self, todo, date, force=False):
+        if (not force) and len(todo.efforts) == 1:
+            raise PlomException('todo must retain at least one effort!')
+        self.days[date].linked_todos_as_list.remove(todo)
+        del todo.efforts[date]
 
 
     # def update_todo(self, task_uuid, date, day_effort, done, comment, day_tags_joined, day_tags_checked, importance):
@@ -619,23 +692,34 @@ class TodoDB(PlomDB):
     #     todo.comment = comment
     #     todo.day_tags = self.collect_tags(day_tags_joined, day_tags_checked) 
 
-    def link_day_with_todo(self, date, todo_id):
-        print("DEBUG link", date, todo_id)
-        todo_creation_date, task_uuid = todo_id.split('_')
-        todo = self.days[todo_creation_date].todos[task_uuid]
-        if date in todo.efforts.keys():
-            raise PlomException('todo already linked to respective day')
-        todo.set_day_effort(date, None)
-        if date not in self.days.keys():
-            print("DEBUG link_day_with_todo", date)
-            self.days[date] = self.add_day(test_date=f'Z:{date}') 
-        self.days[date].linked_todos_as_list += [todo]
-        print("DEBUG", date, self.days[date].linked_todos)
-
-    def show_task(self, id_, return_to=''):
+    def link_day_with_todo(self, date, todo_id):
+        print("DEBUG link", date, todo_id)
+        todo_creation_date, task_uuid = todo_id.split('_')
+        todo = self.days[todo_creation_date].todos[task_uuid]
+        if date in todo.efforts.keys():
+            raise PlomException('todo already linked to respective day')
+        todo.set_day_effort(date, None)
+        if date not in self.days.keys():
+            print("DEBUG link_day_with_todo", date)
+            self.days[date] = self.add_day(test_date=f'Z:{date}') 
+        self.days[date].linked_todos_as_list += [todo]
+        print("DEBUG", date, self.days[date].linked_todos)
+
+    def show_task(self, id_, return_to='', search=''):
         task = self.tasks[id_] if id_ else self.add_task()
         selected = id_ in self.selected_day.todos.keys()
-        return j2env.get_template('task.html').render(db=self, task=task, action=self.prefix+'/task', return_to=return_to, selected=selected)
+        linked_tasks = [self.tasks[l] for l in task.links]
+        filtered_tasks = [t for t in self.tasks.values() if t.visible and t != self and (t not in linked_tasks) and (len(search) == 0 or t.matches(search))] 
+        return j2env.get_template('task.html').render(
+                db=self,
+                search=search,
+                tags=self.t_tags, 
+                filter_and=self.t_filter_and,
+                filter_not=self.t_filter_not,
+                filtered_tasks=filtered_tasks,
+                linked_tasks=linked_tasks,
+                task=task,
+                return_to=return_to)
 
     def update_task(self, id_, title, default_effort, tags_joined, tags_checked, links, comment):
         task = self.tasks[id_] if id_ in self.tasks.keys() else self.add_task(id_)
@@ -643,10 +727,6 @@ class TodoDB(PlomDB):
         task.default_effort = float(default_effort) if len(default_effort) > 0 else None
         task.tags = self.collect_tags(tags_joined, tags_checked) 
         task.links = links
-        for link in links:
-            borrowed_links = self.tasks[link].links 
-            borrowed_links.add(id_)
-            self.tasks[link].links = borrowed_links 
         task.comment = comment 
 
     def show_tasks(self, expand_uuid):
@@ -656,24 +736,39 @@ class TodoDB(PlomDB):
                 expanded_tasks[uuid] = self.tasks[uuid]
         return j2env.get_template('tasks.html').render(db=self, action=self.prefix+'/tasks', expand_uuid=expand_uuid, expanded_tasks=expanded_tasks)
 
-    def new_day(self, search):
+    def show_new_day(self, search, hide_chosen_tasks, sort_order=None):
         prev_date_str, next_date_str = self.neighbor_dates()
+        chosen_todos = self.selected_day.linked_todos_as_list
         relevant_todos = []
         for todo in self.todos.values():
-            # if todo.done or (not todo.visible) or (not todo.matches(search)) or todo.day.date == self.selected_day.date:  # TODO or todo is linked by day  
-            if todo.done or (not todo.visible) or (not todo.matches(search)): # or todo.day.date == self.selected_day.date:  # TODO or todo is linked by day  
+            if todo.done or (not todo.visible) or (not todo.matches(search)) or todo in self.selected_day.linked_todos_as_list: # or todo.day.date == self.selected_day.date:  # TODO or todo is linked by day  
                 continue
             relevant_todos += [todo] 
         tasks = []
+        chosen_tasks = [todo.task for todo in self.selected_day.linked_todos_as_list]
         for uuid, task in self.tasks.items():
-            if not task.visible or (not task.matches(search)):
+            if (not task.visible) or (not task.matches(search)) or (hide_chosen_tasks and task in chosen_tasks):
                 continue
             tasks += [task]
+        if sort_order == 'title':
+            chosen_todos.sort(key=lambda t: t.title)
+            relevant_todos.sort(key=lambda t: t.title)
+            tasks.sort(key=lambda t: t.title)
+        elif sort_order == 'effort':
+            chosen_todos.sort(key=lambda t: t.day_effort if t.day_effort else t.default_effort if t.done else 0, reverse=True)
+            relevant_todos.sort(key=lambda t: t.total_effort, reverse=True)
+            tasks.sort(key=lambda t: t.default_effort, reverse=True)
         return j2env.get_template('new_day.html').render(
+                sort=sort_order,
+                tags=self.t_tags,
+                chosen_todos=chosen_todos,
+                filter_and=self.t_filter_and,
+                filter_not=self.t_filter_not,
                 day=self.selected_day,
                 prev_date=prev_date_str,
                 next_date=next_date_str,
                 tasks=tasks,
+                hide_chosen_tasks=hide_chosen_tasks,
                 relevant_todos=relevant_todos,
                 search=search)
 
@@ -703,6 +798,19 @@ class ParamsParser:
             self.cookie_db[key] = param
         return param
 
+    def get_cookied_chain(self, key, default=None):
+        # default = default if default else ['-']
+        params = self.params.get(key, default)
+        if params == ['-']:
+            params = None 
+            if key in self.cookie_db.keys():
+                del self.cookie_db[key]
+        if params is None and key in self.cookie_db.keys():
+            params = self.cookie_db[key]
+        if params is not None:
+            self.cookie_db[key] = params
+        return params
+
 
 class TodoHandler(PlomHandler):
 
@@ -733,15 +841,15 @@ class TodoHandler(PlomHandler):
         # site = path_split(parsed_url.path)[1]
         db = TodoDB(prefix=config['prefix'])
         redir_params = []
-        for param_name, filter_db_name in {('t_and', 't_filter_and'), ('t_not', 't_filter_not')}:
-            filter_db = getattr(db, filter_db_name)
-            if param_name in postvars.keys():
-                for target in postvars[param_name]:
-                    if len(target) > 0 and not target in filter_db:
-                        filter_db += [target]
-                if len(filter_db) == 0:
-                    redir_params += [(param_name, '-')]
-            redir_params += [(param_name, f) for f in filter_db]
+        for param_name, filter_db_name in {('t_and', 't_filter_and'), ('t_not', 't_filter_not')}:
+            filter_db = getattr(db, filter_db_name)
+            if param_name in postvars.keys():
+                for target in postvars[param_name]:
+                    if len(target) > 0 and not target in filter_db:
+                        filter_db += [target]
+                if len(filter_db) == 0:
+                    redir_params += [(param_name, '-')]
+            redir_params += [(param_name, f) for f in filter_db]
 
         def collect_checked(prefix, postvars):
             tags_checked = []
@@ -763,7 +871,7 @@ class TodoHandler(PlomHandler):
             for i, date in enumerate(postvars['effort_date']):
                 if '' == date:
                     continue
-                efforts[date] = postvars['effort'][i] if len(postvars['effort'][i]) > 0 else None 
+                efforts[date] = float(postvars['effort'][i]) if len(postvars['effort'][i]) > 0 else None 
             if 'delete_effort' in postvars.keys():
                 for date in postvars['delete_effort']:
                     del efforts[date]
@@ -797,28 +905,61 @@ class TodoHandler(PlomHandler):
         elif 'task' == site:
             id_ = postvars['id'][0]
             redir_params += [('id', id_)]
-            if 'title' in postvars.keys():
-                db.update_task(id_, postvars['title'][0], postvars['default_effort'][0], postvars['joined_tags'][0], collect_checked('tag_', postvars), collect_checked('link_', postvars), postvars['comment'][0])
-                if 'as_todo' in postvars.keys() and id_ not in db.selected_day.todos.keys():
-                    db.update_todo_mini(id_, db.selected_date, None, False, 1.0)
-                elif 'as_todo' not in postvars.keys() and id_ in db.selected_day.todos.keys():
-                    todo = db.selected_day.todos[id_]
-                    if todo.internals_empty() and (not todo.done) and todo.day_effort is None:
-                        del db.selected_day.todos[id_]
-                    else:
-                        raise PlomException('cannot deselect task as todo of preserve-worthy values')
+            if 'filter' in postvars.keys():
+                redir_params += [('search', postvars['search'][0])]
+            elif 'title' in postvars.keys():
+                links = [] if not 'link_task' in postvars.keys() else postvars['link_task']
+                # db.update_task(id_, postvars['title'][0], postvars['default_effort'][0], postvars['joined_tags'][0], collect_checked('tag_', postvars), collect_checked('link_', postvars), postvars['comment'][0])
+                db.update_task(id_, postvars['title'][0], postvars['default_effort'][0], postvars['joined_tags'][0], collect_checked('tag_', postvars), links, postvars['comment'][0])
+                # if 'as_todo' in postvars.keys() and id_ not in db.selected_day.todos.keys():
+                #     db.update_todo_mini(id_, db.selected_date, None, False, 1.0)
+                # elif 'as_todo' not in postvars.keys() and id_ in db.selected_day.todos.keys():
+                #     todo = db.selected_day.todos[id_]
+                #     if todo.internals_empty() and (not todo.done) and todo.day_effort is None:
+                #         del db.selected_day.todos[id_]
+                #     else:
+                #         raise PlomException('cannot deselect task as todo of preserve-worthy values')
 
         elif 'new_day' == site:
-            redir_params += [('search', postvars['search'][0])]
-            if 'choose_task' in postvars.keys():
-                for i, uuid in enumerate(postvars['choose_task']):
-                     if not uuid in db.selected_day.todos.keys():
-                        # task = db.tasks[uuid]
-                         db.update_todo_mini(uuid, db.selected_date, None, False, 1.0)
-            if 'choose_todo' in postvars.keys():
-                for i, id_ in enumerate(postvars['choose_todo']):
-                    if not id_ in [todo.id_ for todo in db.selected_day.linked_todos_as_list]:
-                        db.link_day_with_todo(db.selected_date, id_)
+            if 'filter' in postvars.keys():
+                redir_params += [('search', postvars['search'][0])]
+                redir_params += [('hide_chosen_tasks', int('hide_chosen_tasks' in postvars.keys()))]
+            else:
+                db.selected_date = postvars['date'][0]
+                todos_to_shrink = []
+                todos_to_delete = []
+                for todo in db.selected_day.linked_todos_as_list:
+                    if todo.visible and not ('chosen_todo' in postvars.keys() and todo.id_ in postvars['chosen_todo']):
+                        if len(todo.comment) > 0 or len(todo.day_tags) > 0 or not todo.is_effort_removable(db.selected_date):
+                            # print("DEBUG", len(todo.comment) > 0, len(todo.day_tags) > 0, todo.is_effort_removable(db.selected_date))
+                            raise PlomException('will not remove effort of preserve-worthy values')
+                        if len(todo.efforts) > 1:
+                            todos_to_shrink += [todo]
+                            # db.delete_effort(todo, db.selected_date)
+                        else:
+                            todos_to_delete += [todo]
+                            # db.delete_todo(todo.id_)
+                for todo in todos_to_shrink:
+                    db.delete_effort(todo, db.selected_date)
+                for todo in todos_to_delete:
+                    db.delete_todo(todo.id_)
+                if 'choose_task' in postvars.keys():
+                    for id_ in postvars['choose_task']:
+                        db.add_todo(task=db.tasks[id_], efforts={db.selected_date: None})
+                if 'choose_todo' in postvars.keys():
+                    for id_ in postvars['choose_todo']:
+                        todo = db.todos[id_]
+                        todo.efforts[db.selected_date] = None
+
+            # if 'choose_task' in postvars.keys():
+            #     for i, uuid in enumerate(postvars['choose_task']):
+            #          if not uuid in db.selected_day.todos.keys():
+            #             # task = db.tasks[uuid]
+            #              db.update_todo_mini(uuid, db.selected_date, None, False, 1.0)
+            # if 'choose_todo' in postvars.keys():
+            #     for i, id_ in enumerate(postvars['choose_todo']):
+            #         if not id_ in [todo.id_ for todo in db.selected_day.linked_todos_as_list]:
+            #             db.link_day_with_todo(db.selected_date, id_)
 
         elif 'do_day' == site:
             if 'filter' in postvars.keys():
@@ -918,20 +1059,27 @@ class TodoHandler(PlomHandler):
         hide_unchosen = hide_done = False
         # return_to = params.get('return_to', [''])[0]
         return_to = params.get('return_to', '')
-        if site in {'day', 'do_day', 'new_day'}:
+        if site in {'do_day', 'new_day'}:
             selected_date = params.get_cookied('date')
+        if site in {'do_day', 'new_day', 'task'}:
+            t_filter_and = params.get_cookied_chain('t_and')
+            # t_filter_not = params.get_cookied_chain('t_not', ['deleted', 'cancelled'])
+            t_filter_not = params.get_cookied_chain('t_not')
         # if site in {'day','tasks', 'task', 'new_day'}:
         #     t_filter_and = get_param('t_and', chained=True)
         #     t_filter_not = get_param('t_not', chained=True)
-        if site in {'day', 'do_day'}:
+        if 'do_day' == site:
             # hide_unchosen = get_param('hide_unchosen', boolean=True)
             hide_done = params.get('hide_done', False) 
         db = TodoDB(config['prefix'], selected_date, t_filter_and, t_filter_not, hide_unchosen, hide_done)
-        if 'day' == site:
-            pass
-        elif 'do_day' == site:
+        if 'do_day' == site:
             sort_order = params.get_cookied('sort')
             page = db.show_do_day(sort_order)
+        elif 'new_day' == site:
+            sort_order = params.get_cookied('sort')
+            hide_chosen_tasks = params.get('hide_chosen_tasks', False)
+            search = params.get('search', '')
+            page = db.show_new_day(search, hide_chosen_tasks, sort_order)
         elif site == 'todo':
             todo_id = params.get('id')
             page = db.show_todo(todo_id, return_to)
@@ -944,15 +1092,13 @@ class TodoHandler(PlomHandler):
             # page = db.show_todo(task_uuid, todo_date, return_to)
         elif 'task' == site:
             id_ = params.get('id')
-            page = db.show_task(id_, return_to)
+            search = params.get('search', '')
+            page = db.show_task(id_, return_to, search)
         elif 'tasks' == site:
             expand_uuid = params.get('expand_uuid')
             page = db.show_tasks(expand_uuid)
         elif 'add_task' == site:
             page = db.show_task(None)
-        elif 'new_day' == site:
-            search = params.get('search', '')
-            page = db.new_day(search)
         elif 'unset_cookie' == site:
             page = 'no cookie to unset.'
             if len(cookie_db) > 0:
index 80a90fb4da267e71d8e9cece8de1683958f46d04..476459aedba30f407436579d096f028bfb60916a 100644 (file)
@@ -6,12 +6,10 @@ input { font-family: monospace; padding: 0em; margin: 0em; }
 </style>
 <body>
 tasks: <a href="tasks">list</a> <a href="add_task">add</a> | day:
-<a href="day?hide_unchosen=0&hide_done=0">choose tasks</a>
-<a href="day?hide_unchosen=1&hide_done=1">do tasks</a>
+<a href="new_day">new day</a>
 <a href="do_day">do day</a>
 | <a href="calendar">calendar</a>
 | <a href="unset_cookie">unset cookie</a>
-| <a href="new_day">NEW</a>
 <hr />
 {% block content %}
 {% endblock %}
index 1bfb88347cc4a75e27614f1c621400de003e5819..18399d78488e3a2dc00ca491adb6fdc984313e81 100644 (file)
@@ -19,7 +19,7 @@ to: <input name="end" {% if end_date %}value="{{ end_date }}"{% endif %} placeho
 {% for todo in day.linked_todos_as_list %}
 
 {% if todo.visible %}
-<tr><td class="checkbox">{% if todo.done and not "cancelled" in todo.tags%}✓{% else %}&nbsp;&nbsp;{% endif %}</td><td><a href="{{db.prefix}}/todo?id={{todo.id_}}">{% if "cancelled" in todo.tags %}<s>{% endif %}{% if "deadline" in todo.tags %}DEADLINE: {% endif %}{{ todo.title|e }}{%if "cancelled" in todo.tags%}</s>{% endif %}</a></td><td>{{ todo.comment|e }}</td></tr>
+<tr><td class="checkbox">{% if todo.done and not "cancelled" in todo.tags%}✓{% else %}&nbsp;&nbsp;{% endif %}</td><td><a href="todo?id={{todo.id_}}">{% if "cancelled" in todo.tags %}<s>{% endif %}{% if "deadline" in todo.tags %}DEADLINE: {% endif %}{{ todo.title|e }}{%if "cancelled" in todo.tags%}</s>{% endif %}</a></td><td>{{ todo.comment|e }}</td></tr>
 {% endif %}
 
 {% endfor %}
index 3f784ea8b69c789808d2583c20946412c5ae7be4..869cf54a8715fbef9a057182523e688d72cf6c8f 100644 (file)
@@ -1,37 +1,32 @@
-<p style="float: left; margin-right: 1em;">
-<input type="submit" value="filter">
-</p>
-<p>
 mandatory tags:
-{% for and_filter in db.t_filter_and %}
+{% for and_filter in filter_and %}
 <select name="t_and">
 <option></option>
-{% for tag in db.t_tags | sort %}
+{% for tag in tags | sort %}
 <option value="{{tag|e}}" {% if and_filter == tag %}selected{% endif %}>{{tag|e}}</option>
 {% endfor %}
 </select>
 {% endfor %}
 <select name="t_and">
 <option></option>
-{% for tag in db.t_tags | sort %}
+{% for tag in tags | sort %}
 <option value="{{tag|e}}">{{tag|e}}</option>
 {% endfor %}
 </select>
 <br />
 forbidden tags:
-{% for not_filter in db.t_filter_not %}
+{% for not_filter in filter_not %}
 <select name="t_not">
 <option></option>
-{% for tag in db.t_tags | sort %}
+{% for tag in tags | sort %}
 <option value="{{tag|e}}" {% if not_filter == tag %}selected{% endif %}>{{tag|e}}</option>
 {% endfor %}
 </select>
 {% endfor %}
 <select name="t_not">
 <option></option>
-{% for tag in db.t_tags | sort %}
+{% for tag in tags | sort %}
 <option value="{{tag|e}}">{{tag|e}}</option>
 {% endfor %}
 </select>
-</p>
 
index e752b2718a7e47e516366ae7c82fddbf510e9b2d..05a661193eecbc990c90c270439359fdd8aa4a4f 100644 (file)
@@ -8,10 +8,10 @@ input[type="text"] { width: 100% }
 textarea { width: 100% };
 {% endblock %}
 {% block content %}
-<form id="form_to_watch" action="{{action|e}}" method="POST">
+<form id="form_to_watch" action="task" method="POST">
 <h3>edit task</h3>
 <input type="hidden" name="id" value="{{ task.id_ }}" />
-<input type="hidden" name="referer" value="{{ referer }}" />
+<input type="hidden" name="return_to" value="{{ return_to }}" />
 <table>
 <tr><th>title</th><td class="input"><input name="title" type="text" value="{{ task.title|e }}" /><details><summary>history</summary><ul>{% for k,v in task.title_history.items() | sort(attribute='0', reverse=True) %}<li>{{ k }}: {{ v|e }}{% endfor %}</ul></details></td></tr>
 <tr><th></th><td><input type="checkbox" name="as_todo" {% if selected %}checked{% endif%}> selected for {{db.selected_date}}</td></tr>
@@ -25,26 +25,36 @@ textarea { width: 100% };
 add: <input name="joined_tags" type="text" value="" ><br />
 <details><summary>history</summary><ul>{% for k,v in task.tags_history.items() | sort(attribute='0', reverse=True) %}<li>{{ k }}: {{ v|e }}{% endfor %}</ul></details>
 </td></tr>
-<tr><th>links</th>
+<tr><th>children</th>
 <td>
-{% for other_task_id, other_task in db.tasks.items() | sort(attribute='1.title') %}
-{% if task.id_ != other_task_id and other_task.visible and other_task_id in task.links %}
-<input name="link_{{other_task_id}}" type="checkbox" checked /> <a href="{{db.prefix}}/task?id={{ other_task_id }}">{{ other_task.title|e }}</a><br />
-{% endif %}
+<table>
+{% for task in linked_tasks %}
+<tr>
+<td><input name="link_task" type="checkbox" value="{{task.id_}}" checked/></td>
+<td><a href="task?id={{task.id_}}">{{task.title}}</a></td>
+</tr>
 {% endfor %}
-{% for other_task_id, other_task in db.tasks.items() | sort(attribute='1.title') %}
-{% if task.id_ != other_task_id and other_task.visible and not other_task_id in task.links %}
-<input name="link_{{other_task_id}}" type="checkbox"/> <a href="{{db.prefix}}/task?id={{ other_task_id }}">{{ other_task.title|e }}</a><br />
-{% endif %}
+<tr>
+<th colspan=2>---</th>
+</tr>
+{% for task in filtered_tasks %}
+<tr>
+<td><input name="link_task" type="checkbox" value="{{task.id_}}"/></td>
+<td><a href="task?id={{task.id_}}">{{task.title}}</a></td>
+</tr>
 {% endfor %}
+</table>
 </td>
 </tr>
 </table>
 <input type="submit" value="update" />
 </form>
-<form action="{{action|e}}" method="POST">
-<input type="hidden" name="id" value="{{ task.id_ }}" />
+<form action="task" method="POST">
+<input type="hidden" name="id" value="{{task.id_}}" />
 {% include 'tagfilters.html' %}
+<br />
+search: <input name="search" value="{{search|e}}" />
+<input type="submit" name="filter" value="filter" />
 </form>
 {% include 'watch_form.html' %}
 {% endblock %}
index 09aaf452bb260db264624f58b8460113b43695ad..035c9496ddac666e9785c163e1b301e4f097e730 100644 (file)
@@ -45,6 +45,27 @@ textarea { width: 100% };
 add: <input name="joined_day_tags" type="text" value="" >
 </td>
 </tr>
+<tr><th>parent</th><td>{% if todo.parent %}<a href="todo?id={{todo.parent.id_}}">{{todo.parent.title}}</a>{% else %}–{% endif %}</td></tr>
+<tr><th>children</th>
+<td>
+<table>
+{% for todo in linked_todos %}
+<tr>
+<td><input name="link_child" type="checkbox" value="{{todo.id_}}" checked/></td>
+<td><a href="todo?id={{todo.id_}}">{{todo.title}}</a></td>
+</tr>
+{% endfor %}
+<tr>
+<th colspan=2>---</th>
+</tr>
+{% for todo in filtered_todos %}
+<tr>
+<td><input name="link_todo" type="checkbox" value="{{todo.id_}}"/></td>
+<td><a href="todo?id={{todo.id_}}">{{todo.title}}</a></td>
+</tr>
+{% endfor %}
+</table>
+</td>
 </table>
 <input type="submit" value="update" />
 <div style="text-align: right">