MarcSkovMadsen commited on
Commit
a79cff1
1 Parent(s): 2703250

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -94
app.py CHANGED
@@ -1,95 +1,82 @@
1
  import panel as pn
2
-
3
- pn.extension(sizing_mode="stretch_width", design="material")
4
-
5
- BUTTON_WIDTH = 125
6
-
7
- # We use intslider to avoid teaching users pn.rx. Is that a good thing?
8
- state_changed_count = pn.widgets.IntInput()
9
- tasks = pn.Column()
10
-
11
- def update_state_changed_count(*args):
12
- state_changed_count.value += 1
13
-
14
- def remove_task(task, *args):
15
- index = tasks.index(task)
16
- tasks.pop(index)
17
-
18
- def remove_all_tasks(*args):
19
- tasks.clear()
20
-
21
- def create_task(text):
22
- state = pn.widgets.Checkbox(align="center", sizing_mode="fixed")
23
- content = pn.pane.Markdown(text)
24
- remove = pn.widgets.Button(width=BUTTON_WIDTH, icon="trash", sizing_mode="fixed")
25
- task = pn.Row(state, content, remove, sizing_mode="stretch_width")
26
-
27
- pn.bind(remove_task, task, remove, watch=True)
28
- # We have to bind the below after the above!
29
- pn.bind(update_state_changed_count, state, remove, watch=True)
30
-
31
- return task
32
-
33
- def add_task(text, *args):
34
- if not text:
35
- return
36
-
37
- new_task = create_task(text)
38
- tasks.append(new_task)
39
-
40
- return tasks
41
-
42
- def get_state(*args):
43
- total_tasks = len(tasks)
44
- completed_tasks = sum(check[0].value for check in tasks)
45
- return f"{completed_tasks} of {total_tasks} tasks completed"
46
-
47
- def can_add(value_input):
48
- return not bool(value_input)
49
-
50
- def has_tasks(*args):
51
- return len(tasks) > 0
52
-
53
-
54
- add_task("Inspect the blades")
55
- add_task("Inspect the nacelle")
56
- add_task("Tighten the bolts")
57
-
58
- text_input = pn.widgets.TextInput(name="Task", placeholder="Enter a task")
59
-
60
- submit_task = pn.widgets.Button(
61
- name="Add",
62
- align="center",
63
- button_type="primary",
64
- width=BUTTON_WIDTH,
65
- sizing_mode="fixed",
66
- disabled=pn.bind(can_add, text_input.param.value_input)
67
- )
68
- clear = pn.widgets.Button(
69
- name="Remove All",
70
- button_type="primary",
71
- button_style="outline",
72
- width=BUTTON_WIDTH,
73
- sizing_mode="fixed",
74
- visible=pn.bind(has_tasks, state_changed_count)
75
- )
76
-
77
- def reset_text_input(*args):
78
- text_input.value = text_input.value_input = ""
79
-
80
- pn.bind(add_task, text_input, submit_task, watch=True)
81
- pn.bind(reset_text_input, text_input, submit_task, watch=True)
82
- pn.bind(remove_all_tasks, clear, watch=True)
83
- # We have to bind the below after the above!
84
- pn.bind(update_state_changed_count, text_input, submit_task, clear, watch=True)
85
-
86
- status_report = pn.bind(get_state, state_changed_count, tasks.param.objects)
87
-
88
- pn.Column(
89
- "## WTG Task List",
90
- status_report,
91
- pn.Row(text_input, submit_task),
92
- tasks,
93
- pn.Row(pn.Spacer(), clear),
94
- max_width=500,
95
- ).servable()
 
1
  import panel as pn
2
+ import param
3
+ import json
4
+
5
+ FORM_TEXT = """\
6
+ <h1>Join Newsletter</h1>
7
+
8
+ Get the latest updates and news about Panel.
9
+ """
10
+
11
+ FORM_ICON = """\
12
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"> <path d="M3 7a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10z"></path> <path d="M3 7l9 6l9 -6"></path> </svg>
13
+ """
14
+
15
+ class FormState(param.Parameterized):
16
+ name = param.String(default="", doc="The name of the user.")
17
+ email = param.String(default="", doc="The email of the user.")
18
+ message = param.String(default="", label="Message", doc="An optional message from the user")
19
+
20
+ is_not_valid = param.Boolean(default=False)
21
+ validation_errors = param.Dict()
22
+ validation_message = param.String()
23
+
24
+ def __init__(self, **params):
25
+ params["name"]=params.get("name", "")
26
+ super().__init__(**params)
27
+
28
+ def _validate(self):
29
+ errors = {}
30
+
31
+ if not self.name:
32
+ errors["name"] = "No *Name* entered."
33
+ if not self.email:
34
+ errors["email"] = "No *Email* entered."
35
+ elif not "@" in self.email or not "." in self.email:
36
+ errors["email"] = "Not a valid *Email*."
37
+
38
+ self.validation_errors=errors
39
+ self.is_not_valid = bool(errors)
40
+ self.validation_message = "**Error**. " + " ".join(errors.values())
41
+
42
+ def _to_dict(self):
43
+ return {
44
+ "name": self.name, "email": self.email, "message": self.message
45
+ }
46
+
47
+ def _reset_to_defaults(self):
48
+ self.param.update(name=self.param.name.default, email=self.param.email.default, message=self.param.message.default)
49
+
50
+ def submit(self, event):
51
+ self._validate()
52
+
53
+ if not self.validation_errors:
54
+ pn.state.notifications.success(f"Form submitted: {self._to_dict()}", duration=2000)
55
+ self._reset_to_defaults()
56
+
57
+
58
+
59
+ def create_form():
60
+ form_state = FormState()
61
+
62
+ header = pn.Row(
63
+ pn.pane.SVG(FORM_ICON, margin=0, height=80, sizing_mode="fixed"),
64
+ FORM_TEXT,
65
+ )
66
+
67
+ error_pane = pn.pane.Alert(object=form_state.param.validation_message, visible=form_state.param.is_not_valid, alert_type="danger", stylesheets=["p {margin-bottom: 0}"])
68
+
69
+ name_input = pn.widgets.TextInput.from_param(form_state.param.name, name="Name*", placeholder="User Name")
70
+ email_input = pn.widgets.TextInput.from_param(form_state.param.email, name="Email*", placeholder="Email Address")
71
+ message_input = pn.widgets.TextAreaInput.from_param(form_state.param["message"], placeholder="An optional message")
72
+
73
+ submit_button = pn.widgets.Button(name="Send", on_click=form_state.submit, button_type="primary")
74
+
75
+ return pn.Column(header, error_pane, name_input, email_input, message_input, submit_button, sizing_mode="fixed", width=500, styles={"margin": "auto"})
76
+
77
+
78
+
79
+ pn.extension(notifications=True, design="bootstrap", sizing_mode="stretch_width")
80
+
81
+ form = create_form()
82
+ form.servable()