@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.
- package/LICENSE +201 -0
- package/README.md +20 -0
- package/content/actions/callapi.md +66 -0
- package/content/actions/callmethod.md +41 -0
- package/content/actions/copytoclipboard.md +32 -0
- package/content/actions/displaymessage.md +53 -0
- package/content/actions/downloadcsv.md +89 -0
- package/content/actions/fetch.md +50 -0
- package/content/actions/geolocationcurrentposition.md +56 -0
- package/content/actions/link.md +104 -0
- package/content/actions/login.md +85 -0
- package/content/actions/logout.md +56 -0
- package/content/actions/pdfmake.md +304 -0
- package/content/actions/request.md +67 -0
- package/content/actions/reset.md +27 -0
- package/content/actions/resetvalidation.md +85 -0
- package/content/actions/scrollto.md +85 -0
- package/content/actions/setdarkmode.md +62 -0
- package/content/actions/setfocus.md +33 -0
- package/content/actions/setglobal.md +63 -0
- package/content/actions/setlocale.md +69 -0
- package/content/actions/setstate.md +70 -0
- package/content/actions/throw.md +72 -0
- package/content/actions/validate.md +87 -0
- package/content/actions/wait.md +24 -0
- package/content/agents/agent-endpoint-tools.md +190 -0
- package/content/agents/agent-mcp-tools.md +124 -0
- package/content/agents/agent-multi-agent.md +136 -0
- package/content/agents/agent-properties.md +174 -0
- package/content/agents/agent-server-hooks.md +336 -0
- package/content/agents/agentchat.md +515 -0
- package/content/agents/agentconversations.md +148 -0
- package/content/concepts/ai-agent-docs.md +190 -0
- package/content/concepts/cli.md +213 -0
- package/content/concepts/connections-and-requests.md +7 -0
- package/content/concepts/custom-html.md +3 -0
- package/content/concepts/custom-styling.md +161 -0
- package/content/concepts/events-and-actions.md +271 -0
- package/content/concepts/hosting-files.md +18 -0
- package/content/concepts/i18n.md +320 -0
- package/content/concepts/keyboard-shortcuts.md +218 -0
- package/content/concepts/layout-overview.md +478 -0
- package/content/concepts/lists.md +144 -0
- package/content/concepts/logger.md +43 -0
- package/content/concepts/lowdefy-schema.md +365 -0
- package/content/concepts/menus.md +144 -0
- package/content/concepts/module-authoring.md +564 -0
- package/content/concepts/modules.md +338 -0
- package/content/concepts/operators.md +45 -0
- package/content/concepts/overview.md +19 -0
- package/content/concepts/references-and-templates.md +207 -0
- package/content/concepts/secrets.md +24 -0
- package/content/concepts/selectors.md +143 -0
- package/content/connections/amazonredshift.md +176 -0
- package/content/connections/anthropic.md +232 -0
- package/content/connections/awss3.md +313 -0
- package/content/connections/azureblobstorage.md +133 -0
- package/content/connections/elasticsearch.md +371 -0
- package/content/connections/google.md +228 -0
- package/content/connections/googlecloudstorage.md +139 -0
- package/content/connections/googlesheet.md +313 -0
- package/content/connections/knex.md +206 -0
- package/content/connections/mariadb.md +177 -0
- package/content/connections/mcp.md +134 -0
- package/content/connections/mongodb.md +739 -0
- package/content/connections/mssql.md +191 -0
- package/content/connections/mysql.md +192 -0
- package/content/connections/openai-connection.md +228 -0
- package/content/connections/postgresql.md +200 -0
- package/content/connections/redis.md +116 -0
- package/content/connections/sendgridmail.md +94 -0
- package/content/connections/smtp.md +149 -0
- package/content/connections/sqlite.md +187 -0
- package/content/connections/stripe.md +115 -0
- package/content/container-blocks/affix.md +413 -0
- package/content/container-blocks/alert.md +937 -0
- package/content/container-blocks/badge.md +1222 -0
- package/content/container-blocks/box.md +1453 -0
- package/content/container-blocks/card.md +1200 -0
- package/content/container-blocks/carousel.md +2247 -0
- package/content/container-blocks/collapse.md +1335 -0
- package/content/container-blocks/configprovider.md +1070 -0
- package/content/container-blocks/confirmmodal.md +1159 -0
- package/content/container-blocks/content.md +597 -0
- package/content/container-blocks/descriptions.md +870 -0
- package/content/container-blocks/drawer.md +1379 -0
- package/content/container-blocks/dropdownmenu.md +643 -0
- package/content/container-blocks/flex.md +1510 -0
- package/content/container-blocks/footer.md +380 -0
- package/content/container-blocks/googlemaps.md +546 -0
- package/content/container-blocks/googlemapsheatmap.md +607 -0
- package/content/container-blocks/googlemapsscript.md +61 -0
- package/content/container-blocks/header.md +302 -0
- package/content/container-blocks/label.md +739 -0
- package/content/container-blocks/layout.md +604 -0
- package/content/container-blocks/masonry.md +1090 -0
- package/content/container-blocks/mobilemenu.md +1244 -0
- package/content/container-blocks/modal.md +1180 -0
- package/content/container-blocks/pageheadermenu.md +614 -0
- package/content/container-blocks/pagesidebarlayout.md +438 -0
- package/content/container-blocks/pagesidermenu.md +651 -0
- package/content/container-blocks/popover.md +1421 -0
- package/content/container-blocks/result.md +972 -0
- package/content/container-blocks/sider.md +1064 -0
- package/content/container-blocks/span.md +747 -0
- package/content/container-blocks/spinner.md +267 -0
- package/content/container-blocks/splitter.md +1735 -0
- package/content/container-blocks/tabs.md +1718 -0
- package/content/container-blocks/tooltip.md +1274 -0
- package/content/container-blocks/watermark.md +515 -0
- package/content/controls/for.md +103 -0
- package/content/controls/if.md +107 -0
- package/content/controls/log.md +50 -0
- package/content/controls/parallel.md +71 -0
- package/content/controls/parallel_for.md +36 -0
- package/content/controls/reject.md +56 -0
- package/content/controls/return.md +66 -0
- package/content/controls/set_state.md +98 -0
- package/content/controls/switch.md +90 -0
- package/content/controls/throw.md +79 -0
- package/content/controls/try.md +88 -0
- package/content/deployment/docker.md +149 -0
- package/content/deployment/node-server.md +27 -0
- package/content/deployment/vercel.md +101 -0
- package/content/display-blocks/aggrid.md +1459 -0
- package/content/display-blocks/anchor.md +336 -0
- package/content/display-blocks/avatar.md +1154 -0
- package/content/display-blocks/breadcrumb.md +517 -0
- package/content/display-blocks/button.md +758 -0
- package/content/display-blocks/calendar.md +156 -0
- package/content/display-blocks/dangeroushtml.md +314 -0
- package/content/display-blocks/dangerousmarkdown.md +423 -0
- package/content/display-blocks/diffgit.md +44 -0
- package/content/display-blocks/difflist.md +225 -0
- package/content/display-blocks/diffsidebyside.md +56 -0
- package/content/display-blocks/difftimeline.md +94 -0
- package/content/display-blocks/divider.md +406 -0
- package/content/display-blocks/download.md +60 -0
- package/content/display-blocks/dropdownbutton.md +661 -0
- package/content/display-blocks/echart.md +418 -0
- package/content/display-blocks/floatbutton.md +545 -0
- package/content/display-blocks/html.md +311 -0
- package/content/display-blocks/icon.md +717 -0
- package/content/display-blocks/img.md +479 -0
- package/content/display-blocks/markdown.md +520 -0
- package/content/display-blocks/markdownwithcode.md +730 -0
- package/content/display-blocks/menu.md +1123 -0
- package/content/display-blocks/message.md +941 -0
- package/content/display-blocks/notification.md +1410 -0
- package/content/display-blocks/paragraph.md +643 -0
- package/content/display-blocks/progress.md +818 -0
- package/content/display-blocks/qrcode.md +519 -0
- package/content/display-blocks/s3download.md +240 -0
- package/content/display-blocks/search.md +360 -0
- package/content/display-blocks/skeleton.md +272 -0
- package/content/display-blocks/skeletonavatar.md +222 -0
- package/content/display-blocks/skeletonbutton.md +245 -0
- package/content/display-blocks/skeletoninput.md +223 -0
- package/content/display-blocks/skeletonparagraph.md +201 -0
- package/content/display-blocks/statistic.md +485 -0
- package/content/display-blocks/steps.md +585 -0
- package/content/display-blocks/tag.md +620 -0
- package/content/display-blocks/title.md +654 -0
- package/content/display-blocks/tour.md +2359 -0
- package/content/input-blocks/autocomplete.md +786 -0
- package/content/input-blocks/buttonselector.md +964 -0
- package/content/input-blocks/checkboxselector.md +765 -0
- package/content/input-blocks/checkboxswitch.md +497 -0
- package/content/input-blocks/colorselector.md +884 -0
- package/content/input-blocks/daterangeselector.md +777 -0
- package/content/input-blocks/dateselector.md +693 -0
- package/content/input-blocks/datetimeselector.md +791 -0
- package/content/input-blocks/inputgallery.md +528 -0
- package/content/input-blocks/monthselector.md +717 -0
- package/content/input-blocks/multipleselector.md +1337 -0
- package/content/input-blocks/numberinput.md +855 -0
- package/content/input-blocks/pagination.md +679 -0
- package/content/input-blocks/paragraphinput.md +1664 -0
- package/content/input-blocks/passwordinput.md +480 -0
- package/content/input-blocks/phonenumberinput.md +688 -0
- package/content/input-blocks/radioselector.md +820 -0
- package/content/input-blocks/ratingslider.md +684 -0
- package/content/input-blocks/s3uploadbutton.md +384 -0
- package/content/input-blocks/s3uploaddragger.md +305 -0
- package/content/input-blocks/s3uploadphoto.md +288 -0
- package/content/input-blocks/segmentedselector.md +782 -0
- package/content/input-blocks/selector.md +1162 -0
- package/content/input-blocks/switch.md +552 -0
- package/content/input-blocks/textarea.md +714 -0
- package/content/input-blocks/textinput.md +639 -0
- package/content/input-blocks/tiptapinput.md +226 -0
- package/content/input-blocks/tiptapmentioninput.md +471 -0
- package/content/input-blocks/titleinput.md +1094 -0
- package/content/input-blocks/treeinput.md +144 -0
- package/content/input-blocks/treemultipleselector.md +162 -0
- package/content/input-blocks/treeselector.md +185 -0
- package/content/input-blocks/upload.md +149 -0
- package/content/input-blocks/uploaddragger.md +85 -0
- package/content/input-blocks/uploadphoto.md +84 -0
- package/content/input-blocks/weekselector.md +630 -0
- package/content/list-blocks/controlledlist.md +498 -0
- package/content/list-blocks/list.md +529 -0
- package/content/list-blocks/listselector.md +301 -0
- package/content/list-blocks/masonrylist.md +230 -0
- package/content/migration/upgrade-guide.md +106 -0
- package/content/migration/v4-to-v5.md +589 -0
- package/content/migration/v5-to-v6.md +36 -0
- package/content/operators/_actions.md +58 -0
- package/content/operators/_and.md +76 -0
- package/content/operators/_api.md +254 -0
- package/content/operators/_app.md +114 -0
- package/content/operators/_args.md +65 -0
- package/content/operators/_array.md +331 -0
- package/content/operators/_base64.md +49 -0
- package/content/operators/_boolean.md +33 -0
- package/content/operators/_build.md +166 -0
- package/content/operators/_change_case.md +357 -0
- package/content/operators/_date.md +415 -0
- package/content/operators/_dayjs.md +128 -0
- package/content/operators/_diff.md +61 -0
- package/content/operators/_divide.md +32 -0
- package/content/operators/_eq.md +52 -0
- package/content/operators/_event.md +86 -0
- package/content/operators/_function.md +52 -0
- package/content/operators/_get.md +92 -0
- package/content/operators/_global.md +86 -0
- package/content/operators/_gt.md +50 -0
- package/content/operators/_gte.md +50 -0
- package/content/operators/_hash.md +112 -0
- package/content/operators/_if.md +30 -0
- package/content/operators/_if_none.md +47 -0
- package/content/operators/_index.md +48 -0
- package/content/operators/_input.md +86 -0
- package/content/operators/_intl.md +135 -0
- package/content/operators/_item.md +166 -0
- package/content/operators/_js.md +113 -0
- package/content/operators/_json.md +120 -0
- package/content/operators/_jsonata.md +152 -0
- package/content/operators/_locale.md +65 -0
- package/content/operators/_location.md +40 -0
- package/content/operators/_log.md +22 -0
- package/content/operators/_lt.md +50 -0
- package/content/operators/_lte.md +50 -0
- package/content/operators/_math.md +407 -0
- package/content/operators/_media.md +83 -0
- package/content/operators/_menu.md +62 -0
- package/content/operators/_module.md +340 -0
- package/content/operators/_mql.md +95 -0
- package/content/operators/_ne.md +62 -0
- package/content/operators/_not.md +33 -0
- package/content/operators/_number.md +159 -0
- package/content/operators/_nunjucks.md +117 -0
- package/content/operators/_object.md +253 -0
- package/content/operators/_operator.md +33 -0
- package/content/operators/_or.md +67 -0
- package/content/operators/_product.md +45 -0
- package/content/operators/_random.md +90 -0
- package/content/operators/_ref.md +80 -0
- package/content/operators/_regex.md +69 -0
- package/content/operators/_request.md +35 -0
- package/content/operators/_request_details.md +29 -0
- package/content/operators/_secret.md +56 -0
- package/content/operators/_state.md +134 -0
- package/content/operators/_step.md +98 -0
- package/content/operators/_string.md +327 -0
- package/content/operators/_subtract.md +24 -0
- package/content/operators/_sum.md +45 -0
- package/content/operators/_switch.md +37 -0
- package/content/operators/_t.md +96 -0
- package/content/operators/_theme.md +65 -0
- package/content/operators/_type.md +78 -0
- package/content/operators/_uri.md +49 -0
- package/content/operators/_url_query.md +92 -0
- package/content/operators/_user.md +154 -0
- package/content/operators/_uuid.md +118 -0
- package/content/operators/_var.md +88 -0
- package/content/operators/_yaml.md +96 -0
- package/content/other/introduction.md +39 -0
- package/content/other/next-auth-providers.md +3 -0
- package/content/other/updatesession.md +26 -0
- package/content/plugins/plugins-actions.md +80 -0
- package/content/plugins/plugins-connections.md +98 -0
- package/content/plugins/plugins-dev.md +138 -0
- package/content/plugins/plugins-introduction.md +29 -0
- package/content/plugins/plugins-operators.md +71 -0
- package/content/testing/e2e-auth.md +108 -0
- package/content/testing/e2e-configuration.md +107 -0
- package/content/testing/e2e-getting-started.md +96 -0
- package/content/testing/e2e-introduction.md +53 -0
- package/content/testing/e2e-mocking.md +155 -0
- package/content/testing/e2e-writing-tests.md +214 -0
- package/content/tutorial/tutorial-actions-operators.md +222 -0
- package/content/tutorial/tutorial-add-blocks.md +86 -0
- package/content/tutorial/tutorial-create-page.md +57 -0
- package/content/tutorial/tutorial-display-data-page.md +181 -0
- package/content/tutorial/tutorial-next-steps.md +53 -0
- package/content/tutorial/tutorial-requests-sql.md +22 -0
- package/content/tutorial/tutorial-start.md +71 -0
- package/content/user-authentication/auth-providers.md +15 -0
- package/content/user-authentication/login-and-logout.md +122 -0
- package/content/user-authentication/users-introduction.md +31 -0
- package/index.json +2281 -0
- package/package.json +34 -0
- 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>.
|