@lowdefy/docs-content 0.0.0-experimental-20260710073520

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +20 -0
  3. package/content/actions/callapi.md +66 -0
  4. package/content/actions/callmethod.md +41 -0
  5. package/content/actions/copytoclipboard.md +32 -0
  6. package/content/actions/displaymessage.md +53 -0
  7. package/content/actions/downloadcsv.md +89 -0
  8. package/content/actions/fetch.md +50 -0
  9. package/content/actions/geolocationcurrentposition.md +56 -0
  10. package/content/actions/link.md +104 -0
  11. package/content/actions/login.md +85 -0
  12. package/content/actions/logout.md +56 -0
  13. package/content/actions/pdfmake.md +304 -0
  14. package/content/actions/request.md +67 -0
  15. package/content/actions/reset.md +27 -0
  16. package/content/actions/resetvalidation.md +85 -0
  17. package/content/actions/scrollto.md +85 -0
  18. package/content/actions/setdarkmode.md +62 -0
  19. package/content/actions/setfocus.md +33 -0
  20. package/content/actions/setglobal.md +63 -0
  21. package/content/actions/setlocale.md +69 -0
  22. package/content/actions/setstate.md +70 -0
  23. package/content/actions/throw.md +72 -0
  24. package/content/actions/validate.md +87 -0
  25. package/content/actions/wait.md +24 -0
  26. package/content/agents/agent-endpoint-tools.md +190 -0
  27. package/content/agents/agent-mcp-tools.md +124 -0
  28. package/content/agents/agent-multi-agent.md +136 -0
  29. package/content/agents/agent-properties.md +174 -0
  30. package/content/agents/agent-server-hooks.md +336 -0
  31. package/content/agents/agentchat.md +515 -0
  32. package/content/agents/agentconversations.md +148 -0
  33. package/content/concepts/ai-agent-docs.md +190 -0
  34. package/content/concepts/cli.md +213 -0
  35. package/content/concepts/connections-and-requests.md +7 -0
  36. package/content/concepts/custom-html.md +3 -0
  37. package/content/concepts/custom-styling.md +161 -0
  38. package/content/concepts/events-and-actions.md +271 -0
  39. package/content/concepts/hosting-files.md +18 -0
  40. package/content/concepts/i18n.md +320 -0
  41. package/content/concepts/keyboard-shortcuts.md +218 -0
  42. package/content/concepts/layout-overview.md +478 -0
  43. package/content/concepts/lists.md +144 -0
  44. package/content/concepts/logger.md +43 -0
  45. package/content/concepts/lowdefy-schema.md +365 -0
  46. package/content/concepts/menus.md +144 -0
  47. package/content/concepts/module-authoring.md +564 -0
  48. package/content/concepts/modules.md +338 -0
  49. package/content/concepts/operators.md +45 -0
  50. package/content/concepts/overview.md +19 -0
  51. package/content/concepts/references-and-templates.md +207 -0
  52. package/content/concepts/secrets.md +24 -0
  53. package/content/concepts/selectors.md +143 -0
  54. package/content/connections/amazonredshift.md +176 -0
  55. package/content/connections/anthropic.md +232 -0
  56. package/content/connections/awss3.md +313 -0
  57. package/content/connections/azureblobstorage.md +133 -0
  58. package/content/connections/elasticsearch.md +371 -0
  59. package/content/connections/google.md +228 -0
  60. package/content/connections/googlecloudstorage.md +139 -0
  61. package/content/connections/googlesheet.md +313 -0
  62. package/content/connections/knex.md +206 -0
  63. package/content/connections/mariadb.md +177 -0
  64. package/content/connections/mcp.md +134 -0
  65. package/content/connections/mongodb.md +739 -0
  66. package/content/connections/mssql.md +191 -0
  67. package/content/connections/mysql.md +192 -0
  68. package/content/connections/openai-connection.md +228 -0
  69. package/content/connections/postgresql.md +200 -0
  70. package/content/connections/redis.md +116 -0
  71. package/content/connections/sendgridmail.md +94 -0
  72. package/content/connections/smtp.md +149 -0
  73. package/content/connections/sqlite.md +187 -0
  74. package/content/connections/stripe.md +115 -0
  75. package/content/container-blocks/affix.md +413 -0
  76. package/content/container-blocks/alert.md +937 -0
  77. package/content/container-blocks/badge.md +1222 -0
  78. package/content/container-blocks/box.md +1453 -0
  79. package/content/container-blocks/card.md +1200 -0
  80. package/content/container-blocks/carousel.md +2247 -0
  81. package/content/container-blocks/collapse.md +1335 -0
  82. package/content/container-blocks/configprovider.md +1070 -0
  83. package/content/container-blocks/confirmmodal.md +1159 -0
  84. package/content/container-blocks/content.md +597 -0
  85. package/content/container-blocks/descriptions.md +870 -0
  86. package/content/container-blocks/drawer.md +1379 -0
  87. package/content/container-blocks/dropdownmenu.md +643 -0
  88. package/content/container-blocks/flex.md +1510 -0
  89. package/content/container-blocks/footer.md +380 -0
  90. package/content/container-blocks/googlemaps.md +546 -0
  91. package/content/container-blocks/googlemapsheatmap.md +607 -0
  92. package/content/container-blocks/googlemapsscript.md +61 -0
  93. package/content/container-blocks/header.md +302 -0
  94. package/content/container-blocks/label.md +739 -0
  95. package/content/container-blocks/layout.md +604 -0
  96. package/content/container-blocks/masonry.md +1090 -0
  97. package/content/container-blocks/mobilemenu.md +1244 -0
  98. package/content/container-blocks/modal.md +1180 -0
  99. package/content/container-blocks/pageheadermenu.md +614 -0
  100. package/content/container-blocks/pagesidebarlayout.md +438 -0
  101. package/content/container-blocks/pagesidermenu.md +651 -0
  102. package/content/container-blocks/popover.md +1421 -0
  103. package/content/container-blocks/result.md +972 -0
  104. package/content/container-blocks/sider.md +1064 -0
  105. package/content/container-blocks/span.md +747 -0
  106. package/content/container-blocks/spinner.md +267 -0
  107. package/content/container-blocks/splitter.md +1735 -0
  108. package/content/container-blocks/tabs.md +1718 -0
  109. package/content/container-blocks/tooltip.md +1274 -0
  110. package/content/container-blocks/watermark.md +515 -0
  111. package/content/controls/for.md +103 -0
  112. package/content/controls/if.md +107 -0
  113. package/content/controls/log.md +50 -0
  114. package/content/controls/parallel.md +71 -0
  115. package/content/controls/parallel_for.md +36 -0
  116. package/content/controls/reject.md +56 -0
  117. package/content/controls/return.md +66 -0
  118. package/content/controls/set_state.md +98 -0
  119. package/content/controls/switch.md +90 -0
  120. package/content/controls/throw.md +79 -0
  121. package/content/controls/try.md +88 -0
  122. package/content/deployment/docker.md +149 -0
  123. package/content/deployment/node-server.md +27 -0
  124. package/content/deployment/vercel.md +101 -0
  125. package/content/display-blocks/aggrid.md +1459 -0
  126. package/content/display-blocks/anchor.md +336 -0
  127. package/content/display-blocks/avatar.md +1154 -0
  128. package/content/display-blocks/breadcrumb.md +517 -0
  129. package/content/display-blocks/button.md +758 -0
  130. package/content/display-blocks/calendar.md +156 -0
  131. package/content/display-blocks/dangeroushtml.md +314 -0
  132. package/content/display-blocks/dangerousmarkdown.md +423 -0
  133. package/content/display-blocks/diffgit.md +44 -0
  134. package/content/display-blocks/difflist.md +225 -0
  135. package/content/display-blocks/diffsidebyside.md +56 -0
  136. package/content/display-blocks/difftimeline.md +94 -0
  137. package/content/display-blocks/divider.md +406 -0
  138. package/content/display-blocks/download.md +60 -0
  139. package/content/display-blocks/dropdownbutton.md +661 -0
  140. package/content/display-blocks/echart.md +418 -0
  141. package/content/display-blocks/floatbutton.md +545 -0
  142. package/content/display-blocks/html.md +311 -0
  143. package/content/display-blocks/icon.md +717 -0
  144. package/content/display-blocks/img.md +479 -0
  145. package/content/display-blocks/markdown.md +520 -0
  146. package/content/display-blocks/markdownwithcode.md +730 -0
  147. package/content/display-blocks/menu.md +1123 -0
  148. package/content/display-blocks/message.md +941 -0
  149. package/content/display-blocks/notification.md +1410 -0
  150. package/content/display-blocks/paragraph.md +643 -0
  151. package/content/display-blocks/progress.md +818 -0
  152. package/content/display-blocks/qrcode.md +519 -0
  153. package/content/display-blocks/s3download.md +240 -0
  154. package/content/display-blocks/search.md +360 -0
  155. package/content/display-blocks/skeleton.md +272 -0
  156. package/content/display-blocks/skeletonavatar.md +222 -0
  157. package/content/display-blocks/skeletonbutton.md +245 -0
  158. package/content/display-blocks/skeletoninput.md +223 -0
  159. package/content/display-blocks/skeletonparagraph.md +201 -0
  160. package/content/display-blocks/statistic.md +485 -0
  161. package/content/display-blocks/steps.md +585 -0
  162. package/content/display-blocks/tag.md +620 -0
  163. package/content/display-blocks/title.md +654 -0
  164. package/content/display-blocks/tour.md +2359 -0
  165. package/content/input-blocks/autocomplete.md +786 -0
  166. package/content/input-blocks/buttonselector.md +964 -0
  167. package/content/input-blocks/checkboxselector.md +765 -0
  168. package/content/input-blocks/checkboxswitch.md +497 -0
  169. package/content/input-blocks/colorselector.md +884 -0
  170. package/content/input-blocks/daterangeselector.md +777 -0
  171. package/content/input-blocks/dateselector.md +693 -0
  172. package/content/input-blocks/datetimeselector.md +791 -0
  173. package/content/input-blocks/inputgallery.md +528 -0
  174. package/content/input-blocks/monthselector.md +717 -0
  175. package/content/input-blocks/multipleselector.md +1337 -0
  176. package/content/input-blocks/numberinput.md +855 -0
  177. package/content/input-blocks/pagination.md +679 -0
  178. package/content/input-blocks/paragraphinput.md +1664 -0
  179. package/content/input-blocks/passwordinput.md +480 -0
  180. package/content/input-blocks/phonenumberinput.md +688 -0
  181. package/content/input-blocks/radioselector.md +820 -0
  182. package/content/input-blocks/ratingslider.md +684 -0
  183. package/content/input-blocks/s3uploadbutton.md +384 -0
  184. package/content/input-blocks/s3uploaddragger.md +305 -0
  185. package/content/input-blocks/s3uploadphoto.md +288 -0
  186. package/content/input-blocks/segmentedselector.md +782 -0
  187. package/content/input-blocks/selector.md +1162 -0
  188. package/content/input-blocks/switch.md +552 -0
  189. package/content/input-blocks/textarea.md +714 -0
  190. package/content/input-blocks/textinput.md +639 -0
  191. package/content/input-blocks/tiptapinput.md +226 -0
  192. package/content/input-blocks/tiptapmentioninput.md +471 -0
  193. package/content/input-blocks/titleinput.md +1094 -0
  194. package/content/input-blocks/treeinput.md +144 -0
  195. package/content/input-blocks/treemultipleselector.md +162 -0
  196. package/content/input-blocks/treeselector.md +185 -0
  197. package/content/input-blocks/upload.md +149 -0
  198. package/content/input-blocks/uploaddragger.md +85 -0
  199. package/content/input-blocks/uploadphoto.md +84 -0
  200. package/content/input-blocks/weekselector.md +630 -0
  201. package/content/list-blocks/controlledlist.md +498 -0
  202. package/content/list-blocks/list.md +529 -0
  203. package/content/list-blocks/listselector.md +301 -0
  204. package/content/list-blocks/masonrylist.md +230 -0
  205. package/content/migration/upgrade-guide.md +106 -0
  206. package/content/migration/v4-to-v5.md +589 -0
  207. package/content/migration/v5-to-v6.md +36 -0
  208. package/content/operators/_actions.md +58 -0
  209. package/content/operators/_and.md +76 -0
  210. package/content/operators/_api.md +254 -0
  211. package/content/operators/_app.md +114 -0
  212. package/content/operators/_args.md +65 -0
  213. package/content/operators/_array.md +331 -0
  214. package/content/operators/_base64.md +49 -0
  215. package/content/operators/_boolean.md +33 -0
  216. package/content/operators/_build.md +166 -0
  217. package/content/operators/_change_case.md +357 -0
  218. package/content/operators/_date.md +415 -0
  219. package/content/operators/_dayjs.md +128 -0
  220. package/content/operators/_diff.md +61 -0
  221. package/content/operators/_divide.md +32 -0
  222. package/content/operators/_eq.md +52 -0
  223. package/content/operators/_event.md +86 -0
  224. package/content/operators/_function.md +52 -0
  225. package/content/operators/_get.md +92 -0
  226. package/content/operators/_global.md +86 -0
  227. package/content/operators/_gt.md +50 -0
  228. package/content/operators/_gte.md +50 -0
  229. package/content/operators/_hash.md +112 -0
  230. package/content/operators/_if.md +30 -0
  231. package/content/operators/_if_none.md +47 -0
  232. package/content/operators/_index.md +48 -0
  233. package/content/operators/_input.md +86 -0
  234. package/content/operators/_intl.md +135 -0
  235. package/content/operators/_item.md +166 -0
  236. package/content/operators/_js.md +113 -0
  237. package/content/operators/_json.md +120 -0
  238. package/content/operators/_jsonata.md +152 -0
  239. package/content/operators/_locale.md +65 -0
  240. package/content/operators/_location.md +40 -0
  241. package/content/operators/_log.md +22 -0
  242. package/content/operators/_lt.md +50 -0
  243. package/content/operators/_lte.md +50 -0
  244. package/content/operators/_math.md +407 -0
  245. package/content/operators/_media.md +83 -0
  246. package/content/operators/_menu.md +62 -0
  247. package/content/operators/_module.md +340 -0
  248. package/content/operators/_mql.md +95 -0
  249. package/content/operators/_ne.md +62 -0
  250. package/content/operators/_not.md +33 -0
  251. package/content/operators/_number.md +159 -0
  252. package/content/operators/_nunjucks.md +117 -0
  253. package/content/operators/_object.md +253 -0
  254. package/content/operators/_operator.md +33 -0
  255. package/content/operators/_or.md +67 -0
  256. package/content/operators/_product.md +45 -0
  257. package/content/operators/_random.md +90 -0
  258. package/content/operators/_ref.md +80 -0
  259. package/content/operators/_regex.md +69 -0
  260. package/content/operators/_request.md +35 -0
  261. package/content/operators/_request_details.md +29 -0
  262. package/content/operators/_secret.md +56 -0
  263. package/content/operators/_state.md +134 -0
  264. package/content/operators/_step.md +98 -0
  265. package/content/operators/_string.md +327 -0
  266. package/content/operators/_subtract.md +24 -0
  267. package/content/operators/_sum.md +45 -0
  268. package/content/operators/_switch.md +37 -0
  269. package/content/operators/_t.md +96 -0
  270. package/content/operators/_theme.md +65 -0
  271. package/content/operators/_type.md +78 -0
  272. package/content/operators/_uri.md +49 -0
  273. package/content/operators/_url_query.md +92 -0
  274. package/content/operators/_user.md +154 -0
  275. package/content/operators/_uuid.md +118 -0
  276. package/content/operators/_var.md +88 -0
  277. package/content/operators/_yaml.md +96 -0
  278. package/content/other/introduction.md +39 -0
  279. package/content/other/next-auth-providers.md +3 -0
  280. package/content/other/updatesession.md +26 -0
  281. package/content/plugins/plugins-actions.md +80 -0
  282. package/content/plugins/plugins-connections.md +98 -0
  283. package/content/plugins/plugins-dev.md +138 -0
  284. package/content/plugins/plugins-introduction.md +29 -0
  285. package/content/plugins/plugins-operators.md +71 -0
  286. package/content/testing/e2e-auth.md +108 -0
  287. package/content/testing/e2e-configuration.md +107 -0
  288. package/content/testing/e2e-getting-started.md +96 -0
  289. package/content/testing/e2e-introduction.md +53 -0
  290. package/content/testing/e2e-mocking.md +155 -0
  291. package/content/testing/e2e-writing-tests.md +214 -0
  292. package/content/tutorial/tutorial-actions-operators.md +222 -0
  293. package/content/tutorial/tutorial-add-blocks.md +86 -0
  294. package/content/tutorial/tutorial-create-page.md +57 -0
  295. package/content/tutorial/tutorial-display-data-page.md +181 -0
  296. package/content/tutorial/tutorial-next-steps.md +53 -0
  297. package/content/tutorial/tutorial-requests-sql.md +22 -0
  298. package/content/tutorial/tutorial-start.md +71 -0
  299. package/content/user-authentication/auth-providers.md +15 -0
  300. package/content/user-authentication/login-and-logout.md +122 -0
  301. package/content/user-authentication/users-introduction.md +31 -0
  302. package/index.json +2281 -0
  303. package/package.json +34 -0
  304. package/scripts/extractAgentDocs.js +130 -0
@@ -0,0 +1,222 @@
1
+ # 4. Interactive pages with actions and operators
2
+
3
+ If you have been following along, you can continue with your current config. Else, you can find the config from the previous section [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/03-adding-blocks).
4
+
5
+ ## Configuring the reset button
6
+
7
+ The reset button should reset all the user's inputs. To do this, we can add a [Reset action](/Reset) to the reset button.
8
+
9
+ #### 4.1. Configure the reset button
10
+
11
+ Copy the following into the definition of the reset button:
12
+
13
+ ##### `new-ticket.yaml`
14
+ ```yaml
15
+ id: new-ticket
16
+ # ...
17
+ blocks:
18
+ - id: content_card
19
+ # ...
20
+ blocks:
21
+ - id: page_heading
22
+ # ...
23
+ # ...
24
+ # ...
25
+ - id: reset_button
26
+ type: Button
27
+ layout:
28
+ span: 12
29
+ properties:
30
+ title: Reset
31
+ block: true
32
+ icon: AiOutlineClear
33
+ ################ -------- Copy from here -------- ################
34
+ events:
35
+ onClick:
36
+ - id: reset
37
+ type: Reset
38
+ ################ -------- Copy to here ---------- ################
39
+ - id: submit_button
40
+ type: Button
41
+ # ...
42
+ ```
43
+
44
+ If you add some inputs into the form and click the reset button, those inputs should be cleared.
45
+
46
+ ### How it works
47
+
48
+ Blocks can define events, which they can trigger when certain events happen on the page. You can then define a array of actions, that are executed sequentially when a block triggers an event. The button triggers an event called `onClick` when it gets clicked. We can add an array of action definitions that will be executed when this action is fired. We only added one action, the [`Reset` action](/Reset), that resets the page state as it was when it first loaded.
49
+
50
+ ## Required fields
51
+
52
+ We should validate the form to make sure the user input data is clean for the app to work as expected. The `ticket_title` and `ticket_type` fields should be compulsory, and the user should not be able to submit the ticket if they are not completed.
53
+
54
+ #### 4.2. Mark fields as required
55
+
56
+ To make the fields required, add a required property to the input blocks like this:
57
+
58
+ ```yaml
59
+ - id: ticket_title
60
+ type: TextInput
61
+ required: true
62
+ properties:
63
+ title: Title
64
+ ```
65
+
66
+ A red asterisk should appear next to each input field, looking like this:
67
+
68
+ We can now add a [`Validate` action](/Validate) to the submit button. This will validate the inputs and give an error if any inputs are not filled in.
69
+
70
+ #### 4.3. Add a Validate action
71
+
72
+ Add the validate action like this:
73
+
74
+ ##### `new-ticket.yaml`
75
+ ```yaml
76
+ id: new-ticket
77
+ # ...
78
+ blocks:
79
+ - id: content_card
80
+ # ...
81
+ blocks:
82
+ - id: page_heading
83
+ # ...
84
+ # ...
85
+ # ...
86
+ - id: submit_button
87
+ type: Button
88
+ layout:
89
+ span: 12
90
+ properties:
91
+ title: Submit
92
+ block: true
93
+ color: primary
94
+ variant: solid
95
+ icon: AiOutlineSave
96
+ ################ -------- Copy from here -------- ################
97
+ events:
98
+ onClick:
99
+ - id: validate
100
+ type: Validate
101
+ ################ -------- Copy to here ---------- ################
102
+ ```
103
+
104
+ Now if we click the submit button and all our inputs aren't complete, a message pops up saying we have validation errors on the page. All the fields that have not been completed are highlighted in red.
105
+
106
+ The result should look and work like this. The examples in this tutorial are live versions of the tutorial app, so you can verify that they work like your own app.
107
+
108
+ Log a ticket
109
+
110
+ ### How it works
111
+
112
+ The [Validate action](/Validate) we added to the submit button evaluates all the input blocks on the page, and gives an error if any of them fail the validation. This will also stop the execution of any actions after that action. For example, the app won't insert the data into our database if a Request action is used after a failing Validate action. The first time a Validate action is called on a page it sets a flag that tells all the input blocks to show their validation errors.
113
+
114
+ ## Hiding blocks
115
+
116
+ We would like to ask the user if they had purchased the product within the last month, for which they are formulating a complaint. To do this, we will add a input block with a `visible` property. This property expects a boolean value. In Lowdefy, we can make use of [operators](/operators) to evaluate logic. We'll use the [`_eq`](/_eq) operator to test if the ticket type is equal to `Complaint`.
117
+
118
+ #### 4.4. Add a block with a visible condition
119
+
120
+ Add the following [`ButtonSelector`](/ButtonSelector) to your app.
121
+
122
+ ##### `pages/new-ticket.yaml`
123
+ ```yaml
124
+ id: new-ticket
125
+ # ...
126
+ blocks:
127
+ - id: content_card
128
+ # ...
129
+ blocks:
130
+ # ...
131
+ - id: ticket_description
132
+ type: TextArea
133
+ properties:
134
+ title: Description
135
+ ################ -------- Copy from here -------- ################
136
+ - id: purchase_in_last_month
137
+ type: ButtonSelector
138
+ visible: # Test if block should be visible to the user
139
+ _eq: # Equals operator
140
+ - _state: ticket_type # Get the ticket_type value from state.
141
+ - Complaint
142
+ properties:
143
+ title: Did you purchase this product within the last month?
144
+ label:
145
+ colon: false # Hide the label colon
146
+ options:
147
+ - Yes
148
+ - No
149
+ ################ -------- Copy to here ---------- ################
150
+ - id: reset_button
151
+ type: Button
152
+ ```
153
+
154
+ If you select the "Complaint" ticket type, the selector confirming if you purchased the product within the last month should appear.
155
+
156
+ ### How it works
157
+
158
+ If the visible field value is `false`, the block won't be rendered. To change this value while our app is running, we use an operator. [Operators](/operators) evaluate every time something in the app changes, like when a user provides an input.
159
+
160
+ We used the [`_eq`](/_eq) operator to check the ticket type is equal to 'Complaint'.
161
+
162
+ To get the value of the `ticket_type` input, we use the [`_state`](/_state) operator. This get a value from the page's [`state`](/page-and-app-state). The page `state` is an object to temporary store page data. All inputs automatically write their values to `state` under the object key of the block `id`, and you can also set values to the page `state` by using the [`SetState`](/SetState) action.
163
+
164
+ ## Validation rules
165
+
166
+ We would like to add a validation rule on the `purchase_in_last_month` block to warn users that the product that they have purchased may not be eligible for replacement.
167
+
168
+ #### 4.5. Add a validation rule
169
+
170
+ Add the following to your app
171
+ ##### `pages/new-ticket.yaml`
172
+ ```yaml
173
+ id: new-ticket
174
+ # ...
175
+ blocks:
176
+ - id: content_card
177
+ # ...
178
+ blocks:
179
+ # ...
180
+ - id: purchase_in_last_month
181
+ type: ButtonSelector
182
+ visible: # Test if block should be visible to the user
183
+ _eq: # Equals operator
184
+ - _state: ticket_type # Get the ticket_type value from state.
185
+ - Complaint
186
+ ################ ------- Copy from here -------- ################
187
+ validate:
188
+ # Show a warning that shows before validate is called
189
+ # and does not block Validate action.
190
+ - status: warning
191
+ message: If you have had the product for over a month, we may not be able to replace it.
192
+ pass:
193
+ _eq:
194
+ - _state: confirm_restart
195
+ - Yes
196
+ ################ -------- Copy to here ---------- ################
197
+ properties:
198
+ title: Did you purchase this product within the last month?
199
+ label:
200
+ colon: false # Hide the label colon
201
+ options:
202
+ - Yes
203
+ - No
204
+ ```
205
+
206
+ Your app should now show a warning message if `purchase_in_last_month` is not yes.
207
+
208
+ ### How it works
209
+
210
+ The `validate` field contains an array of validation rules that can be evaluated using operators.
211
+
212
+ If the pass field receives `true`, the rule passes and nothing happens. If the rule fails and the status is error, the `Validate` action will fail, like it did for required fields. If the status is warning, a warning will be shown to the user, but the `Validate` action will still pass.
213
+
214
+ Your final new ticket page should look and work like this:
215
+
216
+ Log a ticket
217
+
218
+ > You can find the final configuration files for this section [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/04-interactive-pages).
219
+
220
+ ## Up next
221
+
222
+ Our app doesn't save the form data anywhere when the submit button is clicked. In the next section we will set up a connection and a request to save the data in a local SQLite database.
@@ -0,0 +1,86 @@
1
+ # 3. Adding blocks
2
+
3
+ We would like to add an input form with the following fields:
4
+
5
+ - A title for the ticket.
6
+ - The type of ticket. This should be a selection from a list of types.
7
+ - A description of the ticket.
8
+
9
+ There should also be submit and reset buttons at the bottom of the page.
10
+
11
+ #### 3.1. Add some input blocks
12
+
13
+ Copy the following blocks and add them in the card's blocks array.
14
+
15
+ ###### `new-ticket.yaml`
16
+ ```yaml
17
+ id: new-ticket
18
+ # ...
19
+ blocks:
20
+ - id: content_card
21
+ # ...
22
+ blocks:
23
+ - id: page_heading
24
+ type: Title
25
+ properties:
26
+ content: Log a ticket # Change the title on the page.
27
+ level: 3 # Make the title a little smaller (an html `<h3>`).
28
+ ################ ------- Copy from here -------- ################
29
+ - id: ticket_title
30
+ type: TextInput
31
+ properties:
32
+ title: Title
33
+ - id: ticket_type
34
+ type: ButtonSelector
35
+ properties:
36
+ title: Ticket type
37
+ options: # Set the allowed options
38
+ - Suggestion
39
+ - Complaint
40
+ - Question
41
+ - id: ticket_description
42
+ type: TextArea
43
+ properties:
44
+ title: Description
45
+ - id: reset_button
46
+ type: Button
47
+ layout:
48
+ span: 12 # Set the size of the button (span 12 of 24 columns)
49
+ properties:
50
+ title: Reset
51
+ block: true # Make the button fill all the space available to it
52
+ type: default # Make the button a plain button
53
+ icon: AiOutlineClear
54
+ - id: submit_button
55
+ type: Button
56
+ layout:
57
+ span: 12
58
+ properties:
59
+ title: Submit
60
+ block: true
61
+ type: primary # Make the button a primary button with color
62
+ icon: AiOutlineSave
63
+ ################ -------- Copy to here ---------- ################
64
+ ```
65
+
66
+ Your new-ticket page should look something like this:
67
+
68
+ Log a ticket
69
+
70
+ > If you would like to see how your config should look at this point, you can find it [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/03-adding-blocks).
71
+
72
+ ### What happened
73
+
74
+ We added 3 form input blocks to the page. For each of those blocks, we set the `title` property, and for the ticket type selector we set a list of ticket types to the `options` property.
75
+
76
+ We also added reset button and submit button. We set a few more properties on the buttons to set their layout and appearance.
77
+
78
+ ### How it works
79
+
80
+ Lowdefy apps are made from blocks. These blocks can be the page layout with header and menu, a piece of text, a chart or table, tabs or even a popup message or icon. You specify which block is rendered with the `type` field. There are 4 block categories, namely display, input, container, and list.
81
+
82
+ All blocks need to have an `id` that identifies the block. Blocks of category input and list use this `id` as the object key to represent a value in page state, but more on this later.
83
+
84
+ ### Up next
85
+
86
+ Currently our form doesn't do very much. In the next section we will use [actions](/events-and-actions) and [operators](/operators) to make it more interactive.
@@ -0,0 +1,57 @@
1
+ # 2. Creating a page
2
+
3
+ > Indentation is important
4
+
5
+ #### 2.3. Navigate to the new page
6
+
7
+ Your browser should reload, and you should see a link in the header menu to the booking page. If you click on that link it should take you to a page that looks like this:
8
+
9
+ Log a ticket
10
+
11
+ If you click on the link in the menu, you should see that your browser path (the part after `localhost:3000` or `example.com`) changes from `welcome` to `new-ticket`.
12
+
13
+ ### What happened
14
+
15
+ - We created a new page with id `new-ticket`.
16
+ - We used the [`_ref` operator](/_ref) to reference configuration in another file.
17
+ - That page can now be found at the `/new-ticket` route.
18
+ - A link to that page was created in the menu. These links are in the order of the pages.
19
+
20
+ ## Menus
21
+
22
+ A menu is created by default from all the pages in your app, in the order that they appear in the pages array. Often more control is needed over the menu. You might want to group menu items into different groups, change the title, exclude a page or add an icon. To do this, we can define a menu in the `menus` section of the `lowdefy.yaml` file.
23
+
24
+ #### 2.4 - Add the menu configuration
25
+
26
+ Copy the following and add it to your `lowdefy.yaml` file just before the pages section:
27
+
28
+ ```yaml
29
+ ################ -------- Copy from here -------- ################
30
+ menus:
31
+ - id: default
32
+ links:
33
+ - id: new-ticket
34
+ type: MenuLink
35
+ properties:
36
+ icon: AiOutlineAlert
37
+ title: New ticket
38
+ pageId: new-ticket
39
+ - id: welcome
40
+ type: MenuLink
41
+ properties:
42
+ icon: AiOutlineHome
43
+ title: Home
44
+ pageId: welcome
45
+ ################ -------- Copy to here ---------- ################
46
+ pages:
47
+ - _ref: new-ticket.yaml
48
+ # ...
49
+ ```
50
+
51
+ The menu links will now have icons and titles.
52
+
53
+ > If you would like to see how your config should look at this point, you can find it [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/02-creating-a-page).
54
+
55
+ ### Up next
56
+
57
+ In the next section we will add some more blocks to our page to create a form to capture the ticket data.
@@ -0,0 +1,181 @@
1
+ # 7. Display ticket data
2
+
3
+ If you have been following along, you can continue with your current config. Else, you can find the config from the previous section [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/06-requests-sql).
4
+
5
+ In this section we will add a page with a table to view the tickets that have been saved to our database.
6
+
7
+ We will make use of the concepts shown throughout the previous steps of this tutorial. If you would like to skip this, the final config can be found [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/07-display-data) and you can move on to [Next Steps](/tutorial-next-steps).
8
+
9
+ #### 7.1. Create `view-tickets.yaml`
10
+
11
+ Create a new YAML file in the project directory (the same directory as the `lowdefy.yaml` file) called `view-tickets.yaml`.
12
+
13
+ In this file we will add an `AgGridBalham` table block, using [Ag-Grid](https://www.ag-grid.com/), that will be used to display the tickets that are currently in our SQLite table.
14
+
15
+ We shall start with the basic page structure, as follows:
16
+
17
+ ```yaml
18
+ id: view-tickets
19
+ type: PageHeaderMenu
20
+
21
+ properties:
22
+ title: View tickets # The title in the browser tab.
23
+ layout:
24
+ justify: center # Center the contents of the page.
25
+ blocks:
26
+ - id: content_card
27
+ type: Card
28
+ layout:
29
+ size: 1000 # Set the size of the card so it does not fill the full screen.
30
+ gap: 28 # Make a 28px gap between all blocks in this card.
31
+ blocks:
32
+ - id: page_heading
33
+ type: Title
34
+ properties:
35
+ content: View Tickets # Change the title on the page.
36
+ level: 3 # Make the title a little smaller (an html `<h3>`).
37
+ ```
38
+
39
+ #### 7.2. Add request to `view-tickets.yaml`
40
+
41
+ Next we shall add a request to fetch the tickets currently in the tickets table in the SQLite database. To do this, we shall create a `fetch_tickets` request and call it when the page is mounted.
42
+
43
+ ```yaml
44
+ id: view-tickets
45
+ type: PageHeaderMenu
46
+
47
+ ################ -------- Copy from here -------- ################
48
+ requests:
49
+ - id: fetch_tickets
50
+ type: KnexRaw
51
+ connectionId: knex
52
+ properties:
53
+ query: SELECT * FROM "tickets"
54
+
55
+ events:
56
+ onMount:
57
+ - id: fetch_tickets
58
+ type: Request
59
+ params: fetch_tickets
60
+ ################ -------- Copy to here -------- ################
61
+
62
+ properties:
63
+ title: View tickets # The title in the browser tab.
64
+ #...
65
+ ```
66
+
67
+ ### 7.3. Add an `AgGridBalham` block
68
+
69
+ We will add an `AgGridBalham` table block to our page to display the tickets that have been saved in the tickets table. We want to display five columns in our table; `ticket_title`, `created_date`, `ticket_type`, `product` and `ticket_description`.
70
+
71
+ The `rowData` used for our table will be the result from our `fetch_tickets` request and is accessed by making use of the [_request](/_request) operator.
72
+
73
+ In order to display the `created_date` in a more compact format, we will make use of the [_nunjucks](/_nunjucks) operator.
74
+
75
+ Add the following config to the `view-tickets.yaml` filename:
76
+
77
+ ```yaml
78
+ #...
79
+
80
+ blocks:
81
+ - id: page_heading
82
+ type: Title
83
+ properties:
84
+ content: View Tickets # Change the title on the page.
85
+ level: 3 # Make the title a little smaller (an html `<h3>`).
86
+
87
+ ################ -------- Copy from here -------- ################
88
+ - id: view_tickets_table
89
+ type: AgGridBalham
90
+ properties:
91
+ enableCellTextSelection: true
92
+ pagination: true
93
+ rowData:
94
+ _request: fetch_tickets
95
+ defaultColDef:
96
+ sortable: true
97
+ resizable: true
98
+ filter: true
99
+ columnDefs:
100
+ - headerName: Title
101
+ field: ticket_title
102
+ width: 200
103
+ filter: false
104
+ - headerName: Date Created
105
+ field: created_date
106
+ width: 140
107
+ cellRenderer:
108
+ _function:
109
+ __nunjucks:
110
+ template: |
111
+ {{ created_date | date('DD MMM YYYY') }}
112
+ on:
113
+ __args: 0.data
114
+ - headerName: Ticket Type
115
+ field: ticket_type
116
+ width: 150
117
+ filter: false
118
+ - headerName: Product
119
+ field: product
120
+ width: 200
121
+ filter: false
122
+ - headerName: Ticket Description
123
+ field: ticket_description
124
+ width: 250
125
+ filter: false
126
+ ################ -------- Copy to here -------- ################
127
+ ```
128
+
129
+ #### 7.4. Update `lowdefy.yaml`
130
+
131
+ Last step is to add the page to our app. In order to do this, we need to update the `lowdefy.yaml`.
132
+
133
+ Change the `lowdefy.yaml` to include `view-tickets.yaml` in the list of pages and the list of menu items:
134
+
135
+ ```lowdefy.yaml
136
+ #...
137
+ menus:
138
+ - id: default
139
+ links:
140
+ - id: welcome
141
+ type: MenuLink
142
+ properties:
143
+ icon: AiOutlineHome
144
+ title: Home
145
+ pageId: welcome
146
+ - id: new-ticket
147
+ type: MenuLink
148
+ properties:
149
+ icon: AiOutlineAlert
150
+ title: New ticket
151
+ pageId: new-ticket
152
+ ################ -------- Copy from here -------- ################
153
+ - id: view-tickets
154
+ type: MenuLink
155
+ properties:
156
+ icon: AiOutlineDatabase
157
+ title: View tickets
158
+ pageId: view-tickets
159
+ ############### -------- Copy to here ---------- ################
160
+
161
+ pages:
162
+ - _ref: new-ticket.yaml
163
+ ################ -------- Copy from here -------- ################
164
+ - _ref: view-tickets.yaml
165
+ ################ -------- Copy to here ---------- ################
166
+ - id: welcome
167
+ type: PageHeaderMenu
168
+ properties:
169
+ title: Welcome
170
+ # ...
171
+ ```
172
+
173
+ ### What happened
174
+
175
+ We added a new page in order to view the tickets saved in our database.
176
+
177
+ We defined a `KnexRaw` request, to read the ticket data from our SQLite database, and called that request when the page was mounted.
178
+
179
+ The data from this request was then displayed in an `AgGridBalham` table block, which we added to the new page.
180
+
181
+ Lastly, we linked this new page to our app.
@@ -0,0 +1,53 @@
1
+ # Next steps
2
+
3
+ Congratulations! You have completed the tutorial and built a basic functioning app, which can request data from an API, as well as validate and save user input to a database.
4
+
5
+ Next, consider joining the Lowdefy community, and exploring Lowdefy in more detail.
6
+
7
+ ### Join the community
8
+
9
+ Whether Get help with any problems you have, share you ideas, ask questions, and show off the apps you have built, join and hlep us grow the Lowdefy community.
10
+
11
+ - [Github Discussions](https://github.com/lowdefy/lowdefy/discussions)
12
+ - [Lowdefy Discord](https://discord.gg/QQY9eJ7A2D)
13
+ - [Lowdefy Twitter](https://twitter.com/lowdefy)
14
+
15
+ ### Understand the concepts
16
+
17
+ To get a more in-depth understanding of how everything works, you can start [here](/overview).
18
+
19
+ ### Play with blocks
20
+
21
+ The docs are interactive, so you can adjust a block's properties and see how that affects the block in real time. Go look at what you can do with a [`Button`](/Button).
22
+
23
+ ### Look at an example app
24
+
25
+ One of the best ways to learn is by doing things for yourself. You can clone an example app that is similar to something you want to build, and start experimenting from there.
26
+
27
+ ###### CRUD example
28
+
29
+ This example shows patterns to implement a data admin app which allows users to view, create new, edit and delete data records.
30
+
31
+ - [Example demo.](https://example-crud.lowdefy.com)
32
+ - [App source code.](https://github.com/lowdefy/lowdefy-example-crud)
33
+
34
+ ###### Survey example
35
+
36
+ This is a simple customer survey example built with Lowdefy. With this example we demonstrate how simple it is to define a public webform and thank you page in Lowdefy.
37
+
38
+ - [Example demo.](https://example-survey.lowdefy.com)
39
+ - [App source code.](https://github.com/lowdefy/lowdefy-example-survey)
40
+
41
+ ###### Case management (ticketing) system example
42
+
43
+ This example focuses on building a rich UI for a hypothetical case management app, in a customer relations setting.
44
+
45
+ - [Example demo.](https://example-case-management.lowdefy.com)
46
+ - [App source code.](https://github.com/lowdefy/lowdefy-example-case-management)
47
+
48
+ ###### Movies reporting example
49
+
50
+ This example demonstrates useful patterns for building a BI report/dashboard pages in Lowdefy. It connects to a MongoDB database with the Atlas Movies sample dataset pre-loaded.
51
+
52
+ - [Example demo.](https://example-reporting.lowdefy.com)
53
+ - [App source code.](https://github.com/lowdefy/lowdefy-example-reporting)
@@ -0,0 +1,22 @@
1
+ # 6. Saving data to SQL
2
+
3
+ If you have been following along, you can continue with your current config. Else, you can find the config from the previous section [here](https://github.com/lowdefy/lowdefy-example-tutorial/tree/main/05-requests-api).
4
+
5
+ We will now add a `SQLite` [connection and request](/connections-and-requests) to our app to save user tickets to the SQLite database file.
6
+
7
+ ## Configuring the SQLite Connection and Request
8
+
9
+ We will be saving the data from our form in a SQLite database, using the [`Knex`](/SQLite) connection. To do this, we will first need to set up an SQLite database as described in the following steps:
10
+
11
+ #### 6.1. Setting up the SQLite database
12
+
13
+ We will make use of an SQLite database with a table called `tickets`, that has the following columns:
14
+
15
+ - ticket_title
16
+ - ticket_type
17
+ - ticket_description
18
+ - product
19
+ - purchase_in_last_month
20
+ - created_date
21
+
22
+ The database used in this tutorial can be downloaded <a href="/tutorial/tutorial_db.sqlite" download>here</a>.