date = self.params.get_str('date', todays_date())
top_todos = [t for t in Todo.by_date(self.conn, date) if not t.parents]
- seen_todos: set[int] = set()
- seen_conditions: set[int] = set()
- todo_trees = [t.get_step_tree(seen_todos, seen_conditions)
- for t in top_todos]
+ todo_trees = [t.get_undone_steps_tree() for t in top_todos]
+ done_trees = []
+ for t in top_todos:
+ done_trees += t.get_done_steps_tree()
condition_listings: list[ConditionListing] = []
for cond in Condition.all(self.conn):
enablers = Todo.enablers_for_at(self.conn, cond, date)
condition_listings += [ConditionListing(cond, enablers, disablers)]
return {'day': Day.by_id(self.conn, date, create=True),
'todo_trees': todo_trees,
+ 'done_trees': done_trees,
'processes': Process.all(self.conn),
'condition_listings': condition_listings}
todo.adopt_from(existing_todos)
todo.make_missing_children(self.conn)
todo.save(self.conn)
+ for todo_id in self.form_data.get_all_int('done'):
+ todo = Todo.by_id(self.conn, todo_id)
+ todo.is_done = True
+ todo.save(self.conn)
return f'/day?date={date}'
def do_POST_todo(self) -> str:
is_todo: bool
children: list[TodoStepsNode]
seen: bool
+ hide: bool
class Todo(BaseModel[int], ConditionsRelations):
else:
seen = step.id_ in seen_conditions
seen_conditions.add(step.id_)
- return TodoStepsNode(step, is_todo, children, seen)
+ return TodoStepsNode(step, is_todo, children, seen, False)
node = make_node(self)
return node
+ def get_undone_steps_tree(self) -> TodoStepsNode:
+ """Return tree of depended-on undone Todos and Conditions."""
+
+ def walk_tree(node: TodoStepsNode) -> None:
+ if isinstance(node.item, Todo) and node.item.is_done:
+ node.hide = True
+ for child in node.children:
+ walk_tree(child)
+
+ seen_todos: set[int] = set()
+ seen_conditions: set[int] = set()
+ step_tree = self.get_step_tree(seen_todos, seen_conditions)
+ walk_tree(step_tree)
+ return step_tree
+
+ def get_done_steps_tree(self) -> list[TodoStepsNode]:
+ """Return tree of depended-on done Todos."""
+
+ def make_nodes(node: TodoStepsNode) -> list[TodoStepsNode]:
+ children: list[TodoStepsNode] = []
+ if not isinstance(node.item, Todo):
+ return children
+ for child in node.children:
+ children += make_nodes(child)
+ if node.item.is_done:
+ node.children = children
+ return [node]
+ return children
+
+ seen_todos: set[int] = set()
+ seen_conditions: set[int] = set()
+ step_tree = self.get_step_tree(seen_todos, seen_conditions)
+ nodes = make_nodes(step_tree)
+ return nodes
+
def add_child(self, child: Todo) -> None:
"""Add child to self.children, avoid recursion, update parenthoods."""
body {
font-family: monospace;
}
-ul {
- list-style-type: none;
-}
input.btn-harmless {
color: green;
}
{% extends 'base.html' %}
-{% macro node_with_children(node, indent) %}
-<li>{% for i in range(indent) %}+{% endfor %}
+
+{% macro show_node(node, indent) %}
{% if node.is_todo %}
-{% if not node.item.is_doable %}<del>{% endif %}[{% if node.item.is_done %}x{% else %} {% endif %}]{% if not node.item.is_doable %}</del>{% endif %}
+{% for i in range(indent) %} {% endfor %} +
{% if node.seen %}({% else %}{% endif %}<a href="todo?id={{node.item.id_}}">{{node.item.process.title.newest|e}}</a>{% if node.seen %}){% else %}{% endif %}
{% else %}
-< {% if node.seen %}({% else %}{% endif %}<a href="condition?id={{node.item.id_}}">{{node.item.title.newest|e}}</a>{% if node.seen %}){% else %}{% endif %}
+{% for i in range(indent) %} {% endfor %} +
+{% if node.seen %}({% else %}{% endif %}<a href="condition?id={{node.item.id_}}">{{node.item.title.newest|e}}</a>{% if node.seen %}){% else %}{% endif %}
+{% endif %}
+{% endmacro %}
+
+
+{% macro undone_with_children(node, indent) %}
+{% if not node.hide %}
+<tr>
+<td>
+{% if node.is_todo %}
+<input name="done" value="{{node.item.id_}}" type="checkbox" {% if node.seen or not node.item.is_doable %}disabled{% endif %} {% if node.item.is_done %} checked {% endif %} />
+{% endif %}
+</td>
+<td>
+{{ show_node(node, indent) }}
+</td>
+</tr>
+{% endif %}
+{% for child in node.children %}
+{{ undone_with_children(child, indent+1) }}
+{% endfor %}
+{% endmacro %}
+
+
+{% macro done_with_children(node, indent) %}
+{% if not node.hide %}
+<tr>
+<td>
+{{ show_node(node, indent) }}
+</td>
+</tr>
{% endif %}
{% for child in node.children %}
-{{ node_with_children(child, indent+1) }}
+{{ done_with_children(child, indent+1) }}
{% endfor %}
{% endmacro %}
+
{% block content %}
<h3>{{day.date}} / {{day.weekday}}</h3>
<p>
<option value="{{process.id_}}">{{process.title.newest|e}}</option>
{% endfor %}
</datalist>
-</form>
<h4>conditions</h4>
+<ul>
{% for node in condition_listings %}
<li>[{% if node.condition.is_active %}x{% else %} {% endif %}] <a href="condition?id={{node.condition.id_}}">{{node.condition.title.newest|e}}</a>
-<ul>
-{% for enabler in node.enablers %}
-<li>< {{enabler.process.title.newest|e}}</li>
+({% for enabler in node.enablers %}
+< {{enabler.process.title.newest|e}};
{% endfor %}
{% for disabler in node.disablers %}
-<li>! {{disabler.process.title.newest|e}}</li>
+! {{disabler.process.title.newest|e}};
+{% endfor %})
{% endfor %}
</ul>
-</li>
-{% endfor %}
-<h4>todos</h4>
-<ul>
+<h4>to do</h4>
+<table>
{% for node in todo_trees %}
-{{ node_with_children(node, 0) }}
+{{ undone_with_children(node, indent=0) }}
{% endfor %}
-</ul>
+</table>
+<h4>done</h4>
+<table>
+{% for node in done_trees %}
+{{ done_with_children(node, indent=0) }}
+{% endfor %}
+</table>
+</form>
{% endblock %}
todo_1.save(self.db_conn)
assert isinstance(todo_1.id_, int)
# test minimum
- node_0 = TodoStepsNode(todo_1, True, [], False)
+ node_0 = TodoStepsNode(todo_1, True, [], False, False)
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
# test non_emtpy seen_todo does something
node_0.seen = True
todo_2.save(self.db_conn)
assert isinstance(todo_2.id_, int)
todo_1.add_child(todo_2)
- node_2 = TodoStepsNode(todo_2, True, [], False)
+ node_2 = TodoStepsNode(todo_2, True, [], False, False)
node_0.children = [node_2]
node_0.seen = False
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
todo_3.save(self.db_conn)
assert isinstance(todo_3.id_, int)
todo_2.add_child(todo_3)
- node_3 = TodoStepsNode(todo_3, True, [], False)
+ node_3 = TodoStepsNode(todo_3, True, [], False, False)
node_2.children = [node_3]
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
# test same todo can be child-ed multiple times at different locations
todo_1.add_child(todo_3)
- node_4 = TodoStepsNode(todo_3, True, [], True)
+ node_4 = TodoStepsNode(todo_3, True, [], True, False)
node_0.children += [node_4]
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
# test condition shows up
todo_1.set_conditions(self.db_conn, [self.cond1.id_])
- node_5 = TodoStepsNode(self.cond1, False, [], False)
+ node_5 = TodoStepsNode(self.cond1, False, [], False, False)
node_0.children += [node_5]
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
# test second condition shows up
todo_2.set_conditions(self.db_conn, [self.cond2.id_])
- node_6 = TodoStepsNode(self.cond2, False, [], False)
+ node_6 = TodoStepsNode(self.cond2, False, [], False, False)
node_2.children += [node_6]
self.assertEqual(todo_1.get_step_tree(set(), set()), node_0)
# test second condition is not hidden if fulfilled by non-sibling