Py.Cafe

panel-org/

basic-todo

A todo app implemented using the basic, widget based approach

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import panel as pn

pn.extension(sizing_mode="stretch_width", design="material")

BUTTON_WIDTH = 125

state_changed_count = pn.widgets.IntInput()
tasks = pn.Column()

def update_state_changed_count(*args):
    state_changed_count.value += 1

def remove_task(task, *args):
    index = tasks.index(task)
    tasks.pop(index)

def remove_all_tasks(*args):
    tasks.clear()

def create_task(text):
    state = pn.widgets.Checkbox(align="center", sizing_mode="fixed")
    content = pn.pane.Markdown(text)
    remove = pn.widgets.Button(width=BUTTON_WIDTH, icon="trash", sizing_mode="fixed")
    task = pn.Row(state, content, remove, sizing_mode="stretch_width")

    pn.bind(remove_task, task, remove, watch=True)
    # We have to bind the below after the above!
    pn.bind(update_state_changed_count, state, remove, watch=True)

    return task

def add_task(text, *args):
    if not text:
        return

    new_task = create_task(text)
    tasks.append(new_task)

    return tasks

def get_state(*args):
    total_tasks = len(tasks)
    completed_tasks = sum(check[0].value for check in tasks)
    return f"{completed_tasks} of {total_tasks} tasks completed"

def can_add(value_input):
    return not bool(value_input)

def has_tasks(*args):
    return len(tasks) > 0


add_task("Inspect the blades")
add_task("Inspect the nacelle")
add_task("Tighten the bolts")

text_input = pn.widgets.TextInput(name="Task", placeholder="Enter a task")

submit_task = pn.widgets.Button(
    name="Add",
    align="center",
    button_type="primary",
    width=BUTTON_WIDTH,
    sizing_mode="fixed",
    disabled=pn.bind(can_add, text_input.param.value_input)
)
clear = pn.widgets.Button(
    name="Remove All",
    button_type="primary",
    button_style="outline",
    width=BUTTON_WIDTH,
    sizing_mode="fixed",
    visible=pn.bind(has_tasks, state_changed_count)
)

def reset_text_input(*args):
    text_input.value = text_input.value_input = ""

pn.bind(add_task, text_input, submit_task, watch=True)
pn.bind(reset_text_input, text_input, submit_task, watch=True)
pn.bind(remove_all_tasks, clear, watch=True)
# We have to bind the below after the above!
pn.bind(update_state_changed_count, text_input, submit_task, clear, watch=True)

status_report = pn.bind(get_state, state_changed_count, tasks.param.objects)

pn.Column(
    "## WTG Task List",
    status_report,
    pn.Row(text_input, submit_task),
    tasks,
    pn.Row(pn.Spacer(), clear),
    max_width=500,
).servable()