From 09cd0c2756f8f1ed62fd7d50d015a90f8ae2aaf0 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Thu, 2 Jul 2026 07:58:55 +0100 Subject: [PATCH 01/32] initial pass --- docs/Apps/components/index.md | 100 ++--- docs/Apps/navigation.md | 243 ++--------- docs/Bindings/introduction-to-bindings.md | 213 +++------- .../templates/change-requests.md | 395 ++++-------------- 4 files changed, 224 insertions(+), 727 deletions(-) diff --git a/docs/Apps/components/index.md b/docs/Apps/components/index.md index 47c10b833..a02ee37fd 100644 --- a/docs/Apps/components/index.md +++ b/docs/Apps/components/index.md @@ -10,85 +10,77 @@ metadata: next: description: '' --- -Components are the UI elements of your Budibase apps. They are used to construct your user interface, which could be components that your user will interact with, or components for layout and displaying data. At Budibase we use the Spectrum design system created by Adobe. This gives you a great out-of-the-box experience with themes by default. +Components are the building blocks of Budibase apps. Use them to collect input, display data, and shape the layout of a screen. -*** +## Add components -## Adding components +There are two common ways to add a component: -There are a few different ways to add a component. If you have no components added, in the middle of your screen, there will be some text as well as a button that will allow you to add a component. The main way to add a component is to click the plus symbol found at the bottom right of your screen. +1. Use the add component button in the builder. +2. Select a component type from the searchable component list. -Clicking any of the above options will present a searchable and grouped list of components in the right-hand panel. +When the component list is open, pressing `Enter` adds the highlighted component. +## Delete components +Select a component and press `Backspace` or `Delete`. -When you search for a component, if it is highlighted in blue, add it immediately by pressing the *Enter* key. - -## Deleting a component - -The easiest way to delete a component is to select it and press the **delete** or **backspace** key.\ -You will be prompted to confirm the deletion. - -Alternatively, you can click on the three dots `...` and then click the delete action inside the opened context menu. - - -
+You can also open the component menu and choose the delete action. ## Component tree -The component tree displays the layout and hierarchy of your components.\ -Components can either be below one another, or nested inside a parent component. +The component tree shows the structure of the screen. -Parent components include those related to a Datasource or some variety of container: +Use it to: -* [Data Provider](doc:data-provider) -* [Repeater](doc:repeater) -* [Forms](doc:forms), [Form steps](doc:form-steps) and [Field groups](doc:field-groups) -* [Container](doc:container) -* [Sections](doc:using-sections) -* [Side Panel](doc:side-panel) -* Modal -* [Field Group](doc:field-groups) +* Reorder components with drag and drop +* Nest components inside containers, forms, repeaters, or other parent components +* Copy, move, or delete components from the `...` menu -Components can be re-arranged within the component tree with drag-and-drop.\ -To assist with rearrangement, a green line will highlight the destination whilst a green box indicates that a component will be dropped inside that component. - - -#### Editing - -Within the component tree you can also delete, copy and move components by clicking on the `...` beside the component name. +Common parent components include: +* `Data Provider` +* `Repeater` +* `Form` +* `Form step` +* `Field Group` +* `Container` +* `Section` +* `Side Panel` +* `Modal` ## Keyboard shortcuts -The following keyboard shortcuts are available for components. You can replace the `⌘` (command) button on Mac with `CTRL` on Windows if you wish to use the shortcuts on Windows. - -* **Delete** - Backspace `←` - Allows quicker deletion of a selected component -* **Move up** - `⌘`+ `↑`- Allows the user to move a component up in the component tree -* **Move down** - `⌘` + `↓`- Allows the user to move a component down in the component tree -* **Duplicate** - `⌘` + `D`- Duplicate component with all settings added -* **Cut** - `⌘` + `X`- Removes the component, saves it for pasting elsewhere -* **Copy** - `⌘` + `C`- Copies a component and allows it to be pasted elsewhere, e.g a new screen -* **Paste** - `⌘` + `V`- Pastes a copied/cut component in the component tree +Common shortcuts include: -There are a range of other ways to speed up navigate or perform additional actions more quickly. This is mainly done via the [Command Interface](doc:command-interface) +* `Backspace` or `Delete` to remove a selected component +* `⌘ + ↑` to move a component up +* `⌘ + ↓` to move a component down +* `⌘ + D` to duplicate a component +* `⌘ + X` to cut a component +* `⌘ + C` to copy a component +* `⌘ + V` to paste a component -## Renaming components +Use `CTRL` instead of `⌘` on Windows. -Sometimes, it's helpful to organise your component tree in a way that clearly reflects the purpose of each component. For instance, you might want to differentiate between various forms on a screen, such as the `Create Users form` or the `Edit Users` form. Similarly, labeling buttons can clarify their action, whether they're for endorsing, deactivating, etc. +## Rename components -To rename a component, first select it. Then, locate the component's settings at the top in the side panel. Click the current name, delete it, and enter your desired name. Use these steps to rename components consistently across your app. +Rename components to make the tree easier to scan. +1. Select the component. +2. Open its settings in the right-hand panel. +3. Replace the current name with a clear label. -## Using components +Use names that describe the component’s purpose, not just its type. -When you have added a component you will be able to see the options that you can tweak on the right side under the Settings bar. Some components also have a toolbar that will appear above it in the preview window. +## Use components -To find and rename a component quickly: select it in the canvas or component tree, then use the right-hand Settings panel where the component name appears at the top. +Once a component is on the screen, its settings appear in the right-hand panel. +Some components also expose additional controls in the canvas preview. Use these when you need to adjust layout or content without changing the underlying structure. -## Video tutorial +## Related guides -{` - -`} +* [Command interface](doc:command-interface) +* [Screens](doc:screens) +* [Using data providers](doc:data-provider) diff --git a/docs/Apps/navigation.md b/docs/Apps/navigation.md index f88625491..d3367b93a 100644 --- a/docs/Apps/navigation.md +++ b/docs/Apps/navigation.md @@ -10,227 +10,56 @@ metadata: next: description: '' --- -The navigation section of the design tab allows you position and style the app navigation bar as well as the available navigation links. +Use the Navigation settings to control the app menu, its position, and the links shown to users. -## Settings - -Click on the navigation icon in the Component Tree to access the navigation settings. - - - - The list of properties that can be changed for the navigation bar are displayed in the table below. - - - - - - - - - - - +## Open navigation settings - - - +1. Open the app in the Budibase builder. +2. Select the navigation item in the `Component Tree`. +3. Edit the navigation settings in the right-hand panel. - +## Navigation settings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - - Description - - Visual -
- Position - - Will anchor the nav bar to the top or left hand side of the page. - - -
- Sticky header - - *Top anchored nav bar only.* - - When scrolling down the page, the nav bar will remain visible at the top of the page. - - -
- Width - - *Top anchored nav bar only.* - - The width of the nav bar content. - - -
- Title - - Show/Hide the specified nav bar title. - - -
- Background color - - The background color of the nav bar. - - -
- Text color - - The color of the nav bar title and links. - - -
- -Below is a video that shows how each of the settings present in your app. - - - -By default the navigation bar is visible for all [Screens](doc:screens), however it can be turned on a per screen basis. - - +| Setting | Purpose | +| :--- | :--- | +| Position | Anchors the navigation bar to the top or left side of the screen. | +| Sticky header | Keeps a top navigation bar visible while the page scrolls. | +| Width | Controls the width of a top navigation bar. | +| Title | Shows or hides the navigation title. | +| Background color | Sets the navigation background color. | +| Text color | Sets the color of the title and links. | ## Configure links -The links shown in your navigation bar can be configured in the navigation panel by clicking on the 'Navigation' item in the Component Tree and then clicking the add new nav item button in the Settings Panel. - - - -This will add a new navigation item under any existing ones. This will default to the name `Nav Item`. With basic role permissions attached to the navigation item. - -You can customise various elements such as the text, link (External links or linking to internal screens), role permissions, or deciding whether a nav item is a single link or opens up a modal which contains sub-links. These can all be modified by clicking on the specific nav item you wish to amend. - - - -### Sub links - -If you select `Open sub links` as the option for nav item. The link field will be changed to a button. When clicked this will open a drawer that allows you to add, update and delete sub navigation links related to the parent nav item. - -
- - - -You can begin adding sub-links by clicking the `+ Add link` button. Feel free to add as many sub-links as you need, each with its own name. Just like the parent navigation items, these sub-links can direct users externally (e.g., to Google.com) or internally within your app. Additionally, the role permissions for these sub-links automatically inherit those of the parent navigation item. - - - -## Logo - -By default the navigation bar will show the Budibase logo, but there are a number of settings available to customise this under the *Logo* section of the navigation settings. - -Default logo settings - Default logo settings - - - - - - - - - - +Add navigation items from the navigation panel, then edit each item as needed. - - - +Each navigation item can define: - - +* Display text +* Internal screen links +* External links +* Role restrictions +* Sub-links grouped under a parent item - - +If you use sub-links, the parent item opens a drawer where you can add, update, or delete nested links. Sub-links inherit the parent item’s role restrictions. - - +## Logo settings - - +Use the logo section to control branding in the navigation bar. - - +| Setting | Purpose | +| :--- | :--- | +| Show logo | Hides or shows the logo. | +| Logo image URL | Replaces the Budibase logo with a custom image. | +| Logo link URL | Turns the logo into a link to a screen or external page. | +| Height | Sets the logo height in pixels. | - - +## Screen visibility - - +The navigation bar is available across screens, but you can turn it on or off per screen. - - +## Related guides - - - -
- Name - - Description -
- Show logo - - Toggle off to hide the logo from the nav-bar. -
- Logo image URL - - Allows you to replace the Budibase logo with a custom image. -
- Logo link URL - - If provided, turns your logo into a hyperlink.\ - This can be a screen (such as Home), or to an external webpage. -
- Height (px) - - Defaults to 24px, allows you to resize the logo image. -
- New tab - - Logo hyperlinks will be opened in a new tab. -
+* [Screens](doc:screens) +* [Components](doc:components) +* [Using sections](doc:using-sections) diff --git a/docs/Bindings/introduction-to-bindings.md b/docs/Bindings/introduction-to-bindings.md index 5cb7c6856..765fea320 100644 --- a/docs/Bindings/introduction-to-bindings.md +++ b/docs/Bindings/introduction-to-bindings.md @@ -10,186 +10,103 @@ metadata: next: description: '' --- -Bindings are a core concept in Budibase, and expand the functionality of your Workspaces beyond the standard [autogenerated screens](https://docs.budibase.com/docs/table-block#autogenerated-screen). +Bindings connect dynamic values to fields in Budibase. Use them to pass data, format values, and perform calculations. -You can think of bindings as solving these high-level problems: +## When to use bindings -* passing data from one location to another -* formatting data for display -* performing calculations +Use bindings when you need to: -*** +* Display data from a table, form, or user context +* Pass a value from one component to another +* Use a query parameter or screen state in a data source +* Format output before it is shown to the user +* Run JavaScript for more complex logic -## Bindings drawer +## Open the bindings drawer -In its simplest form, a binding is a reference to a dynamic value, and is expressed with a syntax known as [Handlebars](doc:bindings) by default. +Look for the lightning icon next to a field that supports bindings. -Whether within the **Design** or **Automate** sections, look out for the lightning bolt icon next to input fields. This indicates that the field supports binding values. +1. Click the lightning icon. +2. Choose a binding category. +3. Search for the value you want. +4. Insert the binding into the field. -The 'Text' property of the Heading supports bindings - The 'Text' property of the Heading supports bindings - +You can also type a binding directly into a text field using double braces. -You can directly type bindings into the text field using double braces, e.g. `{{ Field Value }}`. - -However, this won't give you access to the binding drawer, which provides auto-completion or the option to switch to JavaScript syntax. - -To open the bindings drawer, click on the lightning icon. The drawer will slide up from the bottom of the screen. - -You will see a list of binding categories on the right-hand side, which you can search and dig into to find the binding expression you would like to add. You can read more about binding categories and their scope [here](doc:bindings-scope) - -It is worth noting that you can combine static text with binding values, which are distinguished by blue-highlighted text. - - - -From the demonstration above, you may have noticed that each binding indicates the data type along the right-hand side, which will usually be a *String* (text) value such as the first name of the logged-in user. You may also have noticed in the above GIF that it is valuable whenever a binding is hovered. This is very useful as it lets users see what's being output before saving their changes. This only works if there is awareness of the value of the binding. - -If an arrow is present, this means that the item is a category that must be drilled into. Regarding the binding `{{ Current User.firstName }}`, we are accessing the *firstName* text property from the *Current User* object. - -### Auto completion - -While the bindings panel provides an easy way to explore available binding options, there is an even faster way when you get comfortable with using bindings. - -Within the text area type `{{`. This will immediately prompt a dialog with a scrollable list of binding options. Start typing to filter this list; you filter by the property name or category name. Next, use the arrow keys to navigate the list, and press the *Enter* key to insert the binding you want. - - - -### JavaScript - -As you can see from the tabs in the bindings drawer, there is the option to use JavaScript instead of text. The benefit of [Using JavaScript](doc:javascript) is that it provides the maximum flexibility for manipulating data, although it will obviously require a little bit of experience in using the language. - - If you have any existing text, clicking the JavaScript tab will provide a warning prompt - click `Yes - discard text` to proceed if you wish, but you can always click the `Cancel` button to revert your changes. - -Switching to JavaScript will overwrite the existing text value - Switching to JavaScript will overwrite the existing text value - - -Auto-completion works in a similar way for JavaScript, however the difference is the symbol used to denote the binding. Instead of using curly braces, type the `$` dollar symbol to access the bindings menu. - -![](https://files.readme.io/4e380ab-binding_auto.gif) - -> 📘 Return value -> -> JavaScript bindings are considered to be functions, and thus you must always use the `return` keyword to return a value. - -*** - -
- -## Passing data around - -Bindings open a link between your [Data](doc:data) and your [Screens](doc:screens) and [Automations](doc:automation-steps), but they can also be used to connect two screens, or link components within a screen. - -For example you may have a [REST query](doc:rest-queries) or [Custom SQL query](https://docs.budibase.com/docs/data-sources#custom-queries). What if you wanted the app user to input a query param, or provide a filter value? You will need bindings to do this, with configuration needed in both the **Data** section and the **Design** section. - -### Data config - -Whenever you add a query for any [Datasource](doc:data-sources) you have the option of adding bindings to be used in your query. - -For example consider this [SQL query](https://docs.budibase.com/docs/sql-datasource#add-query): - -Get the row entry for Georgi - Get the row entry for Georgi - - -To make this query generically useable for retrieving an entry for any name, click the `Add binding` button. Type in a unique name for the binding, and provide a default value. The default value allows you to test that your query is working correctly, and in the case of a *Read* query, configure the [Schema](https://docs.budibase.com/docs/data-sources#schema). - -Next you need to reference this binding within your query. You do this through the curly braces syntax: - -![](https://files.readme.io/c53f79b-Screenshot_2023-06-06_at_16.47.54.png) - -### Design config - -With the bindings configured in the Data section, we can now pass values from the Design section into our query. - -As this is a *Read* query, we can use it as the source for a [Data provider](doc:data-provider). Click the cog icon to open the bindings drawer. - -Selecting a Read query as a data source - Selecting a Read query as a data source - - -Query bindings drawer - Query bindings drawer - +```text +{{ Field Value }} +``` -You can now see a preview of our query, and also an input field for the *firstName* binding is available. A common scenario would be to use a form text field binding for implementing searching, which would look similar to: +This is useful for simple values, but the drawer gives you autocomplete and access to JavaScript bindings. -Passing the value from a 'first_name' form field into a SQL query - Passing the value from a 'first\_name' form field into a SQL query - +## Use JavaScript bindings -### Further reading +Switch to the JavaScript tab when you need logic that text bindings cannot provide. -* [Bindings in forms](doc:form-bindings) -* [Using query bindings](https://docs.budibase.com/docs/data-sources#using-query-bindings) -* [REST bindings (tutorial)](doc:rest-bindings) -* [URL variables](doc:url-parameters) +JavaScript bindings must return a value. -*** +```javascript +return $("Current User.firstName"); +``` -
+Use JavaScript bindings when you need to: -In addition to passing data from one location to another, you can perform calculations on values, or choose the format you wish to display data. +* Transform values before display +* Combine multiple fields +* Build dynamic URLs +* Calculate totals or conditional output -## Tutorial: Calculating the total cost of selected items +## Pass data between queries and screens -To start, create a new workspace with the [Sample data](https://docs.budibase.com/docs/data-sources#sample-data). In this example we will be focused on the **Inventory** table. +Bindings are commonly used in both the Data and Design sections. -In the Design section, add a [Form](doc:forms), nest a [Data provider](doc:data-provider) for the **Inventory** table, and nest a [Container](doc:container). +### In Data -The idea is to have a dropdown for selecting the inventory items on the left, and a table that shows the details for the selected items on the right. At the bottom of the table there will be a headline that prints the sum total *Purchase Price* of the selected items. +Add a binding to a query when the input value should come from the app. -Add a [Multi-select picker](doc:multi-select-picker) to the container. Type in a unique field name, and in the style tab provide a fixed width of `200px`. +Example use cases: -Under the *Options source* setting, select *Data provider* and then select the data provider we had added earlier. Set the *Label column* to 'Item Name', and the *Value column* to 'Item ID'. +* Filter a read query by a form field +* Pass a screen parameter into a REST query +* Reuse the same query for multiple records by changing the binding value -Component tree so far - Component tree so far - +### In Design -Multi-select settings - Multi-select settings - +Use a data provider, form field, or component state to supply the binding value. -With our multi-select configured, now we want to add a table to show more info for the selected items, and add our sum total of prices. +Typical flow: -Add a container below the multi-select, and nest another Data provider, which will also be for the **Inventory** table. +1. Add the binding in the query. +2. Use the query in a data provider or component. +3. Map a screen field, state value, or user value into the binding. +4. Test the query with a known default value before publishing. -> 🚧 Duplicate data providers -> -> 🚧 Performance Tip: To optimise performance, minimise the number of data providers on your screen, especially for the same data source or table query. -> -> It's best practice to avoid duplicating data sources unnecessarily. Ideally, use a single data provider to query the table's data and then rely on additional providers to filter that data. This reduces server requests and enhances performance. -> -> In this case, a duplicate data provider is required because one is filtered for the table, while the picker needs access to all rows. -> -> For a performance boost, consider using [use custom options](https://docs.budibase.com/docs/option-picker#using-custom-options) if the list of options is static. +## Calculate values -Click `Define filters` and add the following: +You can use bindings to calculate display values as well as data values. -![](https://files.readme.io/5bcf1d5-Screenshot_2023-06-07_at_11.39.10.png) +Example uses: -Make sure to `Save`! This will filter the data provider based on the selected items from the multi-select field. +* Sum selected prices +* Format a status label +* Build a download URL +* Show or hide content based on a condition -Nest a [Table](doc:table) component under the data provider. Add `min-height: 320px;` to the [Custom CSS](doc:custom-css) of the table - this is so the total text at the bottom of the table doesn't move as items are selected. Alternatively, you can drag the elements around the screen to get the same layout if you use the new grid layout. +## Good practice -After selecting the table on the right of the screen, you can show and hide table columns by toggling on and off the columns. +Keep bindings: -Finally, below the table component, add a [Headline](https://docs.budibase.com/docs/displaying-text#headline) component, and right-align the text. Add the following binding after switching to the JS tab: +* Clear +* Short +* Predictable +* Easy to test -```javascript -const autoID = $("New Form.Fields.items"); -const arrayOfItems = $("Inventory Dataprovider.Rows"); -const totalPurchasePrice = arrayOfItems.reduce((acc, item) => { - if (autoID.includes(item["Item ID"])) { - return acc + item["Purchase Price"]; - } - return acc; -}, 0); - -return `Total £${totalPurchasePrice}`; -``` +Prefer direct values and simple expressions. Use JavaScript only when the binding needs real logic. -#### Result +## Related guides - +* [Bindings](doc:bindings) +* [Bindings scope](doc:bindings-scope) +* [JavaScript bindings](doc:javascript) +* [Form bindings](doc:form-bindings) +* [URL parameters](doc:url-parameters) diff --git a/docs/Getting started/templates/change-requests.md b/docs/Getting started/templates/change-requests.md index acd937b57..dcd0bb94b 100644 --- a/docs/Getting started/templates/change-requests.md +++ b/docs/Getting started/templates/change-requests.md @@ -10,352 +10,111 @@ metadata: next: description: '' --- -Our change management template offers a fully functional solution for handling incoming requests. Use it as a ready-to-deploy app or customize any aspect of its data, design, and logic to suit your own unique processes. +Use the Change Requests template to manage submissions through a simple approval flow. It includes the core data model, role-based access, and the automations needed to move requests from submission to final decision. -In this guide, we outline exactly what our template does, how it’s built, and some of the key areas where you can put your own stamp on it using Budibase. +To use this template, [open it here](https://budibase.app/builder?template=app/change-request). -To use this template, [click here](https://budibase.app/builder?template=app/change-request). +## What this template includes -Let’s jump right in. +The template is built for request intake, review, and auditability. It gives you: -## What does this template do? +* A requester-facing form for creating submissions +* Manager and reviewer views for triage and approval +* A status history table for tracking every change +* Automations for notifications and status updates +* Role-based permissions for requesters, managers, reviewers, and admins -Change requests are a key part of managing projects, processes, or services. This presents a few challenges: +## Data model -1. Gathering request data. -2. Enforcing approval workflows. -3. Documenting decisions and outcomes. -4. Handling follow-on actions, including communicating with stakeholders. +The app uses two Budibase DB tables and the built-in `Users` table. -Our solution is based around a two-step approval workflow. It’s built on two tables in Budibase DB. +| Table | Purpose | +| :--- | :--- | +| `Change Request` | Stores the submitted request and the fields needed during review | +| `Status History` | Stores a record of each status change for audit purposes | -Here’s a summary of core functionality. +### `Change Request` -### CRUD Operations +Typical columns include: -Users can take distinct CRUD actions across the application, according to their role. Different users can create, read, update, or delete specific data depending on their needs within the change request workflow. +* `Title` +* `Description` +* `Change type` +* `Submitted date` +* `Date required` +* `Status` +* `Submitted by` +* `Priority` +* `Reason for change` +* `Attachments` +* `References` +* `Date signed` +* `Status history` +* `Review signature` +* `Rejection reason` +* `Completion date` +* `CrId` -In Budibase, user permissions regarding CRUD actions are defined in the Data section. Once we’ve configured which data users can interact with, we can autogenerate CRUD UIs that reflect these permissions. +### `Status History` -Our app UI is made up of a range of task-specific forms and tables. For example, enabling users with the **Requestor** role to add new records to our requests table: +This table records each update to a request status. -![Change Request Management Template](https://files.readme.io/955ba8599cd68c6c05e8aa23ee5b9ccf196ad2b1fb4dc701c85e2557b7b4059b-Change_Request_Form_Gif_1.gif) +* `New status` +* `Previous status` +* `Timestamp` +* `Changed by` +* `Change request` -### Approval workflows +## Roles and access -When a request is submitted, its **status** attribute is automatically set to **Submitted** using Budibase’s **default values**. At this point, a **Row Action** automation is triggered, notifying a **Manager** that a new request needs their attention. +The template uses four access patterns: -The manager then has the option to Accept or Reject the request using separate Row Actions. When a request is accepted by the manager, its status is updated to **In-Review**. +* `Requesters` create requests and edit their own submissions +* `Managers` review requests with `Submitted` status +* `Reviewers` handle requests that have moved to `In Review` +* `Admins` can manage the app and all connected data -![Change Management](https://files.readme.io/78cbecbc02fbb8991f63874aa487e4d5c1a8722e68fb6d35d861441736c08180-Change_Request_Template_Gif_2.gif) +Permissions are configured through views and column-level access: -At this point, it is sent to all users with the **Reviewer** role. +* `My Requests` returns only rows created by the current user +* `Manager Approval` returns rows with `Submitted` status +* `Reviewer Approval` returns rows with `In Review` status +* Admin access covers both tables with full read and write permissions -Reviewers are able to provide the final sign-off for the request. +## Screens -### Tracking change statuses +The template uses autogenerated screens where possible. -A key part of change management is documenting exactly what has been adopted and who signed it off. +* Requesters use a table and form workflow to create and update their own requests +* Managers and reviewers work from a shared review screen with approval and rejection actions +* Admins use a dedicated screen to inspect request history and supporting details -Our template features a dedicated **Status History** table. Each time a **Request’s** status attribute changes, this table is updated with a new row. The new status, previous status, user, and timestamp are automatically recorded. +When you adapt the template, keep the screen structure aligned with the role that uses it. That makes the workflow easier to understand and reduces unnecessary navigation. -This provides a clear record of how requests progress through our approval process, providing oversight and auditability. +## Automations -We can view these records using a dedicated History UI, which is accessible only to users with the **Admin** role. +The template includes automations for the core workflow: - +* `Submitted Change Request` runs when a request is created and notifies managers +* `Cancel` updates the current request and confirms the change to the requester +* Manager and reviewer approval flows update status and write supporting notes +* Status changes can also write to `Status History` for auditability -### Automated emails +If you add new statuses or extra review stages, update the related automations at the same time. -As a change request progresses through our workflow, it’s important to keep stakeholders up to date with developments. +## Customizing the template -Our application utilizes Budibase’s automated email capabilities as the **status** of requests changes, notifying users when there’s something that requires their attention, as well as the final outcome of requests. +Start with these changes: -Take a look at our documentation on [working with email automations](https://docs.budibase.com/docs/send-email). +1. Rename the tables and roles to match your process. +2. Adjust the status values to reflect your approval stages. +3. Update the requester, manager, reviewer, and admin screens. +4. Add or remove fields from the request form as needed. +5. Tighten row-level permissions before using the template in production. -### User roles +## Related guides -Our change management workflow utilizes three custom access roles, along with Budibase’s default Admin user type. - -These are used to determine data exposure and permitted actions for end users. - -The permissions associated with each of our roles are as follows. - -**Requesters** are able to submit change requests or view and edit their own previous submissions. - -**Managers** inherit all permissions from the **Requester** role. On top of this, they can review all requests with a **Submitted** status and trigger approve or reject row actions. When a **Manager** approves a request, it is passed to the next stage of our approval workflow. - -**Reviewers** also inherit permissions from **Requesters**, and from **Managers**. They can then carry out row actions for final approval or rejection and provide additional information. - -**Admins** can manage application settings, users, and roles. They also have full CRUD permissions across all connected data. - - - -## How does it work? - -Our templates are designed to help you get started with Budibase. They’re fully working solutions, but you can customize them as much as you need to suit your change request management workflows. - -Let’s check out how our change request app is built. - -### Data structure - -In Budibase, the Data section is at the core of the app-building experience. In addition to configuring our app’s data, we can use this to set access rules, define user actions, and even generate UIs. - -Check out our documentation on [Budibase DB](https://docs.budibase.com/docs/budibasedb) to learn more. - -Our template is built on two tables within Budibase’s internal database. It also utilizes several role-specific views to control which data different kinds of users can interact with across these. - -Here’s how this works. - -#### Tables - -Our application utilizes two database tables and Budibase’s internal **Users** table. - -One is **Change Request,** which stores all information about incoming requests and additional details provided during the approval process. - -The other is **Status History**, which stores information about how the Status attribute of individual Change Request rows has changed. - -The **Change Request** table stores the following attributes: - -* **Title** - Text, -* **Description** - Long Form Text, -* **Change type** - Single Select, -* **Submitted date** - Date, -* **Date required** - Date, -* **Status** - Single Select, -* **Submitted by** - Single User, -* **Priority** - Single Select, -* **Reason for change** - Long Form Text, -* **Attachments** - Attachment, -* **References** - Text, -* **Date signed** - Date, -* **Status history** - Relationship, -* **Review signature** - Signature, -* **Rejection reason** - Long Form Text, -* **Completion date** - Date, -* **CrId** - Number. - -Meanwhile, the **Status** **History** table maintains a record of updates to the **Status** attribute on our **Change Request** table, with the following attributes: - -* **New status** - Text, -* **Previous status** - Text, -* **Timestamp** - Date, -* **Changed by** - Single User, -* **Change request** - Relationship. - -Whereas the **Change Request** table is primarily populated manually by users, entries on the **Status History** table are created automatically when the **Status** is updated. We’ll see how this works a little later. - -#### Relationships - -Our data model relies on a relationship between our two database tables and between each of these and Budibase’s internal Users table. - -The **Relationship** table allows us to configure links between rows across tables in BudibaseDB. Our application uses a **One-To-Many** relationship from our **Change Request** table to **Status History**. - - - -Budibase also allows us to set up relationships between our database and the internal **Users** table. For instance, to assign a row to a particular record, or track who has created a row. - -This is also helpful when defining data permissions for specific users. For instance, only allowing users to view their own submissions or assigned rows. - -We can do this with two special data types, the **Single User** and **Multi User** columns. - -Across our two tables, we’ve included several **Single User** columns, primarily to track actions. For instance, the **Submitted by** column on our **Change request** table. - - - -#### Views - -**Views** are subsets of data across one or more tables that we can create for a specific purpose or function by setting rules for which rows, columns, or permitted actions to include. We can then set access rules, defining which **Views** can be used by different user roles. - -We’ve created three **Views** based on our **Change Request** table to provide **Employees**, **Managers**, and **Reviewers** with data exposure that’s appropriate for their roles. - -**Employees** can submit data or view their own previous submissions using a **View** called **My Requests**. This uses a filter expression to only return the rows where the **Submitted by** attribute is set to the **Current User** in app’s front-end. - - - -Under the **Columns** tab, we’ve granted **Write** permissions for all attributes required to create an initial change request, as well as **Read** access for the **Status** column. - - - -Our **Manager Approval** and **Reviewer Approval** views include rows irrespective of which user created them. Instead, they’re filtered by their current **Status**, enabling these users to access requests that are at an appropriate stage in our workflow for their role. - -**Managers** can access rows where the **Status** is **Submitted** while the **Reviewer Approval** View returns requests that are **In Review**. - - - -They also each have **Read** and **Write** permissions for the columns that are required for each of them to respond to requests. - - - -Users with the **Admin** role have full **Read** and **Write** permissions for both our **Change Request** and **Status History** tables. - -### User interfaces - -Next, let’s check out how our template’s front end is built. Check out our docs page on [working with screens within Budibase](https://docs.budibase.com/docs/screens). - -Since users primarily need to either create database entries or view and update existing ones, our app relies heavily on Budibase’s autogenerated **Form** and **Table** layouts. - -These inherit the access roles of the tables or views they’re based on. - -For **Employees**, the app’s home screen is **CRUD** **UI**. This has been auto-generated from the **My Requests** View, using the **Table** layout with separate form screens. - - - -Our template uses a single screen for handling both **Manager** and **Reviewer** actions. This displays relevant **Change Request** records for each type of user within a **Table** UI where they can open modal forms to **Approve** or **Reject** submissions and provide notes. - - - -In the Budibase builder, this screen actually contains two separate tables. We’re using conditionality rules to determine which one to display in the end-user app, depending on the current user’s role. - -Take a look at our documentation on [working with data in design](https://docs.budibase.com/docs/working-with-data) to learn more about how this works. - - - -The specific **form** that loads within the **modal** is determined by which action the user has selected. This works by setting an in-app state when they initially hit **Approve** or **Reject** and applying a conditionality rule to our forms based on this. - - - -Lastly, our **Administration** screen is also based on an autogenerated **Table** layout with some important modifications. Firstly, we’ve nested our table inside a form and added filter expressions based on user selections in the provided form fields. - -This means that our table can be filtered from the front-end, so **Admins** can more easily find the history of specific **Change Request** records. - - - -Secondly, rather than opening an **Update** form, when a user clicks a row, it opens a custom screen to expand the details of the specific **Change Request**. - -This utilizes a series of **Markdown Viewer** components and **Containers** to display the data from the original request, as well as a **Read-Only** table of all related **Status History** rows. - -![Audit Form](https://files.readme.io/9fc98bbf632ad878ddf8dd20ef2d5befca6c7b8dc45fa0673e133d2f01c74bee-Change_Request_Template_14_Admin_Screen.png) - -### Automations - -In Budibase, Automations are used to define sequences of steps that can be triggered by user actions, database events, cron expressions, or other triggers. Take a look at our [automation docs](https://docs.budibase.com/docs/automation-steps) to learn more. - -We’ve used several automation workflows across our template to handle key interactions with our data, as well as notifying users of how their submissions are progressing. - -Many of these rely on Budibase’s **Row Actions** functionality. A Row Action is a user-triggered automation rule that relates to a particular entry in a database or view. Others are triggered when a database entry is created or updated. - -Let’s check these out. - -#### Request submission and cancellation - -Our first Automation is called **Submitted Change Request**. This uses a **Row Created** trigger on our **Change Request** table. So, it will run each time a user creates a new request. - -This flow contains three steps. First, we use a **Query Rows** action to return all rows in the **Users** table with their role set to **Manager**. Second, we use some custom JavaScript to pass these users’ emails into an array. - -Thirdly, we use an **Email** action to notify all **Managers** that there’s a new request that requires their attention. - - - -We’ve also included a **Cancel** row action. This uses an **Update Row** step to change the **Status** attribute of the trigger row to **Cancelled**, before emailing the original submitter to confirm that this has been successful. - -This is triggerable from the front-end using a dedicated **Cancel** button within the **Update Form** for **Requesters**. - - - -#### Approval/rejection - -**Row Actions** are also central to our review and approval workflow. - -Specifically, we’ve created two sets of **Approve** and **Reject** actions for our **Manager** and **Reviewer** roles. These follow the same pattern but with a couple of important differences. - -**Manager: Approve** sets the **Status** of the original request to **In Review**, before querying the **Users** table for entries with the **Reviewer** role, passing their emails to an array, and notifying them that the request needs their attention. - -**Manager: Reject** updates the **Status** to **Rejected** and notifies the original submitter. - -Both of these are triggerable from the **Managers** version of our review screen, using button actions. - - - -**Reviewer: Approve** and **Reviewer: Reject** follow the same pattern as **Manager: Reject.** - -These update the **Status** to **Approved** or **Rejected**, respectively. Both then send an email notification of this update to the original **Requester**. - -They’re triggerable from the **Reviewer** UI. - - - -#### Change history - -Our final Automation works slightly differently, utilizing a **Row Update** trigger for our **Change Request** table. This means that it will run each time a row is updated, regardless of how this change was initiated. - -When this is triggered, it carries out three actions. - -First, we use a **Query Rows** action with a filter set to return all existing **Status History** rows that are related to the **Change Request** row in our trigger. - -Next, we use a **Condition** step so that our automation only continues if the most recent returned row does not have the same **Status** as our trigger row. - -Lastly, we use a **Create Row** action to add a record to our **Status History** table, recording the current status, previous status, timestamp, and the user who made the update. - -## Customizing our change request template - -Budibase templates are fully functional apps, but they’re also designed with customization in mind. - -Let’s think about some of the key ways that you can tailor your application to match your internal change management processes. - -### Updating the data model - -Budibase apps center around the Data section. This isn’t just where we set up the data our app connects to. It’s also a centralized location for managing access and permissions or generating screens and automations. - -At the most basic level, we might want to make adjustments to existing attributes within our data model. For instance, we could add additional options to our **Status** column to reflect a more complex approval process. - -Alternatively, we could remove certain attributes or add entirely new ones. For example, we could create a **Number** column called **Estimated Cost** on our **Change Requests** table using the plus icon. - - - -Alternatively, you might want to make more wholesale changes to our app’s backend, such as entirely swapping out the database. - -Budibase offers connectivity for a huge range of external datasets. We can even connect to SQL databases and interact with them in the Data section, exactly as we would in Budibase DB. - -We could then recreate our role-specific views and connect these to our existing screens and automations. Alternatively, we might recreate these from scratch using the **Generate** button. - -### Adding and altering user roles - -Our change management app relies on Budibase’s customizable RBAC system. If we wanted to create a more sophisticated approval flow, we could start by adding additional user roles. - -Say we wanted to update our approval flow so that the CTO can fast-track requests, by setting their status to **Approved**, regardless of their current status. We’d start by creating a new user role called **CTO**. - -RBAC within Budibase applications utilizes visual branches to establish hierarchies and handle permission inheritance. - -We want our CTO to inherit all of the permissions that our **Reviewer** role has but with access to additional data and actions. - -Therefore, we’re placing our CTO in the same branch as our existing roles, to the right of **Reviewer**. - - - -### Adding your own business rules - -After adding a new role, we need to define which data and actions they’ll be able to access. Let’s carry on with the example of only allowing our CTO to approve high-priority requests. - -Currently, our **Reviewers** and **Managers** have permissions to view and approve all requests with certain **Statuses**. Our CTO will be able to approve any request, regardless of its current status. - -Then, we’ll create a new view and call it **CTO** **Approval**. We’ll assign the **Access** to our new **CTO** role. - -Here, we want to recreate our **Reviewer View** but omit the filtering expression for the **status** attribute. - - - -### Creating new user actions - -Currently, our **Reviewers** approve or reject requests, using **Row Actions**, as we saw earlier. We’ll need to set up similar actions for our new **CTO Approval** view. - -We’ll start by hitting **Row Actions** and creating an action called **CTO: Approve**. - - - -Within the Automation section, we can follow the same pattern as our existing Automations, adding the following steps: - -* **Update Row** - Updating the original **Change Request’s** Status to approved. -* **Email** - To notify the original Requester of this update. - -We could also add a corresponding **CTO: Reject** rule using the same process. - -### Modifying our screens - -Lastly, we’ll need to add an appropriate UI for our CTO role. This will essentially match our existing **Managers** and **Reviewers** UI with our updated data view. - -We can achieve this by duplicating one of the existing tables on our Review screen, and updating the Data Source for the new one to our CTO View, making sure to also update the corresponding conditionality rule and button actions. - - - -We’ll then repeat this process to provide conditional forms for our **CTO: Approve** and **CTO: Reject** row actions, mimicking our current settings, including setting an app state as one of the initial button actions. +* [Budibase DB](https://docs.budibase.com/docs/budibasedb) +* [Working with screens](https://docs.budibase.com/docs/screens) +* [Working with email automations](https://docs.budibase.com/docs/send-email) +* [Working with data in design](https://docs.budibase.com/docs/working-with-data) From 461e3d790e1e63fa4d60ee8f631b7aa2d22d21c0 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 10:47:21 +0100 Subject: [PATCH 02/32] second batch update --- .../custom-plugin/custom-automations.md | 123 ++-- .../custom-plugin/custom-component.md | 613 +++--------------- .../custom-plugin/custom-datasource.md | 376 ++--------- docs/Develop & Scale/custom-plugin/index.md | 181 ++---- .../custom-plugin/quickstart-plugins.md | 49 +- .../templates/expense-approval.md | 340 ++-------- .../templates/risk-management.md | 432 ++---------- 7 files changed, 410 insertions(+), 1704 deletions(-) diff --git a/docs/Develop & Scale/custom-plugin/custom-automations.md b/docs/Develop & Scale/custom-plugin/custom-automations.md index 3bcd95f86..95baa4d40 100644 --- a/docs/Develop & Scale/custom-plugin/custom-automations.md +++ b/docs/Develop & Scale/custom-plugin/custom-automations.md @@ -10,97 +10,110 @@ metadata: next: description: '' --- -## Purpose +Custom automation steps let you extend Budibase automations with your own backend logic. -Automation action plugins can be used to extend the functionality of automations. [Automations](https://docs.budibase.com/docs/automation-steps) can be used in conjunction with the various triggers Budibase provides, like webhooks or row created/updated/deleted events to create custom backend functionality, API endpoints or background processes. With plugins we can extend this further, for example we could build an automation plugin that integrates with a local IoT system, allowing you to trigger real world actions through Budibase. Currently, automation plugins can only be used in self host. +Use them when you need an action that is not covered by the built-in automation steps. -Datasource plugins can also be used to provide similar functionality through the "External Data Connector" action in automations - however the integration with automations is more complex, the plugin is more complex (requiring [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations to be fully defined) and is more data centric in functionality; automations in contrast are more action focused. +## Before you start -## Getting started +Make sure you have: -Make sure you have the latest [Budibase CLI](https://docs.budibase.com/docs/budibase-cli-setup) installed. Even if you have previously installed the CLI, you may want to install it again to be sure you have the latest version. +* The latest [Budibase CLI](https://docs.budibase.com/docs/budibase-cli-setup) +* Node.js `v20` or later +* A self-hosted Budibase installation -Also make sure that you have **node v20+** installed. You can run `node --version` to see if you need to upgrade. +Automation step plugins are not available in Budibase Cloud. -Please note that automation action plugins can only be used in self host installations - they cannot be imported to the Budibase Cloud. +## Create the step -Once that's done, we need to initialise a template for our automation action. - -> 📘 Automation actions - not triggers -> -> It is important to note that you can only build automation actions, triggers are built into Budibase and can only be extended through the core project. If you need a new automation trigger type please create an [issue](https://github.com/Budibase/budibase/issues/new?assignees=\&labels=enhancement\&template=feature_request.md\&title=) describing what you need. - -Navigate to the folder location you want to create your plugin, and execute the following command: +1. Go to the folder where you want to create the plugin. +2. Run: ```shell budi plugins --init automation ``` -Next you will receive a series of prompts to enter details about your automation. You can press enter without providing a value if you are happy to use the placeholder. +3. Complete the setup prompts. +4. Open the generated project in your editor. -![](https://files.readme.io/ed400a6-image.png) +The template includes: -This will create an automation skeleton project, with the following structure: +* `src/index.ts` for the entry point +* `src/automation.ts` for the step implementation +* `schema.json` for builder configuration +* `test/index.spec.ts` for template tests -```Text YAML -src: - index.ts: The main entry file - this should not change under normal circumstances. - automation.ts: The code for your custom automation action. Do not rename. +## Build and watch -test: - index.spec.ts: A Jest test file that includes a template test for the action runner. +Build the project with: -package.json: The version, license and dependencies for your automation action. - -schema.json: The metadata which describes your automation action - like settings displayed in builder. +```shell +cd budibase-automation +yarn build ``` - There will be a lot of generated files/directories, such as `node_modules` and build/test configuration files - you will not usually need to edit these, if you do need to change these it may be worth raising an [issue](https://github.com/Budibase/budibase/issues/new?assignees=\&labels=enhancement\&template=feature_request.md\&title=). +During development, run `yarn watch` so changes are reflected in your local Budibase instance. -## Building your automation +If you change `schema.json`, refresh the builder so the new action shape appears. -After you have created your new automation action directory, execute the following: +## Implement the step -```shell -cd budibase-automation -yarn build -``` +`automation.ts` exports a single `run` function. + +Use it to: + +* Read inputs from prior automation steps +* Perform the required action +* Return the next output for the automation chain + +Keep the action focused on one responsibility. If you need multiple behaviours, create separate steps. + +The `run` function receives the automation context, step inputs, and an event emitter. Use those to read data, return outputs, or trigger downstream behaviour. + +The template also includes a `stepId`. Keep that identifier stable once the step is in use, because changing it can break existing automations. + +## Configure the schema -Assuming you have [updated the server env variable](https://docs.budibase.com/docs/custom-plugin#hot-reloading-developers-only) you should now be able to see your automation plugin in Budibase, as a selectable automation step. +`schema.json` defines: -### Automation.ts +* The step name and icon +* The inputs the user configures in the builder +* The outputs the step returns -This is where the code will live for your automation action. It is recommended that it is developed in TypeScript, this allows use of the [@budibase/types](https://www.npmjs.com/package/@budibase/types) package if you desire access to any of the Budibase types. +Keep the public configuration narrow and explicit. -To make sure your saved changes are passed through to your Budibase server, you must execute a `yarn watch` within your custom automation project. This will allow your local Budibase app builder to see those changes in real-time, which is very handy for getting your automation to behave just right. Please note that if you change the `stepId` in your `schema.json` then any automations currently using the plugin will break, the `stepId` should not change. +For most actions, set `type` to `action`. Use a logic step only when the plugin is meant to control flow rather than perform an action. -#### Methods +Use `inputs` for defaults and `schema.inputs` and `schema.outputs` for the structured contract that the builder and runtime share. -The `automation.ts` file contains a single exported function - `run`. This takes the inputs from the prior automation steps, as configured by the user and performs the steps required for this action. This can be quite daunting, as you can do anything with this function, for some inspiration as to how this can be used you can look through the [built-in actions](https://github.com/Budibase/budibase/tree/develop/packages/server/src/automations/steps). +## Testing -Types involved with the automation runner can be found [here](https://github.com/Budibase/budibase/blob/develop/packages/types/src/documents/app/automation.ts). Importantly the `AutomationStepInput` which is provided to the automation runner, contains the following: +Use `test/index.spec.ts` to verify the step behaves correctly with representative inputs. -| Property | Type | Description | -| :-------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `inputs` | object | A map of the specific inputs the user has specified for this automation, these may have been extracted from context | -| `context` | object | The full automation context, containing the outputs of all prior steps | -| `emitter` | object | An event emitter, used to trigger other events in Budibase (can trigger other automations) | -| `appId` | string | The app ID which this automation is being ran within; can be used with the Budibase API, or functions in [@budibase/backend-core](https://npmjs.com/package/@budibase/backend-core) | +Focus on: -### Test +* Input handling +* Returned outputs +* Error paths +* Any side effects triggered by the step -The `index.spec.ts` test file includes a template unit test for the runner function. testing can be quite simple, just pass in the require inputs and check that the function returns the expected outputs/performs the expected actions; the design of your test will depend on the function of your automation action. +When the action interacts with external services, add tests for auth failures and invalid input as well as the happy path. -Testing is not required for developing an automation plugin, but can be useful when developing, rather than having to run an automation within Budibase, you can check your automation action performs its expected result through a test. +## Add an icon -### Schema +Pick an icon from the [Phosphor icons](https://phosphoricons.com/) set, then set the icon name in `schema.json`. -The schema defines various properties such as the name, icon and the inputs/outputs of your automation action. +Keep the icon name stable once the step is in use, because changing it can affect existing automations. -You can jump to the automation schema page [here](https://docs.budibase.com/docs/automation-schema#schema-structure). +## Development notes -### Adding an icon +* Automation step plugins are action focused +* They are only available in self-hosted Budibase +* `stepId` stability matters more than the display name +* The built-in trigger types are not extended through this plugin path -Adding an icon to your automation action is quite simple, first pick the icon you would like to use on the [Phosphor Icon](https://phosphoricons.com/) site. For example if we you want to use the "list-magnifying-glass" icon shown [here](https://phosphoricons.com/?q=list+magnifying+glass). +## Related guides -Then all you need to do is update your `schema.json` - find the top level `icon` field and set it to `list-magnifying-glass` - this is case sensitive and should not contain spaces. +* [Automation schema](https://docs.budibase.com/docs/automation-schema#schema-structure) +* [Budibase CLI setup](https://docs.budibase.com/docs/budibase-cli-setup) +* [Custom plugin overview](https://docs.budibase.com/docs/custom-plugin) diff --git a/docs/Develop & Scale/custom-plugin/custom-component.md b/docs/Develop & Scale/custom-plugin/custom-component.md index 98395f148..b1efc9a47 100644 --- a/docs/Develop & Scale/custom-plugin/custom-component.md +++ b/docs/Develop & Scale/custom-plugin/custom-component.md @@ -10,599 +10,136 @@ metadata: next: description: '' --- -{` -
-`}
+Custom components let you extend the Budibase builder with your own Svelte-based UI elements. -## Getting started +Use them when the built-in component set does not cover the layout or interaction you need. -Budibase components are written in [Svelte](https://svelte.dev/). +## Before you start -If you are using VSCode for your development, you will most likely want to install the [Svelte plugin](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) to enable syntax highlighting. +Make sure you have: -> 📘 NodeJS version -> -> Make sure you have node v20+ installed. You can run `node --version` to see if you need to upgrade. +* The latest [Budibase CLI](https://docs.budibase.com/docs/budibase-cli-setup) +* Node.js `v20` or later +* A local development environment for Budibase plugins -### Initialise component +## Create the component -Make sure you have the latest [Budibase CLI](https://docs.budibase.com/docs/budibase-cli-setup) installed. Even if you have previously installed the CLI, you may want to install it again to be sure you have the latest version. - -Once that's done, we need to initialise a template for our component. - -Navigate to the folder location you want to create your plugin, and execute the following command: +1. Go to the folder where you want to create the plugin. +2. Run: ```shell budi plugins --init component ``` -Next you will receive a series of prompts to enter details about your component. You can press enter without providing a value if you are happy to use the placeholder. - - - -Within the newly created custom component project you should see a tree structure as follows: +3. Complete the setup prompts. +4. Open the generated project in your editor. - +The template includes: -
+* `Component.svelte` for the component UI +* `schema.json` for the builder settings +* `test/index.spec.ts` for template tests -## Building your component +## Build and watch -After you have created your new plugin directory, execute the following: +Build the project with: -```shell Shel +```shell cd my-component yarn build ``` -Assuming you have [updated the server env variable](https://docs.budibase.com/docs/custom-plugin#hot-reloading-developers-only) you should now be able to see your component template in Budibase: - - - -
- -### Component.svelte - -This is where your svelte code will live for your component. You can use html tags, css styling and bindings as you would for any other svelte component. - -To make sure your saved changes are passed through to your Budibase server, you must execute a `yarn watch` within your custom component project. This will allow your local Budibase app builder to see those changes in real-time, which is very handy for getting your component to look and behave just right. - -> 🚧 -> -> The `use:styleable={$component.styles}` attribute must be included in your top-level component div. Removing this will cause issues when displaying your component. - -
- -#### SDK Context - -The SDK context gives you access to the internal Budibase API. - -```javascript -const { styleable, API } = getContext("sdk") -``` - -The [packages/server/src/api/routes](https://github.com/Budibase/budibase/tree/develop/packages/server/src/api/routes) directory provides all of the available endpoint definitions, and the implementations can be found in the [packages/server/src/api/controllers](https://github.com/Budibase/budibase/tree/develop/packages/server/src/api/controllers) directory. - -This provides a large amount of integration with various aspects of the Budibase platform. - -
- -#### Context - -The context key is a promise of what data bindings the component is going to provide. The builder will use this information to generate data bindings to display, but it's up to the components themselves to provide the data they say they will.\ -Components can provide many contexts, so the value of the context key may be either an object or an array of objects. - -Each context definition supports the following configuration: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Key - - Description - - Possible values -
- type - - The type of context provided - - **static**\ - Static contexts define an array of explicit bindings which are provided by the component. This is used when you know each what data bindings your component provides. - - **schema**\ - Schema contexts are generated dynamically based on settings. The data bindings provided will be the schema of a certain datasource. How this datasource is determined is by looking at the component settings and identifying a setting of type dataSource, table or schema. If the component has a setting of type `dataProvider`, the data provider stack will be traversed upwards until a matching setting is found. Data bindings are then generated for whatever matching datasource is found. The component is expected to provide some sort of row from some datasource if this context setting is used. -
- values - - An array of objects defining which static bindings are available - - An array of objects containing `key`, `label` and `type` properties. - - Defines the readable and runtime values for the binding, in the label and key fields respectively. -
- -Example context: - -```json Context -[ - { - "type": "static", - "values": [ - { - "label": "Row index", - "key": "index", - "type": "number" - } - ] - } -] -``` - -
- -### schema.json - -On the next page we will discuss the intricacies of the component schema.json file - which defines the inputs and outputs of your component, which will be controlled through the component settings panel in the builder. - -You can jump to the component schema page [here](/docs/component-schema). - -
- -### Using TypeScript - -The Budibase svelte components use JavaScript by default. If needed, you can convert your custom component over to TypeScript by following the **Adding TypeScript to an existing project** section of this blog: [https://svelte.dev/blog/svelte-and-typescript](https://svelte.dev/blog/svelte-and-typescript). - -In addition, you may need to install **tslib** i.e. `yarn add tslib`, and add an `index.ts` file. - -An example of a custom component that was ported over can be found in this [TypeScript date-picker](https://github.com/melohagan/budibase-component-kasper-date-picker). - -
- -## Example: Custom form field component - -In this example we will create a Star Rating component that can be added as a field to Budibase Forms. - -> 📘 -> -> This example is taken from the [Star Rating custom component](https://github.com/andz-bb/budibase-component-star-rating) - -This example assumes you already have an empty component [initialised and built.](#getting-started) We're going to focus on the parts that allow this custom component to work as an input within the existing Form component. - -### Updating schema.json - -The first step will be to define the settings that will be available to our form. The most important setting for any form field component is the field that we want the input to be for. In my case, I have a Number column in one of my tables called Rating that I want to be able to use my Star Rating component with. - -We need to add a setting for Field to our component and we can do this by defining it in schema.json. On an empty component template there is a placeholder setting for Text. We will replace this with a setting for Field which will be of type `field/number` and make it a required field. While we're here we can also add a text field for the label. - -component settings within schema.json - component settings within schema.json - - -the new settings for our component now show up in the builder - the new settings for our component now show up in the builder - - -#### Optional: Adding custom validation - -If you would like the user to be able to add component level validation, you can add an validation type settings object to your settings array. We will use this `validation` object later [when registering the form field.](#integrating-with-the-form-component) - -```json schema.json - { - "type": "validation/number", - "label": "Validation", - "key": "validation" - } -``` - - - -You can view [my full schema with extra settings here](https://github.com/andz-bb/budibase-component-star-rating/blob/master/schema.json) or [view documentation for the component schema here.](/docs/component-schema) - -### Working with Component.svelte - -The plugin template comes with a basic placeholder in `Component.svelte` and this is what we will modify to create our custom component. This is written in Svelte - if you are new to it you can [check out the tutorial here.](https://svelte.dev/tutorial/basics) - -The first thing we'll do is declare props for our settings values we created above. The syntax for this is `export let [your-setting-key];` This means we can use the parameters set in the builder in our component. - -Now that our props are added we can continue to build out the front end. Using JS, HTML and CSS we can create the basic interface for our component and then make it functional. - -looks good, now let's make it useful! - looks good, now let's make it useful! - - -### Integrating with the Form component - -The first step here is to get the context from the parent Form component. We can then use that Form Context to register our component as a Field in that Form. - -```javascript Component.svelte -export let field; -export let label; -export let validation; - -const component = getContext("component"); -const formContext = getContext("form"); -const formStepContext = getContext("form-step"); - -const formApi = formContext?.formApi; -$: formStep = formStepContext ? $formStepContext || 1 : 1; -$: formField = formApi?.registerField(field, "number", 0, false, validation, formStep); -``` - -> 📘 formApi.registerField() parameters from our example -> -> * field name - we are using the value of `field` from our props -> * field data type - in this case, the field is for a `number` -> * field default value - we have set that to be `0` here -> * field disabled - ours is `false` here but you could make it configurable -> * field validation - ours is `validation` from props, but can be null if no validation is required -> * form step - we use `formStep` derived from the formStepContext - -As this is a form component, we need to verify that the component is actually being used as a child of a form in our Budibase screen. To do this, I will add a Svelte if/else statement to our component so that it will render our field if it's the child of a form, or show a warning if it's not. - -```javascript Component.svelte - {#if !formContext} -
Form components need to be wrapped in a form
- {:else} - // our component goes here - {/if} -``` - -### Setting the field value - -Now that the field is registered, we have to set it to update the form's properties in the parent component every time the store changes. Using [onDestroy](https://svelte.dev/docs#run-time-svelte-ondestroy) we can deregister our field from our form whenever the component unmounts. - -```javascript Component.svelte -import { onDestroy } from "svelte"; - -let fieldApi; -let fieldState; - -$: unsubscribe = formField?.subscribe((value) => { - fieldState = value?.fieldState; - fieldApi = value?.fieldApi; -}); - -onDestroy(() => { - fieldApi?.deregister(); - unsubscribe?.(); -}); -``` - -Just like that we have everything we need to set a value to our form using our component. - -Consider the **Icon** svelte component: - -```typescript Icon.svelte -= i + 1} - on:click={() => fieldApi?.setValue(i + 1)} -/> -``` - -We determine the how many stars should be filled from `fieldState.value`, and we can set the number of stars in the *on click* event via `fieldApi.setValue('new value here')`. - -### Integrating with Field Groups - -Remember we made a setting for the label above? Now we are going to make our component compatible with the Budibase Field Group component, so the label styling can come from that. In order to make this work we need to get context from the Field Group, just like we did above for the Form component. - -```html Component.svelte - - - -
- -
- // component logic in here -
-
- - -``` - -### Handling errors - -```html Component.svelte -{#if fieldState?.error} -
{fieldState.error}
-{/if} - - -``` - -
- -## Example: Context provider - -Sometimes you want to expose [bindings](https://docs.budibase.com/docs/bindings) to child components without the need of a form component - you do this through [context](https://docs.budibase.com/docs/custom-component#context). - -In this example we will add a toggle component that can provide its boolean state to child components. The codebase can be found here: [budibase-toggle](https://github.com/YuanZhang98/budibase-toggle). - -### Add context to schema.json - -First we need to tell Budibase that this component can take children. We do this with the *hasChildren* property in the `"schema"` object. - -```json -{ - "schema": { - "name": "budibase-toggle", - - "hasChildren": true - ... -``` - -Next provide the context array after the `"settings"` property. The context array provides a list of bindings that will be available to the children. - -```json -{ - "hasChildren": true, - "settings": [..], - "context": [ - { - "type": "static", - "values": [ - { - "label": "Active State", - "key": "isActive", - "type": "boolean", - "defaultValue": false - } - ] - } - ] - ... -``` - -If you now build and import the component, you should see something similar to the following: +During development, run `yarn watch` so your local Budibase instance picks up changes as you edit. - +If you update `schema.json`, refresh the builder so the new settings and bindings appear. -### Implement context binding +## Implement the component -Whilst we have exposed the context, we need to do bind it to our toggle state: +`Component.svelte` is the main entry point for the component UI. -1. Import the **Provider** from the SDK: +Use it to define: -```javascript -const { styleable, Provider } = getContext("sdk") -``` - -2. Next bind the *dataContext* to the toggle state of the component: - -```javascript -let isActive = false; -$: dataContext = { - isActive -} -``` - -3. Add the Provider and slot: - -```html -
- -
...
- -
-
-``` +* Layout and markup +* Styling +* Builder bindings and props -The **Provider** exposes the *dataContext* bindings to the *slot*, which represents any nested child. +If the component needs Budibase APIs, use the SDK context exposed by the plugin runtime. -**Result** +Keep the top-level wrapper on the component and include the `use:styleable={$component.styles}` attribute so Budibase can apply builder styles correctly. - +## Work with context - +Context tells Budibase which bindings the component provides. -
+Use it when your component needs to: -
+* Expose static values +* Expose schema-driven bindings +* Register data from a datasource or data provider -## Example: Data provider +The context definition is a contract with the builder. If the component says it provides a binding, it must actually supply that binding at runtime. -Whilst you can query data from an API within your custom component, it can be better practice to expose a [Data provider](https://docs.budibase.com/docs/data-provider) so that the user has flexibility to choose their own [Datasource](https://docs.budibase.com/docs/data-sources). +Keep the context definition as small as possible and document only the bindings the component actually provides. -### Update the schema +## Configure the schema -Include the following setting in your schema: +`schema.json` defines: -```json schema.json -"settings": [ - { - "type": "dataProvider", - "label": "Data provider", - "key": "dataProvider", - "required": true - } -] -``` - -Which will appear as follows in Budibase: +* The settings shown in the builder +* The type of data the component accepts +* The outputs exposed to other components -![](https://files.readme.io/07254eb-Screenshot_2022-10-13_at_14.38.00.png) +If your component is used inside forms, define the field and validation settings explicitly. - +The schema also controls whether the component can hold children, whether the settings bar is shown, and which styling controls are available. -### Using the data provider +## Register form fields -The data provider has a *rows* property which contains an array of objects for the current page of results. +For form-field components, register the field with the parent form context. -In this example we will look at a [Spotify playlist component](https://github.com/YuanZhang98/budibase-spotify-playlist). +Use the form API to connect the custom component to the form value, field type, and validation rules. -Add the following code to the *script* tag of your component: - -```javascript Component.svelte -export let dataProvider -$: playlists = dataProvider?.rows ?? []; -``` +If the component is not a form field, you do not need to register it with the form context. - The first line assigns the data provider from the settings. Next we get all the rows and default to empty if needed. +## TypeScript support -We can now use the playlists variable to loop over each to be displayed in our component: +The template uses JavaScript by default. - +If you want TypeScript, add it after the component works in JavaScript and update the project setup accordingly. -![](https://files.readme.io/1a25e03-Screenshot_2022-10-13_at_14.47.17.png) +The migration path is incremental: -
+1. Make the JavaScript version work. +2. Add TypeScript support. +3. Move the entry file to `index.ts` if needed. +4. Keep the component API unchanged while you change the implementation language. -## Example: Event handler +## Testing -As seen in the component [Actions](doc:actions) it is possible for components to have *On Click*, *On Change* or any other event! +Use `test/index.spec.ts` to verify the component renders and exposes the expected behaviour. -In this example, we will look at a [timer component](https://github.com/doggodoge/bb-timer) that will trigger some user specified action when the count down goes to zero. +Focus on: -### Update the schema - -Include the following setting in your schema: - -```json schema.json -"settings": [ - { - "type": "event", - "key": "timeout", - "label": "On Timeout" - } -] -``` +* Required props +* Context registration +* Form integration +* Validation behaviour -This will appear in the Budibase builder like so: +For components that expose builder settings, also test that the schema and runtime props stay in sync. - +## Example usage -### Wiring the event +The star rating example in this section is most useful as a pattern for form components: -The user is now able to trigger any sequence of Budibase actions upon the *On Timeout* event. We now need to determine when to fire this event. - -To do this we will need to import the Event Dispatcher from Svelte and then fire our event. This can be done like so: - -```typescript Timer.svelte -import { createEventDispatcher } from 'svelte'; -const dispatch = createEventDispatcher(); - -... - -if (counter < 1) { - dispatch('timeout'); -} -``` - -Then in the parent component, we take a prop which matches the key name **timeout**, and also include the **on** listener like so: - -```html Component.svelte - - -
- -
-``` - -### On change event - -An *On Change* event will be similar to the above, but you also will want to provide context to expose the `{{ Field Value }}` binding. - -To do so, add the following to your **schema.json**: - -```json schema.json -"settings": [ - { - "type": "event", - "label": "On Change", - "key": "onChange", - "context": [ - { - "label": "Field Value", - "key": "value" - } - ] - } -] -``` - -Then you can use your *onChange* function similar to the following: - -```html Component.svelte - - -
- -
-``` +* add a field setting in `schema.json` +* map that setting to a prop in `Component.svelte` +* register the field with the parent form +* apply validation only where the form needs it -It is important to note that we are providing an object with the 'value' key, to make sure Budibase can detect the binding. +Keep examples focused on one integration path. That makes the component easier to adapt to another use case later. -
+## Related guides - +* [Component schema](/docs/component-schema) +* [Budibase CLI setup](https://docs.budibase.com/docs/budibase-cli-setup) +* [Custom plugin overview](https://docs.budibase.com/docs/custom-plugin) diff --git a/docs/Develop & Scale/custom-plugin/custom-datasource.md b/docs/Develop & Scale/custom-plugin/custom-datasource.md index 42f839730..c7f40eee8 100644 --- a/docs/Develop & Scale/custom-plugin/custom-datasource.md +++ b/docs/Develop & Scale/custom-plugin/custom-datasource.md @@ -10,361 +10,121 @@ metadata: next: description: '' --- -
-
-`} +This page shows the key configuration points for `Caddy` and `NGINX`. -*** +## Before you start -## Caddy +Make sure you have: -Caddy is an open-source web server with automatic HTTPS written in Go. If you want to get HTTPS up and running on your Budibase instance as quickly as possible with caddy, go through the following steps. +* Budibase running on the target host +* A domain name you control +* A reverse proxy installed or available to install -### Install Caddy +## Caddy -Follow the [Caddy installation instructions](https://caddyserver.com/docs/install). -Once you have done this, you should be able to check that you have Caddy available on your machine, using the following command. +Caddy is the quickest option if you want automatic HTTPS. -``` -caddy version -``` +1. Install Caddy. +2. Create a `Caddyfile` for your domain. +3. Add a reverse proxy rule that points to the Budibase service. +4. Start or restart Caddy. -Next, [create a Caddyfile](https://caddyserver.com/docs/quick-starts/caddyfile) with your domain in it - basically, create a text file named Caddyfile (no extension), then add your domain to the file. +Example: -``` +```text yourdomain.com reverse_proxy localhost:10000 ``` -To set up HTTPS on your domain, you can simply restart the caddy server: - -``` -caddy stop -caddy start -``` - -That's it! Full HTTPS and reverse proxy setup with Caddy and Budibase. Visit your domain and you will see your newly secured budibase instance with a custom domain. - -*** +Use this when you want a simple path to HTTPS without managing certificates manually. ## NGINX -Please note, this section assumes some knowledge of NGINX installation, setup, and configuration. Information about NGINX can be found here: +NGINX is the better fit when Budibase is one service behind a larger proxy setup. -* [installation](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/) -* [setup](https://docs.nginx.com/nginx/admin-guide/basic-functionality/runtime-control/) -* [configuration](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/) +Use a server block that: -Our recommendation for running Budibase is a "many app one server" approach, where many different apps can be deployed to the same self-hosted Budibase platform. Below we have detailed a basic method for getting Budibase up and running behind a reverse proxy, which you can then update to add into an existing configuration or add SSL information. +* Listens on the desired domain or subdomain +* Proxies requests to the Budibase host +* Passes through the forwarded headers Budibase needs +* Sets an appropriate `client_max_body_size` -Here is a basic reverse proxy configuration that will simply pass all requests from a domain/sub-domain/path to your Budibase platform. - -``` -# Budibase +Example: +```nginx server { listen 80; server_name yourdomain.com; - + location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; @@ -84,26 +74,26 @@ server { proxy_http_version 1.1; proxy_pass http://localhost:10000; } - + client_max_body_size 50m; } ``` -In this configuration, all that needs to be updated for this to work is where the Budibase platform has been hosted. If it is hosted on a different machince, replace **localhost** with the correct address. +## Common adjustments -There are a few ways this can be extended/altered: +If the proxy sits on another host, replace `localhost` with the correct upstream address. -1. This is just a basic version which will proxy on any requests to your domain/sub-domain to the Budibase platform, you can change the **server_name** to suit your needs. -2. Where **location /** has been set you can change the slash to a pathname if you desire to have your Budibase app server running on a specific path rather than the whole domain or a sub-domain. -3. Lastly if you want to make use of HTTPS/TLS you can either configure this basic configuration to re-direct traffic to HTTPS and then add your certificate, or you can use [certbot-auto](https://certbot.eff.org/) to automatically generate and look after the certificates for your domain! +If you want Budibase on a path rather than a whole domain, change the `location` block accordingly. -## Proxy Buffer Settings +If you enable TLS through NGINX, either add certificates manually or use a certificate tool such as Certbot. -Some users have reported problems when using a reverse proxy such as Nginx Proxy Manager and external authentication (e.g. OpenID). Users may see the error `502 Bad Gateway openresty` +## Proxy buffer issues -In this case amending the proxy buffer size may be helpful. Example config is shown below for Nginx: +If you see `502 Bad Gateway openresty` with external authentication, increase the proxy buffer sizes. -``` +Example: + +```nginx server { proxy_busy_buffers_size 512k; proxy_buffers 4 512k; @@ -112,32 +102,16 @@ server { } ``` -## Strict Referrer Policy and other security settings - -There are a few caveats with reverse proxies that operators need to pay close attention to—especially when running Budibase behind Nginx, Traefik, Caddy, or any proxy layer that modifies or strips HTTP headers. Some security-focused defaults can unintentionally break core platform functionality. +## Referrer policy -### Referrer Policy and Workspace App Matching +Budibase can rely on the `Referer` header when matching a workspace app to a request path. -Budibase’s server **relies on the Referer header** in a specific part of the request lifecycle. The platform extracts the URL path from the incoming request’s Referer header. If a reverse proxy strips the Referer, changes it, or prevents it from flowing through, Budibase may fail to match the correct workspace app and respond with: +If your proxy strips or rewrites that header, Budibase may fail to find the correct workspace app. -``` -“No matching workspace app found for URL path…” -``` - -To preserve Budibase functionality while keeping sane security defaults, adjust your policy for the Budibase domain: - -``` -server { - add_header Referrer-Policy same-origin; +Keep the header available for the Budibase domain and use a conservative referrer policy that still preserves matching. - location / { - proxy_set_header Referer $http_referer; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Host $host; - proxy_pass http://your-budibase-upstream; - } -} -``` +## Related guides -
\ No newline at end of file +* [Accessing CouchDB](doc:accessing-couchdb) +* [Accessing MinIO](doc:accessing-minio) +* [Hosting methods](doc:hosting-methods) diff --git a/docs/Settings/branding.md b/docs/Settings/branding.md index 1d87b1501..902e9e93d 100644 --- a/docs/Settings/branding.md +++ b/docs/Settings/branding.md @@ -10,141 +10,63 @@ metadata: next: description: '' --- -There are several ways in which you can customise the branding of your Budibase instance and, of course, your applications! +Use Branding to control the visual identity of your Budibase instance and applications. -> 📘 Licensing🔒 +> 📘 Licensing > -> The following features are only available to customers with a **Premium** or **Enterprise** plan. -> -> You can view more details on [our pricing page.](https://budibase.com/pricing/) - -In the Budibase **admin portal**, navigate to the to the branding section, **Settings > Branding**. In here you can manage all available elements of your Budibase branding configuration. - -{` - -`} - - - -
- -
- -
- -
- -
- -
- -
- -
- -
- -### Logo - -Easily the most impactful part of your branding. Your custom logo will be visible in the **portal header**:and the **app navigation** - -You can, of course, update the logo on a per application basis. In the **builder design section**, you can override the global branding and configure a logo especially for your application navigation. - -For **self host** environments, your logo will also appear in your Budibase login page! - - - -
- -
- -
- -
- -
- -
- -
- -### Favicon - - - -If a custom favicon has been set, it will be displayed in the tab for any **published** or **previewed** application. - -In **self host** environments, the favicon will also appear in your Budibase login and authentication pages! - -### Title (Self Host) - -For **self host** environments, the title attribute can be used to customise the tab text for your Budibase login and authentication pages. - -### Email Branding - -Emails sent from Budibase will carry our branding header, as shown below.If you would like to remove this from your Budibase emails and customise your correspondence, simply flip the toggle. - - - -### Login Customisation (Self Host) - -With a self hosted instance of Budibase you can further customise elements of the log in screen. - - - -#### Available options - -* **Header** - the main text below your branding. Currently this defaults to **Log in to Budibase** -* **Button** - the text displayed on the login button. Currently this defaults to **Log in to Budibase**. -* **Remove Testimonials** - Testimonials currently default to **enabled** but you can flip the toggle and remove them if you wish - -Your fully customised home page: +> Branding options are available on Premium and Enterprise plans. - +## Branding settings -### App Preview Meta tags +Open `Settings > Branding` in the admin portal to manage global branding. -Meta tags are primarily used to describe your application to search engines or when sharing a link to your application via social media. +Common settings include: -If you post the link to your application on e.g **Facebook**, **Twitter** or **Slack**, you would typically see a card that looks something like this: In the branding section, you can customise the look and feel of your applications meta data with the following **optional** properties. +* Logo +* Favicon +* Title for self-hosted login pages +* Email branding +* Login screen text and buttons for self-hosted instances +* App preview meta tags - +## Logo -
+Use the logo setting to control the branding shown in the portal, app navigation, and self-hosted login pages. -
+If a specific app needs different branding, override the global logo in the app builder. -
+## Favicon -
+Set a custom favicon to change the browser tab icon for published and previewed apps. -
+On self-hosted instances, the favicon can also appear on login and authentication pages. -
+## Email branding -#### Image URL +Use email branding to remove or replace the Budibase header in outgoing emails. -Use the **Image URL** property to configure a custom branding image URL. +Keep the sender identity and the email template aligned so the message feels consistent. -Ensure the target image is **appropriately sized** for the media preview of your target platforms. +## Self-hosted login customisation -Lastly, be mindful of the **availability** of the file when configuring this property. If the file is inaccessible when sharing your application link, the card will not render as intended. +Self-hosted instances can change the login page header and button text. -#### Title +Use this when you want the login experience to match your organisation’s terminology. -The default behaviour for the meta title combines the **application name** with **"- built with budibase."**. -For example, if your application was called "My Expenses Portal", it would be displayed as **"My Expenses Portal - built with budibase."** +## App preview meta tags -You can use the **Title** property to override this behaviour. Any value set here will **override all app titles** displayed in meta cards. +Use meta tags to control how your app appears when shared in chat or social previews. -#### Description +Configure: -The description field is entirely optional. A description typically provides supplementary information about the target, or in this case, additional information about your organisation/apps. +* Image URL +* Title +* Description -#### App Meta Card example +Make sure the preview image is publicly reachable when the link is shared. -The following is an example of some of the custom meta card elements in action. Our custom branding has replaced the Budibase default and we now have our own description. +## Related guides - +* [Email](doc:email) +* [User management](doc:user-management) +* [Settings overview](doc:settings) diff --git a/docs/Settings/email.md b/docs/Settings/email.md index 877fc1fc0..d3d218d5d 100644 --- a/docs/Settings/email.md +++ b/docs/Settings/email.md @@ -10,150 +10,80 @@ metadata: next: description: '' --- -For Budibase to send emails, you must configure an SMTP Mail Server, such as Gmail SMTP or SendGrid. After you have set this up, you can [invite users](doc:user-management) and send emails using the email [Action](doc:automation-actions). - -### Email setup - -{` -
-`}
- - - - - - - - - - - - - - - - - - - - - - - +Configure SMTP to let Budibase send email for invitations, password recovery, and automation actions. - +## Before you start - - +Make sure you have: - - +* An SMTP provider such as Gmail SMTP or SendGrid +* The host, port, username, and password for that provider +* Access to the Budibase admin portal - +### SMTP settings - - +| Setting | Purpose | +| :--- | :--- | +| Host | SMTP server address. | +| Security type | Encryption mode used by the server. | +| Port | SMTP port exposed by the server. | +| From email address | Address used as the sender. | +| Require sign-in | Enables SMTP authentication. | +| Username | SMTP account username. | +| Password | SMTP account password. | - - +Use the values required by your provider. For modern SMTP setups, ports `587` and `2525` are the most common choices. - +## Email templates - - +Budibase includes templates for: - - +* Password recovery +* Invitation +* Welcome +* Custom templates - +To edit a template: - - +1. Open the template from the email settings table. +2. Add any bindings or static content you need. +3. Preview the result. +4. Save the template. - - - - - - - +Use bindings for values such as the recipient email address, your organisation name, or a logo URL. - - +## Use email in automations - +Once SMTP is configured, you can send email from automation actions. - - - -
- Property - - Description - - Example answer -
- Host - - An SMTP email server will have an address (or addresses) that can be set and is generally formatted as smtp.serveraddress.com. - - email-smtp.eu-east-1.amazonaws.com -
- Security type - - Both SSL and TLS facilitate email sending - - None/STARTTLS -
- Port - - An “SMTP port” refers to the specific part of the Internet address that’s used to transfer email. +## Configure SMTP - If you run your own SMTP server you can find the configured SMTP port number and address from the SMTP server configuration. +1. Open the Budibase admin portal. +2. Go to `Settings > Email`. +3. Enter the SMTP details. +4. Save the configuration. +5. Send a test email if your provider supports it. - Ports 25, 465, 587, or 2525 for SMTP have all been considered standard SMTP ports at some point, but only 587 or 2525 really should be considered for modern use. - - 587 -
- From email address - - The email address your onboarding emails are sent from. - - [noreply@budibase.com](mailto:noreply@budibase.com) -
- Require sign-in - - SMTP auth - some SMTP server hosts require auth to send email. - - True udibase to se -
- Username (visible when require sign-in is checked) - - Username for SMTP server - - AKIAX5ZKDVGGJ2SASAHT2M7Z -
- Password (visible when require sign-in is checked) - - Password for SMTP server - - Password!23IhopeNot -
+Common uses include: -  +* User invitations +* Password recovery +* Workflow notifications +* Approval and rejection messages -## Templates +Keep sender addresses and template content aligned with your domain so mail is less likely to be flagged as suspicious. -Budibase comes with three different email templates: Password Recovery, Invitation, and Welcome. In addition to that, you can also create custom templates. +## Troubleshooting -To edit a template, simply select it in the table. To insert dynamic content you can use the Bindings on the right side of the page. This makes it easier to include things such as the user's email, your organization's logo, or the name of your organization. When you're done hit the preview button to make sure it looks OK. Then hit save. +If email does not send: -The email templates work on all devices, email platforms, and themes (light and dark modes). Below is an image of the invitation email template. +* Confirm the SMTP host and port are correct +* Check whether authentication is required +* Verify the from address is allowed by the provider +* Confirm the provider is not blocking the connection - +## Related guides -## Video tutorial - -{` - -`} +* [Automation actions](doc:automation-actions) +* [User management](doc:user-management) +* [Branding](doc:branding) From 4120a4fa7edf489bb7d876752d88e2551653e97f Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 11:34:15 +0100 Subject: [PATCH 04/32] fourth batch update --- docs/Apps/screens.md | 93 +++++++++--------- docs/Automation/automation-actions/index.md | 65 ++++++------- docs/Automation/trigger/index.md | 52 +++++++--- docs/Automation/trigger/webhook.md | 94 ++++++------------- docs/Data/data/index.md | 57 ++++++----- .../Getting started/quickstart-budibase-ai.md | 60 +++++++----- docs/Settings/user-management/index.md | 39 ++++++-- 7 files changed, 241 insertions(+), 219 deletions(-) diff --git a/docs/Apps/screens.md b/docs/Apps/screens.md index b412a1d87..edfdec629 100644 --- a/docs/Apps/screens.md +++ b/docs/Apps/screens.md @@ -10,90 +10,81 @@ metadata: next: description: '' --- -Budibase Workspaces contain apps, which are single-page applications that contain either a single screen or multiple screens. +Screens are the pages that make up a Budibase app. -## Adding a screen +Use screens to present data, collect input, or launch actions. -When adding a screen, you can either add a blank screen or add an autogenerated screen. +## Add a screen - +You can create either: -### Blank screens +* A blank screen +* An autogenerated screen from a datasource or table -When adding a blank screen, you will be prompted to enter a path for the new screen.\ -Capital letters and spaces are not allowed, however the modal will conveniently convert these to lowercase and hyphens if needed as you type. +Blank screens are useful when you want full control over the layout. -### Autogenerated screen +Autogenerated screens are useful when you want Budibase to create the basic CRUD flow for you. -An autogenerated screen, is a screen generated from a table's data. Budibase is smart, it can read your data and generate tables and side panels for managing that data. When you add an autogenerated screen, Budibase will add a screen with a single preset [table](/table) . +## Screen types -> 📘 Prior to v2.2 -> -> The original autogenerated screen functionality created multiple linked screens. Newer versions of Budibase are backwards compatible with this method, which can still be built using [URL variables](doc:url-parameters).\ -> The advantage of side panels is convenience for the user and developer, as well as better app performance. +### Blank screens -#### Adding autogenerated screens +Use a blank screen when you want to build the page manually. -When adding an autogenerated screen, either a table or a form, you will be presented with options of the available data sources. Multiple sources can be selected at the same time. Once you have selected the data source(s) you will be presented with options for the type of form (for an autogenerated form screen), or how you would like to manage your rows (for an autogenerated table screen). +Choose a path for the screen and then add the components and data you need. -Selecting tables as data sources for autogenerated screens - Selecting tables as data sources for autogenerated screens - +### Autogenerated screens -Selecting row-management methods for autogenerated table screens - Selecting row-management methods for autogenerated table screens - +Use autogenerated screens when you want Budibase to create a table or form layout from a datasource. -Selecting row-management methods for autogenerated form screens. - Selecting row-management methods for autogenerated form screens. - +This is the fastest way to create a working CRUD interface. -These screens will be generated and connected to your tables for full CRUD functionality, allowing users to Create, Read, Update, and Delete data. +## PDF screens -## Home screen +If your plan includes PDF exporting, you can also create a PDF screen. -To assign a home screen, tick *Set as home screen*. +Use a PDF screen when you want to generate downloadable report-style output from app data. - +PDF screens support: -To indicate that it is the home screen, you will see a house icon in the screens panel. +* Standard grid layout +* Components such as tables, text, and images +* Data providers and bindings for dynamic content +* Custom title and button text in the screen settings - +The PDF title also controls the downloaded file name. -## Modal screen +## Home screen -A screen can be opened as a modal from a Navigate To action. (Note: this is not the same as having a Modal component) +Mark a screen as the home screen if you want it to open first when the app launches. - +## Modal screens -Within the target screen you can use the **Close Screen Modal** [Action](doc:actions) to close the modal and return you to the original screen. +You can open a screen in a modal from a `Navigate To` action. - +Use `Close Screen Modal` to return to the original screen when the modal task is complete. ## Access level -Screens are grouped and displayed by the chosen access level. If you have many screens, you can also use the search bar. +Screens are grouped by access level. - +Use access levels to control who can see a screen in the app. -
- -The access level can be changed for any screen in the settings panel.\ App specific roles will determine if a user has the necessary permissions to see the screen. - - +If you use app-specific roles, make sure each screen is assigned to the correct audience. ## On screen load -It is possible to fire [Actions](doc:actions) on load of the screen. Within the Settings Panel of the screen node, click the button beside *On screen load* to add some actions. - - +Use the screen load action area when you want something to happen as soon as the screen opens. -Here you could do a variety of things such as a conditional redirect, [Trigger an automation](doc:trigger), or even set some initial [App state](doc:app-state). +Common uses include: -
+* Initial redirects +* Triggering an automation +* Setting initial app state -## Video tutorial +## Related guides -{` - -`} +* [Actions](doc:actions) +* [App state](doc:app-state) +* [User roles](doc:user-roles) +* [PDF exporting](doc:pdf-exporting) diff --git a/docs/Automation/automation-actions/index.md b/docs/Automation/automation-actions/index.md index 187c43d4b..cdb410131 100644 --- a/docs/Automation/automation-actions/index.md +++ b/docs/Automation/automation-actions/index.md @@ -13,53 +13,50 @@ metadata: next: description: '' --- -Actions are the core of automations. Actions can carry out updates on a table, call to an external service, send emails, and so on. We have built our action system to be easily extensible so actions can be added to the system at any time! Your automation can have many actions, allowing you to perform many different tasks as part of a single trigger. +Actions do the work in an automation after the trigger runs. - +Use actions to: -Below is a few examples of actions that exist today however there may be many more when you look in the builder. To get a full list install the builder and check it out! +* Create or update rows +* Call external services +* Send notifications +* Run scripts +* Query data -1. **Create row** - this will create a new row in a specified table -2. **Update row** - can be used to update a row that was triggered upon -3. **Delete row** - delete a specified row from a table, like something that was triggered upon -4. **Send email** - as it suggests, send an email based on the specified inputs -5. **Send Discord notification** - send a notification to Discord -6. [Slack](doc:slack-notification) - send a notification to Slack -7. **Connect to Integromat** - connect to Integromat -8. **Connect to Zapier** - connect to Zapier -9. **JS scripting** - add JS scripts to an automation -10. **Query rows** - query rows / records +## Common action types -The real power in actions is the ability to make use of outputs from previous steps; how to do this will be covered in the [Contextual bindings](doc:contextual-bindings) section. +Common built-in actions include: -*** +* Create row +* Update row +* Delete row +* Send email +* Send Discord notification +* Slack notification +* Query rows +* JavaScript scripting +* Connect to Zapier or Integromat -## Adding logic +## Use outputs -Sometimes it is necessary for your automation to make decisions as part of the process, for example, if you wanted to send an email to a customer when their order enters the shipped state then you would need a logical step to handle this. An automation can have as many logical steps as you require, if you wish to filter against multiple different outputs from previous steps then this can be done with multiple filters. +Actions become more useful when they consume outputs from earlier steps. -Currently, there are two actions that allow you to add logic to an automation +Use contextual bindings to pass values from one step to the next. -1. **Filter** - Filtering against a specified field, with a particular operator and value to compare against -2. **Delay** - waiting a period of milliseconds before continuing +## Add logic -*** +Automations can also include logic steps. -## Naming automation steps +Use logic when you need to: -When you have many steps in an automation, keeping track of the step numbers can be difficult, particularly in your Bindings. +* Branch on a condition +* Delay the next step +* Filter based on a previous output -To make your automation easier to manage, you can give your steps a name. This will automatically update any bindings as well! +## Name steps -For example, consider this example automation: +Name each step clearly so bindings are easier to read later. -* Step 1: Create Row -* Step 2: Log the response of step 1 +Renaming a step also updates the bindings that reference it. - - -The binding `{{ steps.Create row.response }}` isn't very informative. We can however change the name of *Step 1* to 'Add Expense' which will automatically update the binding to something more useful: - -The binding 'steps.1.response' has automatically been updated - The binding 'steps.Create row\.response' has automatically been updated - +Keep names short and descriptive, especially in longer automations. diff --git a/docs/Automation/trigger/index.md b/docs/Automation/trigger/index.md index 1d2b2e663..a258628ea 100644 --- a/docs/Automation/trigger/index.md +++ b/docs/Automation/trigger/index.md @@ -10,24 +10,46 @@ metadata: next: description: '' --- -Each automation must have a single trigger step, which is essentially a watcher - waiting for a particular condition to be met, at which point the process will kick off. +Every automation starts with a single trigger. - +The trigger listens for an event, then starts the automation when that event occurs. -Currently, there are six ways to trigger an automation: +## Trigger types -1. When a new record/row is created in a table -2. When a new record/row is deleted in a table -3. When a new record/row is updated in a table -4. An external trigger in the form of a JSON Webhook -5. When a certain action happens in an app -6. CRON trigger (trigger this automation at a specific time or day) -7. Email received in a specific inbox +Budibase supports these trigger patterns: -> 📘 Row creation/update/deletion triggers -> -> When utilising row-based triggers, it should be noted that this only works for rows created through Budibase. If you are using an external data source, like say Postgres or MySQL, then rows created externally within the database will not trigger automations. +* Row created +* Row deleted +* Row updated +* Webhook +* App action +* Cron schedule +* Email received -Triggers are internal to the Budibase system and therefore cannot easily be altered - if you have an idea for a good trigger, then [let us know](https://github.com/Budibase/budibase/discussions)! +## Row-based triggers -It is also possible to create custom triggers using the external Webhook - create an external application that will trigger on your required conditions, and target your Budibase Webhook! +Row triggers only respond to rows created through Budibase. + +If you use an external datasource such as PostgreSQL or MySQL, changes made directly in that database do not fire Budibase row triggers. + +Use row triggers when you want to react to changes made inside Budibase itself. + +## External triggers + +Use a webhook trigger when another application needs to start a Budibase automation. + +This is the right option when: + +* The event starts in another service +* You need to pass a JSON payload into Budibase +* You want an external system to call Budibase on demand + +## Trigger guidance + +Keep triggers narrow and predictable: + +* Use one trigger per automation +* Pick the trigger type that matches the source of the event +* Use app actions, cron, or email triggers only when they fit the workflow + +If you need a trigger type that Budibase does not provide, use a webhook-based integration or raise a feature request. diff --git a/docs/Automation/trigger/webhook.md b/docs/Automation/trigger/webhook.md index 66b0237bd..686bfd695 100644 --- a/docs/Automation/trigger/webhook.md +++ b/docs/Automation/trigger/webhook.md @@ -12,84 +12,48 @@ metadata: next: description: '' --- -> A webhook is an HTTP-based callback function that allows lightweight, event-driven communication between two APIs. +Use a webhook trigger when an external service needs to start a Budibase automation. -Contextually, webhooks allow Budibase to listen for an external application event, and trigger an automation. A payload will be included in the trigger that gives Budibase information about the event. +The external system sends a JSON payload to Budibase, and Budibase uses that payload to start the automation. -
+## Set up the trigger -{` - -`} +1. Create a new automation. +2. Select `Webhook` as the trigger. +3. Open the trigger settings. +4. Copy the schema URL. +5. Send a sample payload to that URL. +6. Refresh the builder after Budibase accepts the schema. -## Setup +Use a payload from the external service you plan to connect, then shape the automation around the fields Budibase receives. -Create a new automation and select `Webhook` as the trigger. +## Link the external app -This will present you with a box. To view the details for this step, click on it this should open a side panel with additional information. +Copy the trigger URL from Budibase into the external system’s webhook configuration. - +Make sure the external service sends JSON to the trigger URL. -The **Schema URL** is required to tell Budibase what payload to expect from the external application. +## Build from the payload -Click the `Set Up Webhook` button. This will bring up a dialog with the schema URL. Copy the schema URL. +Once Budibase knows the payload shape, you can add steps that use the trigger data. -Let's assume for this example we want to save a row to a Budibase table any time a new issue is created in our GitHub repo. +Common patterns include: -Conveniently we can grab an [example payload](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#webhook-payload-example-when-someone-edits-an-issue) from the GitHub webhook docs. +* Creating a row from the payload +* Filtering on a field such as an action or event type +* Triggering a follow-up automation -Next open Postman, or any other REST query tool, and POST the example payload to the schema URL. +## Test the workflow - +After publishing the automation: -After you receive the `200 OK` response, you should now see that Budibase has successfully picked up on the schema. Click _Finished_. +1. Send a real event from the external app. +2. Confirm the automation runs. +3. Check the automation history for the result. +4. Verify any downstream row or action changes. - +## Related guides -Finally click the `Publish` button in the top right of the screen to make the automation live. - -## Link the trigger application - -Copy the **Trigger URL** from your Budibase automation and paste it into the _Payload URL_ of your GitHub webhook. - -Make sure **Content type** is _application/json_ - - - -Click `Add webhook`. - -To test, add an new issue in your GitHub repo. Within a minute, you will be able to see that the automation was triggered via the [Automtion history](https://docs.budibase.com/docs/logs). - - - -## Trigger body - -Now that we know that GitHub events are being picked up by our Budibase application, lets do something with the event data. For example, we may want to create a new row in our own 'Issues' table. - -Create a new 'Issues' table with a text _Name_ column, a number _Number_ column, and an options type _Tag_ column. - - - - - -Next within the _Automation_ tab, add an additional [Condition](https://docs.budibase.com/docs/conditions-1) step. This is because we only want to create a row if the GitHub action type is _opened_. - -Add the `{{ trigger.action }}` binding to the _Reference Value_ field. - - - -Select condition _Equals_ comparison value 'opened'. - - - -Add another automation step for **Create Row**. Select _Use bindings_ as well as the 'Issues' table. Fill in the bindings. - - - -You can click `Finish and test automation` to verify your automation. Don't forget to press **Publish** when you're done. - -Now when a new issue is created in your GitHub repo, you should see a new row in your Budibase table. - - - - +* [Automation steps](doc:automation-steps) +* [Automation testing](doc:activating-and-testing) +* [Automation logs](doc:logs) diff --git a/docs/Data/data/index.md b/docs/Data/data/index.md index d18731a56..5cfa9f257 100644 --- a/docs/Data/data/index.md +++ b/docs/Data/data/index.md @@ -25,38 +25,53 @@ next: slug: rest title: REST API --- -The data section in the Budibase UI is where you add and manage your data. Budibase workspaces rely on data and it is strongly advised to create your data structure before designing your web application or automation. Your data structure will involve tables, columns, rows, and views - these are the building blocks that hold and present your data in a structured manner. +Use the Data section to add and manage the tables, views, and datasources that power your workspace. -Predefining the data structure also greatly helps in building the UI as the UI can be automatically generated based on the data structure, as well as any logic, filtering, and sorting. +Your data model should usually come first. It shapes the screens, automations, filters, and permissions you build later. -Within Budibase we have a single built-in Datasource and several external datasources. When using a self-hosted instance of Budibase, an external datasource can still live on the same device, just not within the Budibase container. +## What data is for -Any datasources you create will be available to use within all apps and automations in your workspace. +Use data to: -## Getting started with data +* Store rows and fields in a structured way +* Define relationships between records +* Control what users can read or write +* Generate screens and automation inputs -By default, every Budibase workspace will start with a Budibase DB datasource. This database contains a [Users table](doc:users-table) which is considered a special table that cannot be removed. This table includes all the users who have access to your application, with their respective roles. +## Budibase DB -{` -
-`}
+Every workspace starts with a Budibase DB datasource. -## Adding new datasources +The built-in `Users` table lives there as well and cannot be removed. -There are a broad set of available external datasources you can connect to right from the Budibase UI. +Use Budibase DB when you want the simplest path to app data or when you are prototyping a new workflow. -You can add new data sources by clicking the `+` button on the left-hand panel when you're on the Data tab, as seen in the image below. +## Add datasources -Adding a datasource - Adding a datasource - +Add datasources from the Data tab. -Once you've clicked the `Add source` button, you'll see a modal presented with the available datasources. Pick your datasource of choice, and you will be presented with a configuration screen to connect to your remote datasource. You can also [use AI to generate](/docs/ai-powered-table-generation) a new Budibase DB table for you. +Common source types include: -Choose a datasource - Choose a datasource - +* External SQL databases +* REST APIs +* Document databases +* Budibase DB tables -You can add as many datasources as you need following the same process. +After you add a datasource, you can create tables, configure views, and reuse that data across apps and automations in the same workspace. -To know more about a particular datasource, look at the relevant documentation page in the menu. +## Data workflow + +A typical workflow looks like this: + +1. Define the data model. +2. Add the datasource. +3. Configure tables and columns. +4. Add views and permissions. +5. Build screens and automations on top of that data. + +## Related guides + +* [BudibaseDB](doc:budibasedb) +* [PostgreSQL + MySQL](doc:postgresql) +* [MongoDB](doc:mongodb) +* [REST API](doc:rest) diff --git a/docs/Getting started/quickstart-budibase-ai.md b/docs/Getting started/quickstart-budibase-ai.md index 8f41d4dac..89b1f0776 100644 --- a/docs/Getting started/quickstart-budibase-ai.md +++ b/docs/Getting started/quickstart-budibase-ai.md @@ -20,37 +20,51 @@ next: slug: generating-javascript-with-ai title: Generating JavaScript with AI --- -## Enabling Budibase AI +Use Budibase AI after you connect a model provider in your workspace settings. -To start using Budibase AI, configure an AI provider in your Workspace. +## Enable AI -1. Open your Workspace **Settings**. -2. Go to **Connections > AI models**. -3. Choose a provider (for example Budibase AI, OpenAI, Anthropic, Google, Mistral, OpenRouter, or Groq). +1. Open your workspace settings. +2. Go to `Connections > AI models`. +3. Choose a provider. 4. Enter the required credentials and model details. -5. Save and enable the configuration. +5. Save the configuration. -AI features are workspace specific, so you will need to connect to these again in other workspaces if you wish to enable AI functionality. +AI features are workspace specific. Repeat the setup in each workspace where you want AI enabled. -For a full breakdown of the new setup area, see [Connections](doc:connections). +If you are self-hosting, make sure your plan and license support Budibase AI. -> 📘 If you are self-hosting and want to use Budibase AI, you need to make sure you are on an Enterprise plan and have a active license key in your Workspace. See the [Tenant management guide](doc:tenant-management). +## Where you can use AI -## Where You Can Use AI +Budibase AI is available in several parts of the product: -Once enabled, Budibase AI can assist in various areas of Budibase: +* AI Columns for generating or transforming data +* Binding fields for generating JavaScript +* Cron job expressions +* Agents for building AI assistants that can read data, use tools, and trigger automations +* AI automation actions +* Budibase DB table generation -* [AI Columns](doc:ai-column) - Automatically generate values for columns using AI, perfect for transforming, summarizing, or cleaning data. -* [Generate JavaScript with AI](doc:generating-javascript-with-ai) - You'll now see an AI icon in any field that supports bindings (e.g., visibility rules, dynamic values). Click it to open a prompt where you can describe what you need. Budibase AI will return usable JavaScript tailored to your input. -* [Cron Job Expression Generation](doc:cronjob#configuring-the-cron-expression) - In the settings area for the cron job, you'll see a field called "Generate Cron Expression with AI", simply type in your prompt and this will provide you with an expression that suits your needs. -* [AI Automation Actions](doc:ai-automation-steps-overview) - Triggerable automation actions that leverage AI, including classifying, generating, and categorising text, extracting document data, or executing custom prompts within automation rules. -* [Generate Tables in Budibase DB](doc:ai-powered-table-generation) - Leveraging Budibase AI to generate schemas for Budibase DB tables, which can be leveraged across your Workspace. +## Practical guidance -AI Automation Actions in Budibase +Use AI where it saves repetitive work. -Generate table schemas for your Workspace with Budibase AI +Good fits include: + +* Schema generation +* Cleanup or summarisation tasks +* JavaScript drafts +* Automation prompts + +Review generated output before using it in production. + +## Related guides + +* [Agents](doc:agent-building-101) +* [Agent instructions guide](doc:agent-instructions-guide) +* [Agent tools and permissions](doc:agent-tools-and-permissions) +* [Agent testing guide](doc:agent-testing-guide) +* [AI Column](doc:ai-column) +* [AI automation actions](doc:ai-automation-steps-overview) +* [Generating JavaScript with AI](doc:generating-javascript-with-ai) +* [Connections](doc:connections) diff --git a/docs/Settings/user-management/index.md b/docs/Settings/user-management/index.md index 65533227c..7bba982a7 100644 --- a/docs/Settings/user-management/index.md +++ b/docs/Settings/user-management/index.md @@ -19,20 +19,39 @@ next: slug: user-roles title: User Roles --- -In Budibase, users are shared across your whole Budibase installation. Users can sign into any app that they have access to. To give users access to specific apps, check the [User Roles](doc:user-roles) page. +Use user management to control who can sign in, what roles they have, and whether they need a password reset. -> 📘 Adding new users -> -> Invite users from the workspace **Invite user** flow. Read more in [Adding Users](doc:adding-users). +Users are shared across the whole Budibase installation. -## Resetting passwords +## Invite users -If you need to reset a users' password, you need to click the ellipsis (...) next to their email, and `Force password reset` button on the users` detail page. You get displayed a new password for the user with which they can only log in once. Once logged in they will be prompted to change their password before continuing on. +Invite users from the workspace invite flow. -## Configure user roles +Use the `Adding Users` guide when you need the full invite process. -Users can have roles for both the Budibase installation and workspaces, read more about that in [User Roles](doc:user-roles). +## Reset passwords -## Deleting a user +If a user needs a password reset: -In the ellipsis menu next to the user's email address, you can find a Delete user option. Click the `delete user` button and confirm in the dialogue. Keep in mind deleting users _cannot_ be undone. +1. Open the user list. +2. Open the user menu next to the email address. +3. Select `Force password reset`. + +Budibase generates a temporary password and prompts the user to change it after sign-in. + +## Roles + +Users can have both installation-level and workspace-level roles. + +Use `User Roles` to configure access to specific apps and workspaces. + +## Delete users + +Delete users from the user menu when they no longer need access. + +Treat deletion as permanent. If you need the user again later, invite them again instead. + +## Related guides + +* [Adding Users](doc:adding-users) +* [User Roles](doc:user-roles) From 0751fecec481b79c972d20aa134c61a6421af031 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 12:07:52 +0100 Subject: [PATCH 05/32] fifth batched update --- docs/Apps/pickers/filter-by-relationships.md | 4 +- .../automation-actions/send-email.md | 191 +++------ .../automation-actions/slack-notification.md | 162 ++----- docs/Data/_order.yaml | 1 + docs/Data/data-sources/index.md | 97 +---- docs/Data/data-sources/postgresql.md | 396 +----------------- docs/Data/datasources-copy.md | 95 +---- docs/Data/sql-datasource.md | 2 + docs/Data/sql-workflow.md | 78 ++++ docs/References/command-interface.md | 4 +- 10 files changed, 216 insertions(+), 814 deletions(-) create mode 100644 docs/Data/sql-workflow.md diff --git a/docs/Apps/pickers/filter-by-relationships.md b/docs/Apps/pickers/filter-by-relationships.md index 1b54d7ce4..a7034fb3d 100644 --- a/docs/Apps/pickers/filter-by-relationships.md +++ b/docs/Apps/pickers/filter-by-relationships.md @@ -126,7 +126,7 @@ For this tutorial we will use PostgreSQL, and assume there are three tables with For a given owner, we want to display a list of appointments based on the chosen pet. -Follow this [guide](https://docs.budibase.com/docs/postgresql-1) to see how to connect to your Postgres database, fetch the tables and define the relationships. +Follow [Working with SQL datasources](doc:sql-workflow) to connect to your Postgres database, fetch tables, and define relationships. ![](https://files.readme.io/d4ca78e-Screenshot_2022-08-17_at_14.24.20.png) @@ -167,4 +167,4 @@ The date can be prettified as follows: `{{ date Appointments Cards block.Appoint #### Result -![](https://files.readme.io/ba7a4e8-filter_with_rel.gif) \ No newline at end of file +![](https://files.readme.io/ba7a4e8-filter_with_rel.gif) diff --git a/docs/Automation/automation-actions/send-email.md b/docs/Automation/automation-actions/send-email.md index 23e94ea7f..223f1bf0c 100644 --- a/docs/Automation/automation-actions/send-email.md +++ b/docs/Automation/automation-actions/send-email.md @@ -10,179 +10,82 @@ metadata: next: description: '' --- -Before you can use the Send Email action step, please make sure you have configured [Email](doc:email). +Use the Send Email action after you configure SMTP in Budibase. -Please configure SMTP to use the Send Email action! - Please configure SMTP to use the Send Email action! - +## Before you start -## Settings +Make sure email is configured in `Settings > Email`. -All of these settings support [Bindings](doc:data-in-automations). For email address settings, you can provide multiple addresses by separating them with a comma, e.g. `anna@company.com,bill@company.com`. +## Send Email settings - - - - +All fields support bindings. - - - +| Setting | Purpose | +| :--- | :--- | +| Send To / From | Email addresses used by the message. | +| CC / BCC | Optional copy recipients. | +| Email subject | The subject line. | +| HTML Contents | The email body. | - - - +You can supply multiple addresses by separating them with commas. - - +## Use bindings - - +Use bindings to personalize the message with values from the trigger row or earlier steps. - - +Example: - - +```handlebars +Subject: New request from {{ trigger.row.Name }} - - +Hello {{ trigger.row.Name }}, - - - - - - -
- Setting - - Description -
- Send To / From - - The to / from email addresses -
- CC / BCC - - The carbon copy email addresses -
- Email subject - - The subject line -
- HTML Contents - - The body of the email, which support HTML tags.\ - This will also be the `{{ contents }}` binding in the [custom automation email template](https://docs.budibase.com/docs/email#templates). -
- -### Add calendar invite - -Optionally you can attach a calendar invite to an email. Check the `Add calendar invite` box to see the additional invite settings: - -Sending a calendar invite - Sending a calendar invite - - -In this screenshot above, a start and end time for the meeting was manually selected, however you can also use Binding values, by clicking the lightning bolt icon. - -Both the *Location* and *URL* properties are optional, as your meeting may be in person, or online. +Your request has been received. +``` -The email will then be received with an **ics** invite file attached: +## Calendar invites - +Optionally add a calendar invite to the email. -
+Use this when the message should include meeting details or another scheduled event. -### Adding Attachments +## Attachments -When adding attachments to the Send Email step, you will need to provide 2 parameters - the URL and the filename. These values can come from bindings, or plain text, or a mixture of the two. +To add attachments, provide: - +* A file URL +* A filename -These files will be attached to the email sent. Images attached this way may be displayed with the message body, or simply denoted in the list of attachments, depending on the recipient's mail client. +If you need multiple attachments, return an array of objects with `url` and `filename`. -Alternatively, you can switch the "Use bindings" toggle to open the bindings draw. You should return an array of objects that match this pattern: `{url: string, filename: string}`. This is useful if you have an unspecified or undetermined number of attachments that you wish to attach. +Example: -```javascript JavaScript +```javascript return $("trigger.row.photos").map(photo => { - return {url: photo.url, filename: photo.name} + return { url: photo.url, filename: photo.name } }) ``` -*** - -## Tutorial: Emailing new inventory details to a user - -This tutorial will use the *Inventory* table from the [Sample data](https://docs.budibase.com/docs/data-sources#sample-data). When a user assigns an inventory item, they will be sent an email with a summary of the item. - -### Step 1 - Automation - -In the **Data** section, add a new *User* column to the *Inventory* table called 'AssignedTo' and click `Save`. - - - -Next navigate to the **Automation** section. Click `Add automation`, enter the *Name* 'Confirmation email' and select [On demand](doc:app-action) as the trigger. - -Use the `Add field` button to add the following fields: - - - -Click the `+` button to add the **Send Email (SMTP)** action step. - - - -Set *Send To* as `{{ trigger.fields.email_address }}`, and provide a *Send From* address and *Email Subject*. - -For the *HTML Contents* specify the email body text: - -```html HTML Contents -Hi {{ trigger.fields.first_name }}, -

-The following item has been assigned to you: -
- - - - - - - - - - -
Item NameNotesStatusPrice
{{ trigger.fields.item_name }}{{ trigger.fields.notes }}{{ trigger.fields.status }}{{ trigger.fields.price }}
-``` - - - -
- -### Step 2 - Design - -In the **Design** section. Add a [Table](doc:table) for the *Inventory* table, with a [filter](https://docs.budibase.com/docs/data-provider#filtering): 'AssignedTo' *Is empty* - - - -Add a [Button](doc:button-button-group#adding-buttons-to-table-rows) to the table component. - -Use the setting cog to configure the buttons settings. Here you will be able to change its name and add *on click* actions. Add a [Trigger automation](https://docs.budibase.com/docs/application-actions#trigger-automations) action, selecting the automation you created in the previous step. - -Set the *email\_address* and *first\_name* to the mapping bindings of the [Current user](https://docs.budibase.com/docs/users-table#current-user-bindings). - -Fill out the remaining field inputs with the table row bindings, like so: +## Example workflow - +A common pattern is: -Add a [Save Row](https://docs.budibase.com/docs/data-actions#save-row) action, select the table component as the *Datasource*, and *Inventory* as the target data table. +1. Trigger an automation from a row or app action. +2. Prepare the email body with bindings. +3. Send the email to the user or team that needs it. +4. Add attachments or a calendar invite if needed. -Click `Add Column`, and set *AssignedTo* as `{{ Current User._id }}`. +## Good practice - +Keep the message: -#### Example of received email +* Short +* Clear +* Bound to real data +* Styled consistently with your branding - +## Related guides -Ideally you want to specify styling in the [custom automation email template](https://docs.budibase.com/docs/email#templates). +* [Email](doc:email) +* [Action steps](doc:automation-actions) +* [Bindings in automations](doc:data-in-automations) diff --git a/docs/Automation/automation-actions/slack-notification.md b/docs/Automation/automation-actions/slack-notification.md index 94a055754..414321105 100644 --- a/docs/Automation/automation-actions/slack-notification.md +++ b/docs/Automation/automation-actions/slack-notification.md @@ -10,118 +10,50 @@ metadata: next: description: '' --- -The Slack notification is a webhook that allows you to send notifications from your Budibase app to a Slack channel. +Use the Slack action to send automation messages to a Slack channel. -## Settings +## Before you start -The Slack [Action](doc:automation-actions) has two settings: +Make sure you have: - - - - +* A Slack workspace +* A Slack app with incoming webhooks enabled +* The webhook URL for the channel you want to post to - - - +## Slack action settings - - - +The Slack action uses two fields: - - +## Configure the Slack app - - +1. Create a Slack app. +2. Enable incoming webhooks. +3. Add a webhook to the workspace. +4. Copy the generated webhook URL. +5. Paste it into the Budibase Slack action. - - - -
- Setting - - Description -
- Incoming Webhook URL - - Further information and directions on how to find your Slack channel's webhook URL: +| Setting | Purpose | +| :--- | :--- | +| Incoming Webhook URL | The Slack webhook URL for the target channel. | +| Message | The text Budibase posts when the automation runs. | - [https://slack.com/intl/en-gb/help/articles/115005265063-Incoming-webhooks-for-Slack](https://slack.com/intl/en-gb/help/articles/115005265063-Incoming-webhooks-for-Slack) +You can include bindings in the message to insert values from the trigger row or previous steps. - [https://api.slack.com/messaging/webhooks](https://api.slack.com/messaging/webhooks) -
- Message - - The content you would like to send to your Slack channel when your automation is triggered. -
+## Build the automation -## Tutorial +The common pattern is: -The following tutorial will demonstrate how to send a Slack notification when a new record is created. We will assume you have your data setup and design screens created. If you don't, check out the [Quickstart: Budibase DB](doc:build-a-crud-app). +1. Add a trigger, such as `Row Created`. +2. Add the Slack action. +3. Map the values you want to send into the message. +4. Test the automation. +5. Publish it when the message looks correct. -Our Slack notification automation will consist of two automation blocks: +## Use trigger data -1. Trigger - Row created -2. Action - Slack notification +Use trigger bindings to include row values in the Slack message. -Click the add automation button. - -### Add Trigger - Row created - -Name your automation. We will name ours `Slack notification`. Select the `Row Created` trigger. Then click `Save`. - -{1253} - row created trigger - - -Now click the SETUP dropdown on your new automation block, and select your table. - -{597} - trigger setup - - -### Add Action - Slack - -Now click the small plus icon button under the Trigger automation block, select Slack, then click Save. - -![](https://files.readme.io/ebd020f-CleanShot_2022-04-19_at_15.18.55.png "CleanShot 2022-04-19 at 15.18.55.png") - -Now it's time to set up our Slack action. If you don't have a Slack channel, please set one up. To get your Incoming Webhook URL, [create a Slack App](https://api.slack.com/apps?new_app=1). - -When creating a Slack app, choose 'From Scratch'. - -![](https://files.readme.io/6eeea71-CleanShot_2022-04-19_at_15.23.05.png "CleanShot 2022-04-19 at 15.23.05.png") - -Name your Slack app, and choose your Workspace. - -![](https://files.readme.io/733cc0d-CleanShot_2022-04-19_at_15.24.44.png "CleanShot 2022-04-19 at 15.24.44.png") - -Then select Incoming Webhooks. - - - -Activate incoming webhooks by switching on the toggle. - - - -Select the Add New Webhook to Workspace button. - - - -Now select the channel you would like to post to. - - - -Slack will generate you a webhook. Click the Copy button to copy your webhook. - - - -Paste your Slack Webhook URL into the Incoming Webhook Url input within your [Action](doc:automation-actions) automation block. - - - -In the Message input, add the message you would like Budibase to post to your Slack channel when a new row is created. You can bind values from the newly created record to your message. For our use case, I want to send the following notification to our channel: +Example: ```handlebars Woohoo, we just made a new sale in {{ trigger.row.Country }} @@ -130,34 +62,20 @@ Check out the sale using the link below: https://joe.budibase.app/app/tutorials#/sales/{{ trigger.id }} ``` -From the above, you can see I have used automation [Bindings](doc:bindings) to pull data into our message. - - - -#### Trigger output bindings - Trigger.Row - -To pull data from your Trigger record, you can use Trigger Output helpers (see Gif above). Using the helper `trigger.row` I now have access to that data from our newly created record. I add the field/column title to the binding to pull a specific field back: `trigger.row.Country`. - -To allow users to access the specific record page, we must add a link to our message. - -**To create a link, we must first Publish our application.** Save the automation, click the Publish app button. Now, go back to the app portal page (Click the Budibase icon). Locate your app, click the more icon, and click View published app. Copy your base URL - We will improve this experience soon. - -#### Trigger output bindings - Trigger.ID - -Now, click into your app and go back to the automation we were just creating and into the message section (where we were above). Paste your URL, and append it with the Trigger ID output. Click Save. - -### Test automation +## Test and publish -Click `Finish and test automation`. Then select your table from the dropdown. +Test the automation with a sample row first. - +Then confirm: -In the Column/Field you referenced in your trigger.row binding, add a value - we'll add `Budiland` to the Country field. Click test. You should now see a message in your Slack channel. +* The webhook posts to the correct channel +* The message includes the expected bindings +* The automation runs when the trigger fires - +Once the test passes, publish the app. -If you are happy, click Publish app. Add a new record within your app, and like magic, watch as a new Slack notification appears within your channel. +## Related guides -{` -

-`} +* [Action steps](doc:automation-actions) +* [Triggers](doc:trigger) +* [Automation testing](doc:activating-and-testing) diff --git a/docs/Data/_order.yaml b/docs/Data/_order.yaml index 7b38e2456..09cc5ae86 100644 --- a/docs/Data/_order.yaml +++ b/docs/Data/_order.yaml @@ -4,6 +4,7 @@ - datasources-copy - rest - sql-datasource +- sql-workflow - transformers - environment-variables - pdf-exporting diff --git a/docs/Data/data-sources/index.md b/docs/Data/data-sources/index.md index 72b3eb2e9..9155f0522 100644 --- a/docs/Data/data-sources/index.md +++ b/docs/Data/data-sources/index.md @@ -12,115 +12,44 @@ next: --- Budibase can store your data inside the [native internal database](doc:budibasedb) (CouchDB). This is the default datasource unless you opt to connect another datasource to Budibase. -List of app datasources - List of app datasources - - Budibase supports connection to a range of remote datasources. More information about connecting Budibase to each of these datasources is nested in this section of the documentation. Furthermore, if a datasource you want to use is missing, it is possible to build a [custom datasource](https://docs.budibase.com/docs/custom-datasource). ## Schema -When [Fetching tables](https://docs.budibase.com/docs/sql-datasource#fetching-tables) from external SQL databases, Budibase will attempt to match the external data types to the internal [Budibase DB](https://docs.budibase.com/docs/budibasedb) types. These default types can be changed by clicking the three dots icon beside the table column, and selecting `Edit column`: - -Editing a column type, demonstrated on an MS SQL database - Editing a column type, demonstrated on an MS SQL database - - -Column types displayed in a dropdown when creating a new column for the internal Budibase DB - Column types displayed in a dropdown when creating a new column for the internal Budibase DB - - -For other basic datasources and [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries), the schema will be determined by selecting types in the query output. +When [Fetching tables](https://docs.budibase.com/docs/sql-datasource#fetching-tables) from external SQL databases, Budibase matches the external data types to the internal [Budibase DB](https://docs.budibase.com/docs/budibasedb) types. - +For other basic datasources and [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries), the schema is determined by the types in the query output. The schema is important, as it will affect how [sorting and filtering](https://docs.budibase.com/docs/data-provider#pagination-and-sorting) is applied in the design section. ## Sample data -Budibase provides the option of adding some sample data to allow new users to explore the various [Data types](https://docs.budibase.com/docs/budibasedb#data-types) available, and quickly build an app for learning purposes. While it is an internal Budibase DB source, it will be kept separate to the other internal DB tables that you create. - -Use sample data - Use sample data - +Budibase includes sample data so new users can explore the available [data types](https://docs.budibase.com/docs/budibasedb#data-types) and build an app quickly. It stays separate from the internal DB tables you create. If you do not need this data, it can easily be removed in the same way as other additional datasources. Simply click on the ellipsis to the right of the sample data source and click *Delete*. -Sample data - Deleting sample data - - ## Security -When connecting to an external datasource you must allow Budibase access. Normally datasources will be protected by a firewall and you will need to open firewall access to your datasource from the Budibase cloud or from your self-hosted Budibase. Port numbers and user management differ across each type of datasource so if you have difficulty connecting you should speak to the Database Administrator for your organisation. - -
- -*** +When connecting to an external datasource you must allow Budibase access. Datasources are usually protected by a firewall, so you may need to whitelist the Budibase cloud or your self-hosted Budibase server. -
+## Custom queries -# Custom queries +Budibase supports custom queries for advanced joins and server-side filtering. -Budibase supports the ability to write custom queries. These queries can be really useful if you want to perform advanced joins or server-side filtering. - -To write custom queries, head over to your Datasource, and scroll down until you find the queries section. Click the `Add Query` button, which will guide you to a form to configure your query. +To write one, open a datasource and go to the **Queries** section. > 📘 Budibase DB > -> The internal Budibase DB is a unique datasource that does not support custom queries.\ -> It does however support [Views](https://docs.budibase.com/docs/views) - -An example would be to query all pet names from a specific owner. For this demonstration we've used a custom binding to insert the `ownerID` into the query. - -![](https://files.readme.io/3ffa1e1-4a73ef1-query-owners-pets.png "4a73ef1-query-owners-pets.png") - -> 📘 Read or Write -> -> If you want to use a custom query with a [Data provider](doc:data-provider), you must select **Read** as the function of your query. -> -> Other query types, such as Create, can be used by the [Execute Query action](https://docs.budibase.com/docs/data-sources#tutorial-posting-form-data-to-a-custom-query). - -## Using query bindings - -You can also override the default binding values. - -When you use the query as a data source for your provider, you can click on the cog icon. - - - -This will show a query bindings drawer where you can add a dynamic value to override the default. - -![](https://files.readme.io/42caffe-Screenshot_2022-04-04_at_14.59.01.png "Screenshot 2022-04-04 at 14.59.01.png") - -## Editing custom queries - -A list of your custom queries can be found underneath the associated data sources. Click on the query to be able to edit the config. - -It is also possible to **delete** queries that are no longer needed, or **duplicate** queries, which can useful in cases where an additional query only requires minor changes. - -To access these options, hover over the query and click the **…** - - - -## Tutorial: Posting form data to a custom query - -1. Add your query to a datasource, in this example we'll use [PostgreSQL](https://docs.budibase.com/docs/postgresql-1). Add your bindings with some optional defaults, and then reference them within your query. - -![](https://files.readme.io/c3c5a07-Screenshot_2022-11-15_at_11.15.59.png) - -2. Add a [Form](doc:forms) with fields for each of the bindings, except for the *id* which will come from the [URL ID](https://docs.budibase.com/docs/url-parameters) binding. - -![](https://files.readme.io/7ebc1ef-Screenshot_2022-11-15_at_12.47.12.png) +> The internal Budibase DB does not support custom queries. It does support [views](https://docs.budibase.com/docs/views). -3. **Define actions** for the 'Submit' button. Choose the **Execute Query** action and pick *PostgreSQL* as the datasource. You should now be able to see and select your custom query. +Use `Read` queries with a [Data provider](doc:data-provider). -![](https://files.readme.io/b2e874e-Screenshot_2022-11-15_at_12.49.34.png) +Use `Execute Query` for create, update, or delete actions. -4. Finally map your form field bindings to your custom query bindings like so: +Add bindings when the query needs dynamic values, and use the query settings to override defaults at runtime. -![](https://files.readme.io/382af3b-Screenshot_2022-11-15_at_12.51.51.png) +You can edit, duplicate, or delete queries from the datasource list. -Click **Save** to finish. +For the standard SQL workflow, see [Working with SQL datasources](doc:sql-workflow). diff --git a/docs/Data/data-sources/postgresql.md b/docs/Data/data-sources/postgresql.md index 9e6b72fa7..051f48fa6 100644 --- a/docs/Data/data-sources/postgresql.md +++ b/docs/Data/data-sources/postgresql.md @@ -10,389 +10,29 @@ metadata: next: description: '' --- -> 👍 SQL Databases -> -> Budibase is designed to integrate with any core SQL database. -> -> Read more about [SQL Datasources](doc:sql-datasource). +Budibase can connect to PostgreSQL and use it as a datasource for apps and automations. -# Video tutorial +## Before you start - +Make sure you have: -
+* A running PostgreSQL instance +* Credentials for that database +* Permission to create and edit a datasource in Budibase -*** +## Connect PostgreSQL -# Tutorial: Inventory management +1. Open the Data section. +2. Add a new source. +3. Choose `PostgreSQL`. +4. Enter the connection details. +5. Fetch the tables you want Budibase to use. -In this tutorial we will look at using the [DVD Sample Database](https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/) within Budibase. A link to **pgadmin** import instructions are included in that article, but it is worth noting that if you are not on Windows, you will want to extract the zip folder, and restore from *Directory* instead. +If you are connecting to a local database, use the host value required by your environment instead of `localhost` when Budibase is running in Docker. -![](https://files.readme.io/0c9bb3a-Screenshot_2023-02-07_at_15.39.23.png) +## Related guides -This sample database includes a complete system of film details through to payments and customer details. To keep the tutorial to a modest size, we shall focus on the film details and inventory management. - -
- -## Datasource setup - -Assuming you have setup the example database on a running Postgres instance, we can start pulling data into Budibase. - -First create an app - no sample data needed. - -![](https://files.readme.io/c3e370a9ff9ed2ed9b14a69ada35d3b87f52a0a95fec342013d2491bddff74fb-image.png) - -Click `Add source`, select `PostgreSQL` and press `Continue`. - -![](https://files.readme.io/f70dc3d-1_postgres.png) - -You will then be presented with a connection configuration modal. Fill in the correct connection details but press **Skip table fetch**. We want to manually fetch tables later so we can choose the tables we want to use in our Budibase app. - -> 📘 -> -> Note that if you are connecting to a database on `localhost`, your host should be set to `host.docker.internal`, or `172.17.0.1` if running on Linux. - -![](https://files.readme.io/393148de5b4106e9443e3eacc9347c29e09d4f29d74e113e488fab6eb8213fc2-image.png) - -Now we have the Postgres Datasource added, and the configuration page should be displayed. - -Under the **Tables** section press `Fetch tables`. Tick `Fetch listed tables only` and provide the following table names: - -``` -category -film_category -film -language -film_actor -inventory -actor -store -address -city -country -``` - -Fetch the checked tables from the list - Fetch the checked tables from the list - - -
- -## Defining relationships - -With our tables fetched, we can now define relationships within Budibase. - -We will need to setup the relationships as presented in the [DVD Rental ER Model](https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/), excluding the tables we did not fetch. - -Click the `Define relationship` button below the **Table** section. - -![](https://files.readme.io/7d886616c1af2ba870e20c21f7ff2e9f6d30755221ca79679505fd209f26fea5-image.png) - -
- -Setup a *Many->Many* relationship between the **category** and **film** tables. Notice the error received below: - -film_category is not a valid Budibase join table - film\_category is not a valid Budibase join table - - -This error is caused by the *Not NULL* constraint on the **last\_update** column. This is easily resolved by setting this column to *nullable* in **pgadmin**. - -Setting last_update to nullable - Setting last\_update to nullable - - -**Do the same for the*last\_update* column in the *film\_actor* table.** - -In addition, the **inventory** table is a through table that will need adjusted like so: - -![](https://files.readme.io/9d0ebd6-Screenshot_2023-02-08_at_10.25.43.png) - -> 📘 -> -> Make sure to re-fetch the tables to pull down the new schema information! - -You should now be able to create this *Many->Many* relationship. - -Many to Many relationship between category and film - Many to Many relationship between category and film - - -When all relationships have been defined, you should see something like so: - -![](https://files.readme.io/cd9e620-Screenshot_2023-02-08_at_10.26.55.png) - -
- -## Stores screen - -Add an [autogenerated screen](https://docs.budibase.com/docs/screens#autogenerated-screen) for the **store** table. Change the *Title* to 'Stores'. - -Next `Configure columns`, click `Add all columns`, and then remove columns with the `x` so that only the address is displayed. - -### Adding a flag icon - -We will also add a flag image within the table to indicate the country of the store. It would be possible to write insert statements to add image URLs for the two stores, but for the sake of demonstration we will use the country name from the **store address** relationship. - -[Eject](https://docs.budibase.com/docs/blocks#ejecting-blocks) the table block. As there are only two stores, uncheck the pagination of the Data provider. - -#### Naive approach: using multiple repeaters - -Select the [Table](doc:table) and click `Add component` to nest a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block). Select the address relationship as the datasource. - -Using the address relationship as a datasource - Using the address relationship as a datasource - - -We then have to nest another repeater block under the first one to hop from the **city** table to the **country** table! - -Select the city relationship as the datasource. - -City relationship of the address table - City relationship of the address table - - -Finally we can nest an [Image](doc:image) component within the City repeater block. Provide the following [JavaScript](doc:javascript) binding: - -```javascript -const countryName = $("City Repeater block.city.country")[0].primaryDisplay.toLowerCase(); - -return `https://images.mapsofworld.com/${countryName}/${countryName}-flag.gif`; -``` - -The *primaryDisplay* property works here because the country name is the [table display column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column). - -![](https://files.readme.io/23377d6-Screenshot_2023-02-08_at_11.36.21.png) - -#### Better approach: using a custom query - -Adding two nested repeater blocks is not ideal for performance, and is also not very maintainable. Considering that we are looking to get specific data from the relationships, using [custom SQL queries](https://docs.budibase.com/docs/sql-datasource#add-query) is better for this scenario. - -In the **Data** section add a query to your PostgreSQL datasource. Give it the name 'Get Country Names', give it a Binding or the **address\_id** with the query: - -```sql -SELECT LOWER(country) as country_name FROM address a -JOIN city on a.city_id = city.city_id -JOIN country c ON c.country_id = city.country_id -WHERE a.address_id = {{ address_id }} -``` - -![](https://files.readme.io/941232a-Screenshot_2023-02-08_at_12.23.28.png) - -Make sure to click `Run Query` followed by `Save Query`! - -Now back to the **Design** section, the two existing repeater blocks can be replaced with a single new repeater block, using our new query as the datasource. Click the cog icon to open the binding drawer. Assign the **address\_id**. - -Image repeater block - Image repeater block - - -![](https://files.readme.io/04bb90e-Screenshot_2023-02-08_at_12.24.13.png) - -Finally the image URL can be set to the following Handlebars expression: - -``` -https://images.mapsofworld.com/{{ Image Repeater block.Get Country Names.country_name }}/{{ Image Repeater block.Get Country Names.country_name }}-flag.gif -``` - -Custom query reduces the number of repeater blocks needed - Custom query reduces the number of repeater blocks needed - - -### Adding a store map location - -First we need to make a [REST API](doc:rest) call to get the longitude/latitude from our address. Go to the **Data** section, and add a REST datasource. - -I used the [OpenCage API](https://opencagedata.com/api), which you can sign up to and receive an API key to use. - -Select the `GET` method and paste in the URL: - -``` -https://api.opencagedata.com/geocode/v1/json -``` - -Add a binding called 'location' and give it a default value. Next add two params. One for your API **key**, and another for the **q** (query string). Click the lightning bolt icon to select the *location* binding. - -![](https://files.readme.io/5eb3911-Screenshot_2023-02-08_at_12.51.51.png) - -![](https://files.readme.io/4acac32-Screenshot_2023-02-08_at_12.53.23.png) - - - - - - - - - - - -
- - - -
- -To make sure we're pulling the co-ordinates of the first result, add the following to your [Transformer](doc:transformers): - -```javascript Transformer -return data.results[0]?.geometry -``` - -After clicking the `Send` button, your Schema should include the latitude and longitude. Make sure to also click the `Save` button! - -![](https://files.readme.io/f049f53-Screenshot_2023-02-08_at_13.24.05.png) - -We will need to pull the **city** name and **country** name for a given **address\_id** in order to make use of this API. As before, a custom SQL query is the most efficient way to do this. In fact we can update our existing *Get Country Name* query without breaking the current usage for the flag image. - -Click on the *Get Country Names* query under the PostgreSQL datasource. Update the query to pull back the city name as follows: - -```sql -SELECT LOWER(country) as country_name, city FROM address a -JOIN city on a.city_id = city.city_id -JOIN country c ON c.country_id = city.country_id -WHERE a.address_id = {{ address_id }} -``` - -The schema should now have two fields: one for the country, and one for the city. Make sure to run and save the query. - -![](https://files.readme.io/7194b73-Screenshot_2023-02-08_at_13.36.17.png) - -With the REST query set up, go back to the **Design** section. Within the *Details side panel*, eject the *Details form block*. This will give us access to the **store** entry data. Click on the Repeater and add a repeater block with the name 'Location Repeater Block', which will be nested below. Set the *Get Country Names* as the datasource, and click the cog icon to pass in the binding `{{ Repeater.store.address_id }}`. Drag the Form into the new *Location Repeater Block*. - -Currently the heading is displaying the ID value of the store. This isn't very nice, so let's replace it with the store location. Replace the [Heading](https://docs.budibase.com/docs/displaying-text#headline) *Text* handlebars with the following: - -``` -{{ Location Repeater block.Get Country Names.city }} -``` - -You can use the bindings helper on the left hand panel to insert this value. It is also unlikely that you would want *\_id* fields in the form, so go ahead and delete those. - -Next nest a [Data provider](doc:data-provider) under the Location repeater block, below the form. Set the datasource to REST query we added earlier, and click the cog icon to pass in the following binding for the query string param: - -``` -{{ Location Repeater block.Get Country Names.city }}, {{ Location Repeater block.Get Country Names.country_name }} -``` - -Finally nest an [Embedded Map](doc:map) underneath the REST query data provider. Choose it as the *Provider* and select the *lat* and *lng* keys. - -![](https://files.readme.io/920e662-Screenshot_2023-02-08_at_14.12.18.png) - -
- -## Viewing available films in store - -Create a new screen with the route: `/film/:storeid`. - -Add a [Row Explorer block](https://docs.budibase.com/docs/blocks#row-explorer-block) for the **film** table. Set the *Height* to `800px` and set the *Search Field* to `title`. Assign the *Title*, *Subtitle*, and *Description* to some appropriate bindings, e.g. - -* `{{ Film Explorer Block.film.title }}` -* `{{ Film Explorer Block.film.release_year }}` -* `{{ Film Explorer Block.film.description }}` - -Selecting the film description from the binding dropdown - Selecting the film description from the binding dropdown - - -As we want to filter the list of films by the *store\_id* that we [pass via the URL](doc:url-parameters) go ahead and eject the Row Explorer block, and `Define filters` for the now exposed Data provider. - -Click `Add filter` to add an additional filter for the *store\_id* column. - -![](https://files.readme.io/5c86a2d-Screenshot_2023-02-09_at_13.48.13.png) - -Back to the `/store` screen, click on the table and add a new [Link](doc:link) component. Give it the name 'View films' and the URL binding: `/film/{{ Table.store.store_id }}`. - -![](https://files.readme.io/f64dd4f-Screenshot_2023-02-09_at_14.09.00.png) - -### Adding the film rating image - -At the moment the row explorer presents the film information in a basic form. This is fine, but let's make it look a little nicer. - -First remove the **rating** field, and any of the fields that you do not wish to be displayed or edited from the [Form block](doc:form-block). Next eject the form block so that the data provider can be used. - -Selecting the form block fields - Selecting the form block fields - - -Above the recently exposed form, add an image component. Give it the following JavaScript *URL* binding: - -```javascript JavaScript -let baseUrl = "https://www.motionpictures.org/wp-content/uploads/2018/03"; -const rating = $("Repeater.film.rating"); - -if (rating === 'G') { - return `${baseUrl}/general_audiences_badge.svg`; -} -else if (rating === 'PG') { - return `${baseUrl}/parental_guidance_badge.svg` -} -else if (rating === 'PG-13') { - return `${baseUrl}/parens_strongly_cautioned_badge.svg` - -} -else if (rating === 'R') { - return `${baseUrl}/restricted_badge.svg` -} - -return `${baseUrl}/no_17_and_under_badge.svg` -``` - -As these images are white, you'll also want to edit the [Custom CSS](doc:custom-css) and give it a black background: `background-color: black;`. Also set a *width* and *height*, e.g. 256px \* 96px. - -![](https://files.readme.io/6757f5a-Screenshot_2023-02-09_at_14.39.34.png) - -![](https://files.readme.io/4773739-Screenshot_2023-02-09_at_14.41.01.png) - -### Displaying inventory count - -Within the film view, it would also be useful to show the user what the current stock is for the selected film. - -In the **Data** section add another custom SQL query. - -```sql -select COUNT(*) from inventory -WHERE film_id = {{ film_id }} and store_id = {{ store_id }} -GROUP BY film_id -``` - -![](https://files.readme.io/dfabd7a-Screenshot_2023-02-09_at_14.50.30.png) - -As always, be sure to `Run Query` and `Save Query`. - -Back in the **Design** section, add a new Repeater block above the row explorer detail heading. Select the inventory count query as the datasource. Click the cog icon to pass in the binding values: - -![](https://files.readme.io/d0185d5-Screenshot_2023-02-09_at_15.02.53.png) - -Nest the Heading component under the Stock Repeater block and give it the binding *Text* value: `Stock: {{ Stock Repeater block.Get Inventory Count.count }}`. - -![](https://files.readme.io/5aa907d-Screenshot_2023-02-09_at_15.56.40.png) - -*** - -# Using query bindings in more complex queries - -For the most part Bindings in PostgreSQL queries will behave much in the same way as other [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries) and as shown in the tutorial above. - -It is worth understanding however, that SQL queries will be [parameterized](https://www.postgresql.org/docs/current/sql-prepare.html) under the hood. This is mainly done to improve security and performance. - -This enhanced security does have a small drawback in reducing the flexibility of your queries. For example, bindings cannot be used as a direct inline replacement of text in your queries, and therefore cannot be used to dynamically set table or column names, dynamically set operators, or inject SQL snippets. Ideally your Budibase bindings should be used in the same way that you might use **$** parameters in your Postgres queries. - -##  Example: Using a binding with INTERVAL - -Let's say you have the following query: - -```sql -select * from public."ServiceLog" where "ServiceDate" > NOW() - INTERVAL '2 years' -``` - -And you want to add bindings to make the `INTERVAL` adjustable. This can be done like so: - -Query an interval of 'n' years - Query an interval of 'n' years - - -Alternatively, if we wanted to provide an INTERVAL string, then we need to use Postgres typecasting in our query like so: - -Text binding input must be cast to Postgres interval - Text binding input must be cast to Postgres interval - +* [Working with SQL datasources](doc:sql-workflow) +* [SQL datasource](doc:sql-datasource) +* [Data providers](doc:data-provider) +* [Bindings](doc:bindings) diff --git a/docs/Data/datasources-copy.md b/docs/Data/datasources-copy.md index addd35fe7..c70d22318 100644 --- a/docs/Data/datasources-copy.md +++ b/docs/Data/datasources-copy.md @@ -12,113 +12,44 @@ next: --- Budibase can store your data inside the [native internal database](doc:budibasedb) (CouchDB). This is the default datasource unless you opt to connect another datasource to Budibase. -List of app datasources - List of app datasources - - Budibase supports connection to a range of remote datasources. More information about connecting Budibase to each of these datasources is nested in this section of the documentation. Furthermore, if a datasource you want to use is missing, it is possible to build a [custom datasource](https://docs.budibase.com/docs/custom-datasource). ## Schema -When [Fetching tables](https://docs.budibase.com/docs/sql-datasource#fetching-tables) from external SQL databases, Budibase will attempt to match the external data types to the internal [Budibase DB](https://docs.budibase.com/docs/budibasedb) types. These default types can be changed by clicking the three dots icon beside the table column, and selecting `Edit column`: - -Edit column - Edit column - - - - -For other basic datasources and [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries), the schema will be determined by selecting types in the query output. +When [Fetching tables](https://docs.budibase.com/docs/sql-datasource#fetching-tables) from external SQL databases, Budibase matches the external data types to the internal [Budibase DB](https://docs.budibase.com/docs/budibasedb) types. -![](https://files.readme.io/95963a3-Screenshot_2022-11-25_at_11.40.20.png) +For other basic datasources and [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries), the schema is determined by the types in the query output. The schema is important, as it will affect how [sorting and filtering](https://docs.budibase.com/docs/data-provider#pagination-and-sorting) is applied in the design section. ## Sample data -Budibase provides the option of adding some sample data to allow new users to explore the various [Data types](https://docs.budibase.com/docs/budibasedb#data-types) available, and quickly build an app for learning purposes. While it is an internal Budibase DB source, it will be kept separate to the other internal DB tables that you create. - -Use sample data - Use sample data - +Budibase includes sample data so new users can explore the available [data types](https://docs.budibase.com/docs/budibasedb#data-types) and build an app quickly. It stays separate from the internal DB tables you create. If you do not need this data, it can easily be removed in the same way as other additional datasources. Simply click on the ellipsis to the right of the sample data source and click *Delete*. -Sample data - Deleting sample data - - ## Security -When connecting to an external datasource you must allow Budibase access. Normally datasources will be protected by a firewall and you will need to open firewall access to your datasource from the Budibase cloud or from your self-hosted Budibase. Port numbers and user management differ across each type of datasource so if you have difficulty connecting you should speak to the Database Administrator for your organisation. - -
- -*** +When connecting to an external datasource you must allow Budibase access. Datasources are usually protected by a firewall, so you may need to whitelist the Budibase cloud or your self-hosted Budibase server. -
+## Custom queries -# Custom queries +Budibase supports custom queries for advanced joins and server-side filtering. -Budibase supports the ability to write custom queries. These queries can be really useful if you want to perform advanced joins or server-side filtering. - -To write custom queries, head over to your Datasource, and scroll down until you find the queries section. Click the `Add Query` button, which will guide you to a form to configure your query. +To write one, open a datasource and go to the **Queries** section. > 📘 Budibase DB > -> The internal Budibase DB is a unique datasource that does not support custom queries.\ -> It does however support [Views](https://docs.budibase.com/docs/views) - -An example would be to query all pet names from a specific owner. For this demonstration we've used a custom binding to insert the `ownerID` into the query. - -![](https://files.readme.io/3ffa1e1-4a73ef1-query-owners-pets.png "4a73ef1-query-owners-pets.png") - -> 📘 Read or Write -> -> If you want to use a custom query with a [Data provider](doc:data-provider), you must select **Read** as the function of your query. -> -> Other query types, such as Create, can be used by the [Execute Query action](https://docs.budibase.com/docs/data-sources#tutorial-posting-form-data-to-a-custom-query). - -## Using query bindings - -You can also override the default binding values. - -When you use the query as a data source for your provider, you can click on the cog icon. - -![](https://files.readme.io/f4c82ad-Screenshot_2022-04-04_at_14.52.37.png "Screenshot 2022-04-04 at 14.52.37.png") - -This will show a query bindings drawer where you can add a dynamic value to override the default. - -![](https://files.readme.io/42caffe-Screenshot_2022-04-04_at_14.59.01.png "Screenshot 2022-04-04 at 14.59.01.png") - -## Editing custom queries - -A list of your custom queries can be found underneath the associated data sources. Click on the query to be able to edit the config. - -It is also possible to **delete** queries that are no longer needed, or **duplicate** queries, which can useful in cases where an additional query only requires minor changes. - -To access these options, hover over the query and click the **…** - -![](https://files.readme.io/4f2e995-Screenshot_2022-05-09_at_08.59.35.png "Screenshot 2022-05-09 at 08.59.35.png") - -## Tutorial: Posting form data to a custom query - -1. Add your query to a datasource, in this example we'll use [PostgreSQL](https://docs.budibase.com/docs/postgresql-1). Add your bindings with some optional defaults, and then reference them within your query. - -![](https://files.readme.io/c3c5a07-Screenshot_2022-11-15_at_11.15.59.png) - -2. Add a [Form](doc:forms) with fields for each of the bindings, except for the *id* which will come from the [URL ID](https://docs.budibase.com/docs/url-parameters) binding. - -![](https://files.readme.io/7ebc1ef-Screenshot_2022-11-15_at_12.47.12.png) +> The internal Budibase DB does not support custom queries. It does support [views](https://docs.budibase.com/docs/views). -3. **Define actions** for the 'Submit' button. Choose the **Execute Query** action and pick *PostgreSQL* as the datasource. You should now be able to see and select your custom query. +Use `Read` queries with a [Data provider](doc:data-provider). -![](https://files.readme.io/b2e874e-Screenshot_2022-11-15_at_12.49.34.png) +Use `Execute Query` for create, update, or delete actions. -4. Finally map your form field bindings to your custom query bindings like so: +Add bindings when the query needs dynamic values, and use the query settings to override defaults at runtime. -![](https://files.readme.io/382af3b-Screenshot_2022-11-15_at_12.51.51.png) +You can edit, duplicate, or delete queries from the datasource list. -Click **Save** to finish. \ No newline at end of file +For the standard SQL workflow, see [Working with SQL datasources](doc:sql-workflow). diff --git a/docs/Data/sql-datasource.md b/docs/Data/sql-datasource.md index 9910f9fb0..01d9c9e42 100644 --- a/docs/Data/sql-datasource.md +++ b/docs/Data/sql-datasource.md @@ -19,6 +19,8 @@ Our core SQL datasource connections include: * [Oracle](doc:oracle) * [PostgreSQL](doc:postgresql) +For the shared workflow after connecting, see [Working with SQL datasources](doc:sql-workflow). + {` `} diff --git a/docs/Data/sql-workflow.md b/docs/Data/sql-workflow.md new file mode 100644 index 000000000..ce7c70ce2 --- /dev/null +++ b/docs/Data/sql-workflow.md @@ -0,0 +1,78 @@ +--- +title: Working with SQL datasources +excerpt: Fetch tables, define relationships, and build screens from SQL databases +deprecated: false +hidden: false +metadata: + title: '' + description: '' + robots: index +next: + description: '' +--- +Use this workflow for SQL datasources once the connection is in place. + +## Connect the datasource + +1. Open the **Data** section. +2. Add a new source. +3. Choose your SQL provider. +4. Enter the connection details. +5. Fetch the tables you need. + +See the provider page for connection-specific settings: + +* [PostgreSQL](doc:postgresql) +* [MySQL / MariaDB](doc:mysql-mariadb) +* [MS SQL Server](doc:ms-sql-server) +* [Oracle](doc:oracle) + +## Fetch tables + +Fetch only the tables you need. This keeps the schema easier to manage and reduces the amount of setup later. + +## Define relationships + +Add relationships for the joins you want to reuse in screens and bindings. + +Use one-to-many relationships for foreign keys and many-to-many relationships when you have a join table. + +If Budibase rejects a join table, check the source constraints, fix them in the database, and fetch the table again. + +## Build screens + +Once the tables and relationships are ready, create autogenerated screens from the datasource. + +Use them to: + +* Browse related records +* Open detail or edit views +* Filter by selected values +* Reuse relationships in bindings and repeaters + +## Custom queries + +Use a custom query when the data shape is easier to express in SQL than in the screen builder. + +Custom queries are useful for: + +* Flattening nested relationships +* Grouped or aggregated results +* Write workflows that run from a form action +* Returning a shape that is easier to bind in design + +For read operations, select `Read` when you want to use the query with a data provider. + +For write operations, use `Execute Query` from a form or button action. + +## Query bindings + +Add bindings when the query needs dynamic values. Use the query settings drawer to override defaults at runtime. + +## Related guides + +* [SQL datasource](doc:sql-datasource) +* [PostgreSQL](doc:postgresql) +* [Screens](doc:screens) +* [Data providers](doc:data-provider) +* [Bindings](doc:bindings) diff --git a/docs/References/command-interface.md b/docs/References/command-interface.md index 8be92de0d..96bec710e 100644 --- a/docs/References/command-interface.md +++ b/docs/References/command-interface.md @@ -71,7 +71,7 @@ This shows a list of all tables you have fetched within an app. Allows you to ea ## Query -Find all [queries](doc:postgresql#better-approach-using-a-custom-query) related to data sources here. Navigate to view and manage these queries. +Find all [queries](doc:sql-workflow#custom-queries) related to data sources here. Navigate to view and manage these queries. * **Query**: Create Row * **Query**: Get User Record @@ -97,4 +97,4 @@ Change the appearance of the builder interface by selecting a [theme](doc:app-th * **Change Builder Theme**: Dark * **Change Builder Theme**: Darkest * **Change Builder Theme**: Nord -* **Change Builder Theme**: Midnight \ No newline at end of file +* **Change Builder Theme**: Midnight From 49d95afe7f4f7d3298c2a4b87ec213795c44a562 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 13:20:27 +0100 Subject: [PATCH 06/32] sixth batched update --- .../automation-actions/js-scripting-copy.md | 52 ++----- .../automation-actions/js-scripting.md | 52 ++----- .../automation-actions/slack-notification.md | 34 +---- .../automation-actions/trigger-automation.md | 144 ++---------------- 4 files changed, 54 insertions(+), 228 deletions(-) diff --git a/docs/Automation/automation-actions/js-scripting-copy.md b/docs/Automation/automation-actions/js-scripting-copy.md index af76b4628..e24c3d79f 100644 --- a/docs/Automation/automation-actions/js-scripting-copy.md +++ b/docs/Automation/automation-actions/js-scripting-copy.md @@ -14,44 +14,21 @@ While [Bindings](doc:data-in-automations) in automations support JavaScript, you Commonly this action is used to compare and aggregate data from multiple Datasources. -
+## Add the step -## Adding a JavaScript code block +1. Add a trigger to your automation. +2. Add the `JS Scripting` step. +3. Open the step details and use the bindings drawer if you need values from previous steps. -1. After adding an automation [Trigger](doc:trigger), click the `+` icon and select `JS Scripting`. +Make sure the script returns a value. - ![](https://files.readme.io/cf1df567778632c1cd4a4bf0d022c7f01ebc2272d163a763fb4804c136284c5b-image.png) -2. Click on the automation step to see it's details in on the right of the builder. You can click on the lightning bolt to open the bindings drawer. +## Use bindings - ![](https://files.readme.io/0ecb8dc9f8555f2f5c5096c5f46023d02c44f820f892fecca6f5bdc2d4e84ae9-image.png) +Bindings can be read directly in your script. -> 📘 -> -> Make sure to **return** a value at the end of your script! +Example: -3. Available bindings can be seen on the far right of your modal. These can be clicked to references within your JS scripting area. - -Be sure to check the debugging tools on offer when building your automations. - - - -
- -## Tutorial: Using Cron Triggers and JS Steps - -This tutorial assumes that you have a table called People in the internal database, populated with first\_name, last\_name, date\_of\_birth. - -1. Create an automation that uses a Cron Trigger, and set it to run at 8AM each morning - - ![](https://files.readme.io/e5e397071ff1c49bba6b047fb6fc5a4352eaf3bfbd1e718a2960de69f3671777-image.png) -2. Add a Query Rows step set to fetch everything from your People table with no filters - - ![](https://files.readme.io/cc8ae419a1839caad1e103d3b22c7fff67aa916d601c224ef3dbc6ec90832bfa-image.png) -3. Next, add a JS Scripting Block. In it, you can copy & paste the below code. This code takes the result of the Query Rows step, and makes use of JavaScript's `Date` in order to check if any values for `date_of_birth` are today. With it, we then return an array of people who's birthday is today. - - ![](https://files.readme.io/d3695b3553327050d4744297c3da90f51dbeba0ef20b35ab3f2f09e8c626cc44-image.png) - -``` +```javascript const rows = $("steps.Query rows.rows") const today = new Date() const todayMonth = today.getMonth() @@ -73,9 +50,12 @@ rows.forEach((row) => { return birthdays ``` -4. After your JS Scripting block, split into two branches. The run-conditions are equated from left-to-right, meaning the first truthy-comparison will run. +## Good practice + +Keep scripts focused on data shaping, not business logic that belongs in a table or app screen. - The first branch checks if the length of the Birthdays array (The output from the JS Scripting Block) is not 0, meaning there are birthdays today. The following Slack Message step loops over the Birthdays Array to send a new message for each object in the Birthdays array wishing them a happy birthday +## Related guides - ![](https://files.readme.io/60cfa2ba808fd8b687f1982e2e74c2312b0b842f4cb0cf8fb18a910f7f94dfd0-image.png) -5. The other branch has no condition set (see "Add Condition"), which means it will always run if no branches to its left have run. It's Slack Message step simply wishes everyone a good morning. +* [Bindings in automations](doc:data-in-automations) +* [Trigger automation](doc:trigger-automation) +* [Action steps](doc:automation-actions) diff --git a/docs/Automation/automation-actions/js-scripting.md b/docs/Automation/automation-actions/js-scripting.md index 66612b502..76871f061 100644 --- a/docs/Automation/automation-actions/js-scripting.md +++ b/docs/Automation/automation-actions/js-scripting.md @@ -14,44 +14,21 @@ While [Bindings](doc:data-in-automations) in automations support JavaScript, you Commonly this action is used to compare and aggregate data from multiple Datasources. -
+## Add the step -## Adding a JavaScript code block +1. Add a trigger to your automation. +2. Add the `JS Scripting` step. +3. Open the step details and use the bindings drawer if you need values from previous steps. -1. After adding an automation [Trigger](doc:trigger), click the `+` icon and select `JS Scripting`. +Make sure the script returns a value. - ![](https://files.readme.io/cf1df567778632c1cd4a4bf0d022c7f01ebc2272d163a763fb4804c136284c5b-image.png) -2. Click on the automation step to see it's details in on the right of the builder. You can click on the lightning bolt to open the bindings drawer. +## Use bindings - ![](https://files.readme.io/0ecb8dc9f8555f2f5c5096c5f46023d02c44f820f892fecca6f5bdc2d4e84ae9-image.png) +Bindings can be read directly in your script. -> 📘 -> -> Make sure to **return** a value at the end of your script! +Example: -3. Available bindings can be seen on the far right of your modal. These can be clicked to references within your JS scripting area. - -Be sure to check the debugging tools on offer when building your automations. - - - -
- -## Tutorial: Using Cron Triggers and JS Steps - -This tutorial assumes that you have a table called People in the internal database, populated with first\_name, last\_name, date\_of\_birth. - -1. Create an automation that uses a Cron Trigger, and set it to run at 8AM each morning - - ![](https://files.readme.io/e5e397071ff1c49bba6b047fb6fc5a4352eaf3bfbd1e718a2960de69f3671777-image.png) -2. Add a Query Rows step set to fetch everything from your People table with no filters - - ![](https://files.readme.io/cc8ae419a1839caad1e103d3b22c7fff67aa916d601c224ef3dbc6ec90832bfa-image.png) -3. Next, add a JS Scripting Block. In it, you can copy & paste the below code. This code takes the result of the Query Rows step, and makes use of JavaScript's `Date` in order to check if any values for `date_of_birth` are today. With it, we then return an array of people who's birthday is today. - - ![](https://files.readme.io/d3695b3553327050d4744297c3da90f51dbeba0ef20b35ab3f2f09e8c626cc44-image.png) - -``` +```javascript const rows = $("steps.Query rows.rows") const today = new Date() const todayMonth = today.getMonth() @@ -73,9 +50,12 @@ rows.forEach((row) => { return birthdays ``` -4. After your JS Scripting block, split into two branches. The run-conditions are equated from left-to-right, meaning the first truthy-comparison will run. +## Good practice + +Keep scripts focused on data shaping, not business logic that belongs in a table or app screen. - The first branch checks if the length of the Birthdays array (The output from the JS Scripting Block) is not 0, meaning there are birthdays today. The following Slack Message step loops over the Birthdays Array to send a new message for each object in the Birthdays array wishing them a happy birthday +## Related guides - ![](https://files.readme.io/60cfa2ba808fd8b687f1982e2e74c2312b0b842f4cb0cf8fb18a910f7f94dfd0-image.png) -5. The other branch has no condition set (see "Add Condition"), which means it will always run if no branches to its left have run. It's Slack Message step simply wishes everyone a good morning. +* [Bindings in automations](doc:data-in-automations) +* [Trigger automation](doc:trigger-automation) +* [Action steps](doc:automation-actions) diff --git a/docs/Automation/automation-actions/slack-notification.md b/docs/Automation/automation-actions/slack-notification.md index 414321105..bf93ae5d8 100644 --- a/docs/Automation/automation-actions/slack-notification.md +++ b/docs/Automation/automation-actions/slack-notification.md @@ -31,27 +31,9 @@ The Slack action uses two fields: You can include bindings in the message to insert values from the trigger row or previous steps. -## Configure the Slack app +## Use bindings -1. Create a Slack app. -2. Enable incoming webhooks. -3. Add a webhook to the workspace. -4. Copy the generated webhook URL. -5. Paste it into the Budibase Slack action. - -## Build the automation - -The common pattern is: - -1. Add a trigger, such as `Row Created`. -2. Add the Slack action. -3. Map the values you want to send into the message. -4. Test the automation. -5. Publish it when the message looks correct. - -## Use trigger data - -Use trigger bindings to include row values in the Slack message. +Use bindings to include row values in the Slack message. Example: @@ -62,17 +44,13 @@ Check out the sale using the link below: https://joe.budibase.app/app/tutorials#/sales/{{ trigger.id }} ``` -## Test and publish - -Test the automation with a sample row first. +## Set up Slack -Then confirm: +Create a Slack app with incoming webhooks enabled, then paste the generated webhook URL into Budibase. -* The webhook posts to the correct channel -* The message includes the expected bindings -* The automation runs when the trigger fires +## Test -Once the test passes, publish the app. +Test the automation with a sample row first. Confirm the message posts to the correct channel and the bindings resolve as expected. ## Related guides diff --git a/docs/Automation/automation-actions/trigger-automation.md b/docs/Automation/automation-actions/trigger-automation.md index 84774a2d3..a9e20e88b 100644 --- a/docs/Automation/automation-actions/trigger-automation.md +++ b/docs/Automation/automation-actions/trigger-automation.md @@ -10,143 +10,31 @@ metadata: next: description: '' --- -As outlined on the [Triggers](doc:trigger) page there are a variety of ways to trigger an automation. +Use the Trigger automation step to call an on-demand automation from another automation. -In particular the [On demand](doc:app-action) trigger allows an End User to directly trigger an automation. It is also possible to call these *On demand* automations from another automation. This is done with the **Trigger an automation** step. +## Before you start - +The target automation must use the `On demand` trigger. -Select an *Automation* (only **On demand** automations will be available). Next you will see the fields from the target automation that must be filled out. In this case it is just the *employee\_id*. +## Step settings -On demand trigger of the target automation - On demand trigger of the target automation - +Choose the automation to run, then map any fields it expects. -Optionally set the *Timeout (ms)* if you want to make use of the response. +Use `Timeout (ms)` if you need to wait for the result. -#### Using the output +## Outputs -There are a couple of useful [bindings](doc:data-in-automations) that are provided by the trigger an automation action step. +The step exposes two outputs: -Selecting the trigger automation outputs - Selecting the trigger automation outputs - +* `Success` - a boolean that indicates whether the target automation completed successfully +* `Value` - the output returned by the target automation -Available bindings - Available bindings - +## Example -* **Success** - a *boolean* field that indicates if the triggered automation passed or errored -* **Value** - the object representing the output of the target automation +If the target automation expects `employee_id`, pass `{{ trigger.id }}` from the calling automation. -
+## Related guides -*** - -## Tutorial: Generating onboarding tasks for new employees - -In this tutorial we will use automations to generate onboarding tasks from a template table whenever a new employee is added. - -The app export for the tutorial can be [downloaded here](https://drive.google.com/uc?export=download\&id=1MU9s7fjEpMpMGWe5vxdqHFYL740KqKM7). *The download may take a few seconds.* - -### Data - -Create three tables. See [Budibase DB](doc:budibasedb) for more on the available data types. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Table name - - Columns -
- **Employees** - - first\_name: `Text`,\ - last\_name: `Text`,\ - hired\_date: `Date` -
- **OnboardingTasks** - - date: `Date` -
- **OnboardingTaskTemplates** - - title: `Text`,\ - description: `Text` -
- -With our tables created, we need to create [Relationships](doc:relationships) between them as follows: - -* One *Employee* -> Many *OnboardingTasks* -* One *OnboardingTaskTemplate* -> Many *OnboardingTask* - -Finally create a *static* [Formula](doc:formula) column in the **OnboardingTask** table. Set this value to the `Template Relationships` *title* field: - - - -In the **Design** section, create two [autogenerated screens](https://docs.budibase.com/docs/screens#autogenerated-screen) for the **Employees** and **OnboardingTasks** tables. - -### Automation - -The automation section is now where we are going to generate onboarding tasks from our templates whenever a new employee is created. - -1. First create a new [On demand](doc:app-action) automation, and `Add field` *employee\_id*. - - -2. Add a [Query Rows](doc:query-rows) step and select the **OnboardingTaskTemplates** table - - -3. Add a **Create Row** step for the **OnboardingTasks** table, and [Add Looping](doc:looping). - 1. The *Input type* should be `Array`, and the *Value* should be the output of our templates query: `{{ steps.1.rows }}` -4. Now fill out the values for the **OnboardingTask** fields: - 1. *Date*: `return new Date()` *(JavaScript binding)* - 2. *Template*: `{{ loop.currentItem._id }}` - 3. *Employee*: `{{ trigger.fields.employee_id }}` - - - -We now have an automation that will create onboarding tasks from our templates, but we still need to *trigger* this automation. We will do this from a second automation: - -5. Create a new automation with a **Row Created** trigger. Select the **Employees** table -6. Add a **Trigger an automation** action step. Select the first automation we created earlier, and provide the *employee\_id* Binding: `{{ trigger.id }}` - - - -[Publish](https://docs.budibase.com/docs/quickstart#preview-and-publish) your app to test out the workflow! - -#### Result - -Creating a new employee - Creating a new employee - - -Generated onboarding tasks - Generated onboarding tasks - +* [Triggers](doc:trigger) +* [Bindings in automations](doc:data-in-automations) +* [Action steps](doc:automation-actions) From 4042412444d1e6d41f9bdc49f2663a74ab31b88a Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 13:32:36 +0100 Subject: [PATCH 07/32] seventh batched update --- docs/Apps/actions/index.md | 18 ++---- docs/Apps/conditions.md | 12 +--- .../design-guides/designing-for-mobile.md | 24 +++----- docs/Apps/design-guides/index.md | 10 +-- docs/Apps/forms/form-bindings.md | 55 ++++++++--------- docs/Apps/forms/index.md | 61 ++++++------------- docs/Apps/forms/save-static-value.md | 10 +-- docs/Apps/working-with-data/index.md | 24 +++----- .../working-with-data/searchfilter-data.md | 50 +++++---------- 9 files changed, 81 insertions(+), 183 deletions(-) diff --git a/docs/Apps/actions/index.md b/docs/Apps/actions/index.md index b37ca8714..991b14b14 100644 --- a/docs/Apps/actions/index.md +++ b/docs/Apps/actions/index.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -There are a wide variety event actions throughout Budibase. These can be split into four different types: Data, Application, Form and Logic actions. +Budibase actions fall into four groups: data, application, form, and logic. ## Data actions @@ -18,22 +18,12 @@ As the title implies, these actions revolve around data. They involve tasks like ## Application actions -These are actions that can happen at any time in your application. They include things like displaying notifications, opening side panels or pop-up windows, logging out users, and even activating automated processes. This can be found [here.](doc:application-actions) +These actions can happen at any time in your application. They include displaying notifications, opening side panels or pop-up windows, logging out users, and starting automations. See [Application actions](doc:application-actions). ## Form actions -There are fewer actions of this kind compared to data and application actions. When it comes to form actions, there are four different actions: `Update Field Value,` `Validate Form,` `Change Form Step,` and `Clear Form.` These actions specifically deal with manipulating different parts of a form and can be found in more detail [here.](doc:form-actions). +Form actions manipulate different parts of a form. The main actions are `Update Field Value`, `Validate Form`, `Change Form Step`, and `Clear Form`. See [Form actions](doc:form-actions). ## Logic actions -Currently there is only one action of this type, this is the [Continue If / Stop if](https://docs.budibase.com/docs/chaining-actions#continue-if--stop-if). - -![]() - -*** - -## Tutorial video - -{` - -`} +Currently there is only one logic action: [Continue If / Stop if](https://docs.budibase.com/docs/chaining-actions#continue-if--stop-if). diff --git a/docs/Apps/conditions.md b/docs/Apps/conditions.md index 6c1faeeea..f1c95ce2d 100644 --- a/docs/Apps/conditions.md +++ b/docs/Apps/conditions.md @@ -10,9 +10,9 @@ metadata: next: description: '' --- -A lot of the time you want to change the state of some component when certain conditions are true or false. This might be changing color from red to green, showing or hiding a component. You will find the condition settings at the very bottom of the settings panel of your components. +A lot of the time you want to change the state of a component when certain conditions are true or false. For example, you might change color, show a component, or hide it. You will find the condition settings at the bottom of the settings panel. -Adding a condition is simple. Once you click the settings button a drawer will pop up and you will be able to add, edit or remove your conditions. It will look something like this +Adding a condition is simple. Once you click the settings button, a drawer opens where you can add, edit, or remove conditions. ![](https://files.readme.io/38f0f21-conditions.png "conditions.png") @@ -59,10 +59,4 @@ And here's the end result. ## Showing and hiding a component based on the user's role -When building apps, we often want to limit a user's access to specific components. For example, we may not want a user to see certain data or access a particular action. - -Below is a quick demonstration of how to hide a button if the user's role is BASIC. Please remember, when typing the value of the user role, it must be in capitals: `BASIC`, `POWER`, `ADMIN`. - -{` -
-`}
\ No newline at end of file +When building apps, you can also use conditions to limit a user's access to specific components. For example, you may want to hide a button when the user's role is `BASIC`. Role values must be uppercase: `BASIC`, `POWER`, `ADMIN`. diff --git a/docs/Apps/design-guides/designing-for-mobile.md b/docs/Apps/design-guides/designing-for-mobile.md index d899a67d1..7e1c78d75 100644 --- a/docs/Apps/design-guides/designing-for-mobile.md +++ b/docs/Apps/design-guides/designing-for-mobile.md @@ -10,27 +10,23 @@ metadata: next: description: '' --- -Budibase allows you to build apps that look great across multiple devices, including desktops, tablets, and mobile. A few simple techniques that you can use to improve the design and usability of the apps you're building for your team. - -{` - -`} +Budibase apps can adapt to desktops, tablets, and mobile devices. Use the settings below to adjust layouts for smaller screens. ## Key responsive settings and defaults ### Breakpoints -Breakpoints are the points in screen size or orientation where an app is triggered to adjust its layout. Breakpoints are how we define our app when it's being used on mobile, tablet, or desktop. Budibase comes with default breakpoints. Users cannot edit these breakpoints. You can visualize the breakpoints (and your design) within the design section by selecting the device toggle (see GIF below). +Breakpoints are the screen sizes where your app switches layout. Budibase includes default breakpoints that you cannot edit. ### Flexbox -Flexbox is a one-dimensional layout method for arranging items in rows or columns. Items flex (expand) to fill additional space or shrink to fit into smaller spaces. Budibase uses flexbox to help users structure their apps. You can access the flexbox properties within the [Container](doc:container) component - your components must be wrapped in a container for Flexbox to arrange your components. +Flexbox arranges items in rows or columns. Use the [Container](doc:container) component to control flex behavior. ### Flex wrap -The flex-wrap property sets whether flex items are forced onto one line or can wrap onto multiple lines. If wrapping is allowed, it sets the direction in that lines are stacked. So, within Budibase, if you have a row of cards and you select flex-wrap, the cards will 'stack'. In the GIF below, selecting the flex-wrap icon tells the browser to 'wrap' the elements within that container and allow them to stack - therefore free the initial component to take up the remaining space in the row. +`flex-wrap` lets items wrap onto multiple lines instead of staying on one line. Use it when cards or other components need to stack on smaller screens. {1200} flex wrap in budibase @@ -38,20 +34,16 @@ The flex-wrap property sets whether flex items are forced onto one line or can w ### Grid Layout -Using Grid layout, it is possible to drag-and-drop components into place, independently of other elements on the screen. +Grid layout lets you place components independently of the other elements on the screen. ### Update a component's setting based on the device -You can conditionally tell Budibase to update a component's setting if the user is on a particular device. For example, you may want to position your form labels to the left when the user is on desktop and above when on mobile. Here's a quick demonstration: - -{` -
-`}
+You can conditionally update a component setting based on the device. For example, set labels to display to the left on desktop and above on mobile. ### Hamburger menu -A hamburger menu is a menu button that enables a drop-down function for navbar links that helps save space in restricted designs. If you use either the side navigation or top navigation layout, Budibase will add a hamburger menu to your app. This is only visible when your users are on a mobile device. +A hamburger menu saves space in restricted layouts. If you use side navigation or top navigation, Budibase adds the menu automatically on mobile devices. - \ No newline at end of file + diff --git a/docs/Apps/design-guides/index.md b/docs/Apps/design-guides/index.md index 635e56a60..66e0db81b 100644 --- a/docs/Apps/design-guides/index.md +++ b/docs/Apps/design-guides/index.md @@ -10,9 +10,7 @@ metadata: next: description: '' --- -Budibase streamlines the design process making it easier and faster to build beautiful UIs. We've worked hard to provide our users with the right balance between simplicity and flexibility. We believe in making the design process as straightforward as possible, and our mission is to help IT professionals build workspaces, apps, and automations they're proud of. - -Within this section, we will cover several design workflows that promote great design within Budibase. +Budibase keeps the design process straightforward while still leaving room for flexibility. | [Displaying data](doc:fetching-data) | | :----------------------------------------------- | @@ -20,9 +18,3 @@ Within this section, we will cover several design workflows that promote great d | [Theming your app](doc:app-theming) | | [Adding search](doc:adding-a-search-field) | | [Adding filtering](doc:searchfilter-data) | - -## Video tutorial - -{` - -`} diff --git a/docs/Apps/forms/form-bindings.md b/docs/Apps/forms/form-bindings.md index 652b2b5a4..14bc45e6c 100644 --- a/docs/Apps/forms/form-bindings.md +++ b/docs/Apps/forms/form-bindings.md @@ -12,7 +12,7 @@ next: --- Forms are critical in a workspace, as they allow users to collect, edit, and submit data. -While bindings are not necessary to build functional forms for the internal [Budibase DB](doc:budibasedb) and [SQL](doc:sql-datasource) tables provide additional flexibility for your form fields when you need dynamic labels, placeholders, or default values. +Bindings are not required for basic forms, but they are useful when you need dynamic labels, placeholders, or default values in the internal [Budibase DB](doc:budibasedb) and [SQL](doc:sql-datasource) tables. You may want to read the value of a form field when handling cases such as: @@ -24,7 +24,7 @@ You may want to read the value of a form field when handling cases such as: ## Read Query: Setting default values -A default value binding will be applied on the initial load of a screen. +A default value binding is applied when the screen first loads. Consider a [REST query](doc:rest-queries) that retrieves an employee record for a bound ID. We can add a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block) to a [Screen](doc:screens) to pull that employee data. @@ -38,9 +38,9 @@ Consider a [REST query](doc:rest-queries) that retrieves an employee record for Selecting the GET query as the data source -After selecting the GET query as the data source for the repeater block, click on the cog icon and provide a binding value. +After selecting the GET query as the data source for the repeater block, click the cog icon and provide a binding value. -In this example I am using the `{{ URL.id }}` binding which is made available through [URL variables](doc:url-parameters). You can however, use any value here, including [App state](https://docs.budibase.com/docs/app-state#app-state-in-blocks). +In this example, the repeater uses `{{ URL.id }}` from [URL variables](doc:url-parameters). You can also use [App state](https://docs.budibase.com/docs/app-state#app-state-in-blocks). Passing the rowId into the GET query Passing the rowId into the GET query @@ -48,7 +48,7 @@ In this example I am using the `{{ URL.id }}` binding which is made available th #### Step 2 - Configure the form -Add a [Form](doc:forms). Add the form fields that you would like to pull data into. Make sure to enter a unique name in the *Field* setting, or select a field if you are also using a [Create query](https://docs.budibase.com/docs/form-bindings#create-query-mapping-query-bindings-to-form-fields). +Add a [Form](doc:forms) and the fields you want to populate. Use a unique name in the *Field* setting, or select a field if you are using a [Create query](https://docs.budibase.com/docs/form-bindings#create-query-mapping-query-bindings-to-form-fields). For the *Default value* setting, click on the lightning bolt icon, and add the binding to pull out the specific field, for example *Address*: @@ -58,23 +58,23 @@ For the *Default value* setting, click on the lightning bolt icon, and add the b {{ Employee Repeater block.GET Employee Row.Address }} ``` -Once all fields have been added with their appropriate default values, you should see something like so: +Once the fields have the correct default values, you should see something like this: -Note that you may need to refresh the page - remember that default values only apply on load of the screen. +You may need to refresh the page. Default values only apply on load. *** ## Create Query: Mapping query bindings to form fields -If you are building a create form, then it is possible to use the bindings of a 'Create' type custom query as the schema of your form. This means that the form fields will automatically be populated in a [Field group](doc:field-groups) to match the query inputs. +If you are building a create form, you can use the bindings from a `Create` custom query as the schema for the form. The form fields populate in a [Field group](doc:field-groups) to match the query inputs. -For example consider the case of a POST REST query: +For example, consider a POST REST query: #### Step 1 - Add the REST query -Add your binding fields, and optionally set some default values. These will be used in the body of your POST query, and as the schema for your form in the Design section. +Add the binding fields and any default values. These are used in the POST body and as the form schema in Design. POST query bindings POST query bindings @@ -86,52 +86,51 @@ Add your binding fields, and optionally set some default values. These will be u #### Step 2 - Add the form -Add a form and select your create query as the schema. +Add a form and select the create query as the schema. Selecting the form schema Selecting the form schema -Next add a field group, and click the `Update form fields`. You can see that this will now populate the Component Tree with form fields that match your bindings. +Add a field group, then click `Update form fields`. Budibase will populate the Component Tree with form fields that match your bindings. Auto-populating form fields via the field group Auto-populating form fields via the field group -Finally you can add a submit [Button](doc:button) with an [Execute query action](https://docs.budibase.com/docs/data-actions#execute-query). Bind the query bindings to your the form fields: +Add a submit [Button](doc:button) with an [Execute query action](https://docs.budibase.com/docs/data-actions#execute-query), then bind the query inputs to the form fields: > 👍 > -> It is possible to combine the Read and Create query examples shown here into a single form. +> You can combine the read and create examples into a single form. *** ## On Change event -If you want to perform [Actions](doc:actions) when a form field value has changed, you can use the *On Change* event. +Use the *On Change* event when you want to run [Actions](doc:actions) after a field value changes. -Within the Settings Panel of each form field you can find the `Define action` button beside the *On change* label. +In the Settings Panel of each form field, click `Define action` beside *On change*. -### Tutorial: Calculate age from DOB field +### Calculate age from DOB field -1. Create a new app with a new internal Budibase DB table called **Patients**. Add a [Text](doc:text) field for the *Name* of the patient, and another [Date/Time](doc:datetime) field for the *DOB*. Add some rows. +1. Create a **Patients** table with a [Text](doc:text) field for the patient name and a [Date/Time](doc:datetime) field for the DOB. -2. Add a **Side panel** [Autogenerated screen](https://docs.budibase.com/docs/screens#autogenerated-screen) for the **Patients** table. Delete the new row side panel. -3. Eject the form block inside the Side panel. -4. In the form within the *Edit row side panel* , add another field, this time a [Number field](https://docs.budibase.com/docs/text-inputs#number-field), and make it *Disabled*. Type 'Age' into the *Field* name setting. +2. Add a **Side panel** [Autogenerated screen](https://docs.budibase.com/docs/screens#autogenerated-screen) for the **Patients** table. +3. Eject the form block, then add a disabled [Number field](https://docs.budibase.com/docs/text-inputs#number-field) called `Age`. -4. Next select the *DOB* field, and click on `No actions set` beside the *On change* setting. Add an **Update Field Value** action for the *Details Form*, and choose the 'Age' field as the target.\ - For the value, click on the lightning bolt icon and select the *JavaScript* tab. Here we will calculate the *Age* from the *DOB*. +4. Select the *DOB* field, then add an **Update Field Value** action for the `Age` field. +5. For the value, open the *JavaScript* tab and calculate the age from the DOB. ![](https://files.readme.io/a52f4f6-small-Screenshot_2023-05-10_at_15.04.20.png) -5. Provide the following JavaScript binding: +6. Provide the following JavaScript binding: ```javascript Calculate Age from DOB /** @@ -151,7 +150,7 @@ function getAge(dateString) { return getAge($("Field Value")); ``` -Make sure to save! Also note the binding that is being used - we want to use the newly selected date value: +Save the form after updating the binding. > 👍 `{{ Field Value }}` > @@ -159,8 +158,4 @@ Make sure to save! Also note the binding that is being used - we want to use the > ❗️ `{{ Details Form.Fields.DOB }}` > -> Will get the previous value; before the on change was triggered. - -*** - -## +> Gets the previous value before *On change* runs. diff --git a/docs/Apps/forms/index.md b/docs/Apps/forms/index.md index 21e39a323..4951db92f 100644 --- a/docs/Apps/forms/index.md +++ b/docs/Apps/forms/index.md @@ -10,35 +10,30 @@ metadata: next: description: '' --- - +Forms are the primary building blocks of data-heavy applications. Use them to create and edit data with a consistent layout and theme. -Forms are the primary building blocks of any data-heavy application. With Budibase you can build rich, themeable forms to create and edit your data. Forms are built up from 3 main component types: +Forms are built from three main component types: 1. **Form component** 2. **Field group component** 3. **Input components** -
- ## Form component -The Form component is the top-level component of forms. All [Field groups](doc:field-groups) must be placed inside a form, and they won't work outside it. The form component is flexible and allows you to control layout, design, and theme. - -Fields can now be used independently of a Form Component, which can speed up the development process when building things like Search fields. When taking this approach, fields will be available in the bindings drawer. +The Form component is the top-level container. All [Field groups](doc:field-groups) must be placed inside it. - +You can also use fields independently of a form when you need simpler input controls, such as search fields. ### Form schema -Forms have a **Schema** setting which is optional. The schema for a form can be a table, view, relationship or "custom". A custom schema means that there is no backing data source schema. +Forms have an optional **Schema** setting. The schema can be a table, view, relationship, or custom source. -Choosing a form schema has the following advantages: +Choosing a schema helps with: -* When adding fields, field names can be chosen from a dropdown rather than being typed -* Field validation is automatically added to match the schema -* If you want to create rows in a table using your form data, you'll need to choose the correct schema for the table you'll be saving your data to -* Fields will be able to automatically prevent you from entering an illegal field name for a certain data type -* Form components can be automatically generated to match the schema +* Picking field names from a dropdown +* Matching validation to the selected data type +* Generating form components automatically +* Creating rows with the correct table schema > 🚧 Schema from query > @@ -46,46 +41,24 @@ Choosing a form schema has the following advantages: ### Form type -A form can be in 'Create' mode or 'Update' mode. - -In *Create* mode, the form fields will be initially blank, with the exception of those with an assigned Default Value +A form can be in `Create` mode or `Update` mode. -In *Update* mode, the form fields will automatically be populated from the parent [Repeater](doc:repeater) data, assuming the form schema is not set to custom. +In `Create` mode, fields start blank unless they have a Default Value. - - -
+In `Update` mode, fields are populated from the parent [Repeater](doc:repeater) data, unless the schema is custom. ## Inputs -Each input component represents a single field in the form. There are different components for every data type. All fields have a field and label setting. The field is the name of the field or property of the schema. This can be free typed or if a schema exists on the form, selected from a list. There are unique components for every type of data, and if your form has a schema then you'll only be able to choose field names that fit the particular type of component that is selected. The label setting is the label that will be displayed beside or above your field. Most fields also have a placeholder setting to control the text displayed when the field is empty. +Each input component represents a single field. The field name comes from the schema or can be typed manually if no schema is set. ### Custom Inputs / Fields -Whether your form has a schema or not, you can always add custom fields that don't exist in the schema by free typing the name of the field. Data Bindings will always reflect the names of all the fields in your form - so even if you don't have a schema on your form, you'll be able to bind to any of your fields. +You can add custom fields that are not part of the schema. Data Bindings always reflect the names of the fields in the form. ### Help text setting -To add some context to your form fields, you can add some 'Help text'. For example, you may want to pro-actively inform your users about the [validation](doc:form-validation) of your fields. If a validation error is triggered, then the help text will be replaced with the red error message. - -Adding some 'Help text' - Adding some 'Help text' - - -Help text on the form field - Help text on the form field - - -
+Use help text to give context or explain validation. If validation fails, the help text is replaced with the error message. ## Nesting non-form components -Forms can contain any components, not just fields. A handy way to manage layout is to put fields and other components inside [Field groups](doc:field-groups). - -
- -## Video tutorial - -{` - -`} +Forms can contain any components, not just fields. Use [Field groups](doc:field-groups) to manage layout. diff --git a/docs/Apps/forms/save-static-value.md b/docs/Apps/forms/save-static-value.md index fa089f6b4..311386ae3 100644 --- a/docs/Apps/forms/save-static-value.md +++ b/docs/Apps/forms/save-static-value.md @@ -10,12 +10,6 @@ metadata: next: description: '' --- -It's common when creating forms to save a static value when a user submits a form. For example, when an applicant applies for a job, you may want to save a static value such as "Requires HR attention". +It is common to save a static value when a user submits a form. For example, when an applicant applies for a job, you may want to save a value such as `Requires HR attention`. -To achieve this, navigate to the button within your form. Then navigate to your [Button](doc:button) [Actions](doc:actions) . Add a **Save Row** action. Then click the add column button, select your desired column and input your static value. Every time a user submits your form, the static value will be saved alongside the selected column. - -Below is a quick visual demonstration. - -{` -
-`}
+To do this, open the button in your form and add a **Save Row** action. Add the target column, then enter the static value. Every time the form is submitted, Budibase saves that value alongside the row. diff --git a/docs/Apps/working-with-data/index.md b/docs/Apps/working-with-data/index.md index 8bf4577df..96e362f72 100644 --- a/docs/Apps/working-with-data/index.md +++ b/docs/Apps/working-with-data/index.md @@ -10,32 +10,22 @@ metadata: next: description: '' --- -A [Data provider](doc:data-provider) fetches data and provides it to all child components. Any child components which take in data to display, have a *Data* setting where you can select the data provider that passes it data. You can hook up as many components as you like to the same data provider, and they'll all be in sync with each other. +A [Data provider](doc:data-provider) fetches data and passes it to child components. Any component that displays data has a **Data** setting where you can choose the provider. -Data providers have settings to control filtering, sorting, and pagination. Because all of these data settings are handled by the data provider, it keeps all components as purely presentational. You can update the source of your data provider and your whole dashboard will instantly reflect an entirely different table! - - +Data providers control filtering, sorting, and pagination. This keeps the components presentational and makes it easier to reuse the same source across a screen. > 👍 Blocks > -> For common data presentations, you can use [Blocks](doc:blocks). +> For common data presentations, use [Blocks](doc:blocks). > -> Blocks bundle a data provider with other components, thus reducing the nesting in your Component Tree. +> Blocks bundle a data provider with other components and reduce nesting in your Component Tree. ## Fetching data -After adding a Data provider, you must navigate to the Settings Panel and select a Datasource - as shown below: - - +After adding a data provider, open the Settings Panel and select a Datasource. > 🚧 Using Multiple Data Providers > -> Data Providers can use other Data Providers as a source +> Data providers can use other data providers as a source. > -> Each time a Data Provider is set to fetch information from a table or query, it creates extra network traffic on screen-load. If you're re-using data in multiple components on your screen, consider using a Data Provider to fetch the table without filters, and then any subsequent Data Providers can fetch from that first Data Provider and filter as needed, cutting down on the amount of queries to your database. - -## Video tutorial - -{` - -`} +> Reusing a single unfiltered provider can reduce extra network traffic when multiple components need the same data. diff --git a/docs/Apps/working-with-data/searchfilter-data.md b/docs/Apps/working-with-data/searchfilter-data.md index fc743e5b2..5f7460f08 100644 --- a/docs/Apps/working-with-data/searchfilter-data.md +++ b/docs/Apps/working-with-data/searchfilter-data.md @@ -22,45 +22,39 @@ If you have a [Table](doc:table) component connected to a [Data provider](doc:da Once you have linked a Datasource to a component, you can access the filter drawer by clicking the button beside the *Filtering* setting in the Settings Panel. -Adding filters to a Data provider - Adding filters to a Data provider - - The filter drawer is where you select the columns you want to filter on. For example, you may want to return sales records only where any of the sales reps made more than 60 sales, or all sales made in the first week of the month. - - It is also possible to filter on multiple columns, and even filter on the same column multiple times. ## Filtering data from the front-end -Often you will find yourself wanting to let the user filter the data on the front-end. This can be achieved as well but requires a bit more work.To get started, add a Data Provider and set the data source. In this example we want to let the user filter to narrow down by day\_of\_month. +To let users filter data on the front end, add a [Data provider](doc:data-provider) and connect it to your source. -Next, add a Form Component, and add two Number fields. set the first to be day\_start, and label it "Day of month (start)". Take similar steps i for the other Text Field, naming it day\_end and labelling it "Day of month (end)" +Then add a [Form component](doc:form) with two Number fields: -In the data provider, select the define filters button. Next, add an expression and select the column you wish to filter on - in this case `day_of_month`, `More than or equal to` and `Binding`. Select the lightning bolt icon to the right and select the number field choose "start\_day". Repeat the process for the the upper-limit of the filter, this time using "less than or equal to". Now your user can specify a start and end day and view sales made in that particular timeframe. +* `day_start` with the label `Day of month (start)` +* `day_end` with the label `Day of month (end)` - +In the data provider, open the filter drawer and add two expressions: - +* `day_of_month` is `more than or equal to` `day_start` +* `day_of_month` is `less than or equal to` `day_end` -## Filtering options & Filter Groups +Users can now choose a start and end day to narrow the results. -When filtering, there are a couple of settings that can be tweaked that determine how the filters are handled. +## Filtering options & Filter Groups -Notice the change in the second filter group from And to Or - Notice the change in the second filter group from And to Or - +When filtering, there are a few settings that control how the filters are handled. #### Behaviour when combining Filter Groups * **Show data which matches all filter groups**: all filters must match when returning records -* **Show data which matches any filter** : records are returned when they match on any of the provided filter groups +* **Show data which matches any filter**: records are returned when they match any of the provided filter groups #### Behaviour in Filter Groups themselves * **Show data when any of the following filters are matches**: Only one of the filters needs to match in order to return this record -* **Show data when all of the following filters are matches** : All of the filters in this group need to match in order to return this record +* **Show data when all of the following filters are matches**: All of the filters in this group need to match in order to return this record
@@ -68,22 +62,6 @@ When filtering, there are a couple of settings that can be tweaked that determin This setting is specific to filters that are using Bindings. It determines what data should be returned if the binding values are blank. -By default, if all of the filter binding values are empty, then all the rows will be returned. If *Return no rows* is selected and the binding values are empty, then no rows will be returned. This can be particularly useful when pairing a table with search fields, as an empty search field will result in all rows being shown, but as a user types a search-term it will narrow the list down. - - - -As shown, the filters are bound to two form fields which are currently empty, therefore *all table rows* are returned. - - - -In this screenshot we can see that the *Return no rows* option is selected, which prevents rows being displayed as the bound form values are empty. Below we can see that now rows are returned when filters are empty, rows matching the search term are found and returned, and then no rows are returned when nothing matches the filter. - - - -## Video tutorial: filter with two option pickers - -{` -
-`}
+By default, if all filter binding values are empty, all rows are returned. If *Return no rows* is selected, empty bindings return no rows. This is useful when pairing a table with search fields because an empty search field shows all rows and a value narrows the list. -You can also filter using a [relationship picker](https://docs.budibase.com/docs/filter-by-relationships). \ No newline at end of file +You can also filter using a [relationship picker](https://docs.budibase.com/docs/filter-by-relationships). From 6fe691d884c3fdc37b6e7bff16b4073f996276c7 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 8 Jul 2026 13:41:32 +0100 Subject: [PATCH 08/32] eighth batched update --- docs/Apps/actions/chaining-actions.md | 72 +++++++----------------- docs/Apps/components/icon.md | 34 ++--------- docs/Apps/pickers/multi-select-picker.md | 55 +++++------------- 3 files changed, 38 insertions(+), 123 deletions(-) diff --git a/docs/Apps/actions/chaining-actions.md b/docs/Apps/actions/chaining-actions.md index bdc1fb278..619074ab6 100644 --- a/docs/Apps/actions/chaining-actions.md +++ b/docs/Apps/actions/chaining-actions.md @@ -10,13 +10,13 @@ metadata: next: description: '' --- -Using Budibase, you can create a sequence of actions. Actions run synchronously; if one fails, the actions after won't run. +Use chained actions when one action depends on the output of the previous one. Actions run synchronously, so if one fails, later actions do not run. ## Action referencing -Accessing data from a previous action in a new action can be useful. +Accessing data from a previous action in a later one can be useful. The following actions expose data after execution: @@ -105,7 +105,7 @@ The following actions expose data after execution: -**Note** X is the action number +**Note** X is the action number.
@@ -113,13 +113,13 @@ The following actions expose data after execution: ## Query result properties -In addition to the payload data of an execute query action result, you can also access the following additional information: +In addition to the payload data of an execute query action result, you can also access: * Status code - *Number* * Response time - *String including the time unit* * Payload size - *String including the size unit* -This can be useful in combination with [Conditional UI](doc:conditions) for navigating to different screens upon an error, or to change text color based on the status code. +This can be useful with [Conditional UI](doc:conditions) for navigating to different screens on error or changing text color based on the status code. ### Example @@ -147,58 +147,26 @@ This can be useful in combination with [Conditional UI](doc:conditions) for navi ## Tutorial: Creating and Linking two table entries in one form -#### Schema +Use chained actions when one action depends on the output of the previous one. A common pattern is to create one row, then use its ID in a second row. -* Bookings -* Leaders -* One Booking -> One Leader +#### Setup -*** - -#### Use Case - - Create a new booking and a new associated leader in one form - -*** - -#### Steps - -1. In the Data tab, using the internal BudibaseDB, create a new table, "guides", containing the following columns - name (text), phone\_number(text), email(text). Populate these with a few rows of dummy-data. -2. Create another table, "tours", containing the following columns - destination(text) date(date, set to "Date only"). -3. In the tours table, add a column called "guide", with a relationship of many rows in tours to one row in guides. Set the column name in the other table to be "tours". - - -4. Switch back to your guides table to see that the relationship column has been created. The circle with an arrow denote that this column is a relationship to another table. - - -5. Create a new app called "Creating and Linking two table entries in one form" -6. Add a new screen, add a form component (not to be confused with a Form Block). Set the form component to create a row in the tours table. - - -7. Add a Text Field component to your form, and set the name as "destination" and the label as "Tour Destination" - - -8. Repeat the previous step until your form has all of the following +Create two tables: -| Field | Name | Label | -| :--------- | :---------- | :------------------------- | -| Text Field | destination | Tour Destination | -| Date Field | date | Tour Date | -| Text Field | TGname | Tour Guide's Name | -| Text Field | TGphone | Tour Guide's Phone Number | -| Text Field | TGemail | Tour Guide's Email Address | +* `guides` with `name`, `phone_number`, and `email` +* `tours` with `destination` and `date` -8. Next, add a button as a child of your Form Component - Set the text to "Save" and (optional) add an Icon -9. Add an On click action to the button: Validate Form will catch any "required" fields, as well as any custom validation set on a per-field basis (though not applicable in this guide). -10. Add another action - Save Row. Select your form as the datasource, and set the table as tours. Add two columns from the tours table, destination and date, and assign the values from the destination and date fields accordingly. +Add a relationship from `tours` to `guides`. - +#### Build the form -
-11. Add another Save Row action, but this time we will save the Tour Guide's information to the guides table. Look closely at the fourth column - tours - this is saving row\_id from the previous action, which is linking the two rows together. This action will save a new tour and a new guide, and show the relationship between them. +1. Add a form that creates a row in `tours`. +2. Add fields for `destination`, `date`, `TGname`, `TGphone`, and `TGemail`. +3. Add a button with a `Validate Form` action. - -12. (optional) Check the "Do not display default notification" on *one* of the Save Row actions. -13. Add a "Clear Form" action to reset the form back to it's default values +#### Chain the actions -You could also use a "Navigate To" action to take the user to a screen showing the information in a table, or back to the homepage. \ No newline at end of file +1. Add a `Save Row` action for `tours`. +2. Add a second `Save Row` action for `guides`. +3. Use the row ID from the first action to link the new guide to the new tour. +4. Optionally add `Clear Form` or `Navigate To` after the saves complete. diff --git a/docs/Apps/components/icon.md b/docs/Apps/components/icon.md index ffd3ebfe7..ba9a92502 100644 --- a/docs/Apps/components/icon.md +++ b/docs/Apps/components/icon.md @@ -12,38 +12,14 @@ next: --- Icons are scalable vector graphics, which means that they look great on high-resolution displays. +To add an Icon component, click `Add component` and search for `Icon`, or find it under the *Basic* section. -To add an Icon component, click `Add component` and search for "Icon", or locate it under the *Basic* section. - - -Within the Settings Panel under the *Icon* setting, a button will show the currently selected icon, or `Pick icon` if no icon has been selected. Click the button to change the icon. - - -This will allow you to filter the Font Awesome library alphabetically or search for keywords. - -
+In the Settings Panel, the *Icon* setting shows the selected icon or `Pick icon` if none is set. Click it to change the icon and search the Font Awesome library by keyword or alphabetically. ## Using an icon as a button -Icons support the **On Click** event. You can define all of the [Actions](doc:actions) that a button can. - - -## Tutorial: Displaying options as icons - -In this tutorial, we will create an app with the [sample data](https://docs.budibase.com/docs/data-sources#sample-data), and display an icon based on the *Item Tags* value of the *Inventory* table. To do this, we will make use of [Conditional UI](doc:conditions). - -1. Add a [Data provider](doc:data-provider) for the *Inventory* table. -2. Add a [Repeater](doc:repeater) nested inside the data provider. -3. Nest an Icon component within the repeater. This will display an icon for each tag. - -4. Select the icon component on the far right of the screen. You should see its settings. -5. Click the conditions tab - -6. Click the `no conditions set` button, this will open a drawer were you can configure your conditions -7. Click the `Add condition` button to create your conditions. In our case, we are going to use the update setting option. This will allow us to dynamically change the icon based on the inventory table's tag values. (Use the duplicate button to make your life easier!) - - -### Result +Icons support the **On Click** event, so they can trigger the same actions as buttons. -Using a container to hold the Icon, and a Text component to accompany it, we can then show the item tags and an accompanying icon. +## Use conditions +Use [Conditional UI](doc:conditions) to switch the icon based on the current row or component state. diff --git a/docs/Apps/pickers/multi-select-picker.md b/docs/Apps/pickers/multi-select-picker.md index f725ea9f0..bbe1dd294 100644 --- a/docs/Apps/pickers/multi-select-picker.md +++ b/docs/Apps/pickers/multi-select-picker.md @@ -10,17 +10,15 @@ metadata: next: description: '' --- -The `multi-select` option is almost entirely the same as the [Options Picker](doc:option-picker), with the only difference being you can select more than one option in the dropdown. +The `multi-select` option works like the [Option Picker](doc:option-picker), but it lets you select more than one option in the dropdown. > 📘 Explore features at Option Picker > -> To explore most features the multi-option picker offers, head over to the [Option Picker](doc:option-picker) page. This includes sources for the options, autocomplete, and more. +> To explore most features the multi-select picker offers, head over to the [Option Picker](doc:option-picker) page. This includes sources for the options, autocomplete, and more. -## Adding multi-select picker +## Adding the picker -To add the multi-select picker, choose it from \`Form > Multi-select Picker. Make sure the picker is wrapped in a [Form](doc:forms) element to function correctly. - -![](https://files.readme.io/4ea4a11-Screenshot_2023-07-04_at_12.13.17.png) +To add the multi-select picker, choose it from `Form > Multi-select Picker`. Make sure the picker is wrapped in a [Form](doc:forms) element to function correctly. ## Adding options to the picker @@ -28,46 +26,19 @@ To add options, head over to the [Option Picker](doc:option-picker#displaying-op ## Retrieving data from the picker -Opposed to the option picker which returns 1 value, the multi-select picker returns an array of items, even if only one item is selected. When using the data, make sure you handle the data as an array in that situation. Storing the array in a text field will either fail or stringify. +Unlike the option picker, which returns one value, the multi-select picker returns an array of items even if only one item is selected. Handle the result as an array. Storing the array in a text field will either fail or stringify. ## Checkboxes -A multi-select picker can be displayed as a list of tickable options, or as a set of checkboxes. This is purely a visual choice and does not affect the functionality. - -The use of checkboxes can be switched easily: - -![](https://files.readme.io/8a0f3431a502371aebc19537988b569c201f2d552da76805ee373fe9fcfa6faa-image.png) - -If you choose checkboxes, you will also have the option to determine if they should be displayed horizontally or vertically. - -![](https://files.readme.io/fde8ef29572cbb6a6c731b4e00178f140ef298c0c98c36677501358090ee1f91-image.png) - -![](https://files.readme.io/b42619a-Screenshot_2022-07-20_at_16.44.57.png) +A multi-select picker can display as tickable options or as checkboxes. This is a visual choice and does not affect functionality. If you use checkboxes, you can also choose whether they display horizontally or vertically. ## Tutorial: Sum of selected items -In this tutorial we will display the sum of selected items from a multi-select picker. - -Start by creating your table of items. Give each item a *Text* name and *Number* cost. - -![](https://files.readme.io/a95ba851f5e9bcc221479498d2a4e86f19997f4120f4ebd39274738dfa09f002-image.png) - -Next create a new [Formula](https://docs.budibase.com/docs/formula) column. This will be used to display a pretty formatted label for the item options. - -Call it 'Label' and use the following binding: `{{ Name }} [ ${{ Cost }} ]` - -![](https://files.readme.io/b6697ffd9058ce4ca1f14eeb747c54136ecfe5bdaa563e424b5233d70533c967-image.png) - -In the Design section add a [Data Provider](https://docs.budibase.com/docs/data-provider) for the 'Items' table, and nest a [Form](https://docs.budibase.com/docs/forms) with a multi-select picker. - -Give the field a name, and within the settings set the *Options Source* to point at the data provider. Set the label and value columns to 'Label' and 'Cost' respectively. - -![](https://files.readme.io/ed50b934b37d48b31f194930d9b75fb64727fa5d5161f15a4239f355c0c3b682-image.png) - -
- -Finally, add a [Paragraph](https://docs.budibase.com/docs/paragraph) element nested within your form. Assign the following binding text: `Total Cost: ${{ sum New Form.Fields.Item }}` - -#### Result +To calculate the sum of selected items: -![](https://files.readme.io/0666529ff6641fbfd4ff21611e2c1d5acc8f5bf6f1b4a1897efde62ee2ee93ee-Screen_Recording_2024-09-25_at_11.53.33.gif) +1. Create an `Items` table with `Name` and `Cost` fields. +2. Add a formula column called `Label` with `{{ Name }} [ ${{ Cost }} ]`. +3. Add a data provider for the `Items` table and nest a form with a multi-select picker. +4. Set the picker `Options Source` to the data provider. +5. Set the label column to `Label` and the value column to `Cost`. +6. Add a paragraph with `Total Cost: ${{ sum New Form.Fields.Item }}`. From 877422bea509ed153819c39b767de7102e12b490 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Thu, 9 Jul 2026 12:32:37 +0100 Subject: [PATCH 09/32] ninth batched update --- docs/Apps/components/accordion.md | 11 -- docs/Apps/components/tag.md | 176 +++--------------- .../user-management/scim-provisioning.md | 6 +- 3 files changed, 26 insertions(+), 167 deletions(-) diff --git a/docs/Apps/components/accordion.md b/docs/Apps/components/accordion.md index 7d4c7c18e..0e434adf9 100644 --- a/docs/Apps/components/accordion.md +++ b/docs/Apps/components/accordion.md @@ -66,14 +66,3 @@ Example tree: All nested child components remain in the tree at all times, but their visibility in the app is controlled by whether the Accordion is expanded or collapsed. - -### Result - -{` - -`} diff --git a/docs/Apps/components/tag.md b/docs/Apps/components/tag.md index ffd1488bd..f9b4a876e 100644 --- a/docs/Apps/components/tag.md +++ b/docs/Apps/components/tag.md @@ -10,7 +10,9 @@ metadata: next: description: '' --- -The `Tag` component can quickly display tags on, for example, a detail page. An optional delete button can be added, which can be configured using [Actions](doc:actions). +The `Tag` component can quickly display tags on a detail page or in other compact layouts. Use it for statuses, labels, categories, or related records. + +You can bind the tag text to row data, change its color, and optionally add a delete button configured with [Actions](doc:actions). ## Customising the tag @@ -24,163 +26,35 @@ To customise the tag, you have several settings in the Settings Panel< | Allow delete | Adds an `X` delete control to the tag. | | On click delete | This setting appears when `Allow delete` is checked. Use it to configure what happens when the user clicks the `X`, using [Actions](doc:actions). | -
- -## Tutorial: Movie genre tags - -In this tutorial we will look at how you can use the tag component to display movie genres. - -### Setup - -To get started, add an internal [Budibase DB](doc:budibasedb) table called *Movies*, with 'Title', 'Year', and 'Image Url' columns. Add some rows. - - -Next go to the *Design* section, and add a [Cards block](https://docs.budibase.com/docs/blocks#cards-block). Select the *Movies* table as the Datasource, and bind the *Title*, *Subtitle* and *Image URL* values to the table columns. For example, the *Subtitle*: `{{ New Cards block.Movies.Year }}` - -Your screen should now show cards populated from your `Movies` data. - - -### Adding the tags - -Go back to the *Data* section, and add another table called *Tags*. Give it a text column called 'Name' and a Many->Many [Relationship](doc:relationships) column linking to *Movies*. - - -Add some tag rows, linking them to some movies. - - -Head back over to the *Design* section. To be able to add our tags, we must [Eject](https://docs.budibase.com/docs/blocks#ejecting-blocks) the cards block. - - -Next add a [Container](doc:container) nested under the *Repeater*. Set the *Gap* to 'None'. Drag the *Spectrumcard* into the new container. - -Below the *Spectrumcard* insert a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block). Give it the name 'Tags Repeater Block', and select the *Tags* table from the relationship. - - -Finally add the Tag component underneath the *Tags Repeater Block*. Click *Align right* on the repeaters block to align the tags to the right-hand side of the card, and choose *Row layout*. - -Give the tag the text binding: `{{ Tags Repeater block.Tags.Name }}`. This can be selected from the bindings dropdown. - - -As a finishing touch, it would be nice to give the different tags a color. To do so, we will use [Conditional UI](doc:conditions). Click on `Configure conditions`: Update Setting 'Color' TO ... IF `{{ Tags Repeater block.Tags.Name }}` Equals ... - -The duplicate condition button will be very useful in this case! - - -#### Result - -At this stage, each movie card should display its related tags directly beneath the movie details. - -For example: -- **The Shawshank Redemption (1994)** with tags like `Drama`, `Crime` -- **Pulp Fiction (1994)** with tags like `Action` -- **The Godfather (1972)** with tags like `Crime`, `Action` -- **Inception (2010)** with tags like `Sci-Fi`, `Drama` - -This confirms the relationship binding is working and that tags are being rendered per movie row in the repeater. +## Common usage -To see how tags can be used in a SQL database, have a look at this [MS SQL Server tutorial](https://docs.budibase.com/docs/ms-sql-server). +Tags work best when the value is short and repeatable. -### Removing tags +Common examples include: -You may optionally also want the ability to remove tags. To do so, first check the `Allow delete` setting. This will allow you to specify some actions. +* Record statuses +* Category labels +* Related items in a repeater +* Filter chips in compact views -Quick flow: -1. Enable `Allow delete` on the Tag component. -2. Configure an action under `On click delete`. -3. When users click the `X`, your configured action runs and the tag is removed according to that logic. - -Add a **Save Row** action for the `On click delete` setting with the *Movies* Repeater as the datasource (not the tags repeater block), and select the *Movies* table as the save destination. - -Check *Do not display default notification* so that a toast is not displayed. Also `Add column` for the *Tags* relationship and give it the following [JavaScript](doc:javascript) binding: - -```javascript -return $("Repeater.Movies.Tags")?.filter(tag => tag._id !== $("Tags Repeater block.Tags._id")); -``` - -The JavaScript binding may appear a little daunting to some, but to explain in pseudo-code: - -> Save all of the movie tags excluding the one we are removing - -After removing all tags, you will see a *No rows found* message, which isn't what we'd like in this case. - - -Ideally this should just be blank. Click on the *Tags Repeater block* and `Configure conditions`: Hide component IF `{{ Repeater.Movies.Tags }}` Is empty. - -As a finishing touch, it would be nice to add some margin when there are no tags so that the vertical spacing is consistent. Click on the *Spectrumcard* and `Configure conditions`: Update Setting 'Custom CSS' TO `margin-bottom: 32px;` IF `{{ Repeater.Movies.Tags }}` Is empty. - -#### Naive result - - -As you probably noticed, there is substantial delay between clicking the 'x' and the tag being removed. Ideally in this scenario we don't want to await for a database response. We can use [App state](doc:app-state) to cache the tags and improve the tag deletion UX. - -Add a second action for updating app state: - -In the Actions drawer: -1. Click `Add Action`. -2. Choose `Update State`. -3. Set `Type` to `Set value`. -4. Set `Key` to `RemovedTags`. -5. Set `Value` to a JavaScript function (shown below). -6. Leave `Persist this value` unchecked unless you explicitly want removed-tag state to survive page reloads/browser restarts. -7. Click `Save`. - - -```javascript -return { - ...$("State.RemovedTags"), - [$("Tags Repeater block.Tags._id")+$("Repeater.Movies._id")]: true -} -``` - -Next we want to replace the **Save Row** action with a **Trigger Automation** action instead. Follow the below steps to do this. - -Create the automation -1. Switch to the automation section -2. Create a new on demand automation -3. Add the relevant fields - - tags - - movie_id - -In the Actions drawer: -1. Keep your first action as `Update State` -2. Add a second action: `Trigger Automation` -3. Under `Automation`, choose previously created on demand trigger automation, and keep `Do not display default notification` checked -4. Leave `Require confirmation` unchecked unless you want a user confirmation prompt -5. Add fields: - - `tags` -> `Value`: JavaScript function (shown below) - - `movie_id` -> `Value`: `{{ Repeater.Movies._id }}` -6. Click `Save` - -`Add Field` for the *tags*, and *movie\_id*. - -The JavaScript binding for the *tags* field looks as follows: - -```javascript tags -return $("Repeater.Movies.Tags")?.filter(tag => !$("State.RemovedTags")?.[tag._id+$("Repeater.Movies._id")]); -``` - -Here we are only looking to save tags for each movie that have not been flagged as removed in our front-end cache. - -Instead of waiting for a save row response, we will fire and forget a request to our [Automation](doc:contextual-bindings) which will remove the chosen tag from our chosen movie. - -After saving those actions, navigate to the *Automate* section and select the **DeleteTag** automation that was automatically created for us. - -Make sure *tags* is set to type **Array**. - - -Next add an **Update Row** step for the *Movies* table as follows, making sure the `Use bindings` options is selected! +## Tutorial: Movie genre tags -In addition, check the `Clear relationships if empty?` flag to ensure that all tags can be removed. +Use the Tag component to show related labels in a compact layout, such as tags on a card or detail view. +To build the example: -> 👍 -> -> Publish your app to activate the automation. +1. Create `Movies` and `Tags` tables. +2. Add a many-to-many relationship from `Tags` to `Movies`. +3. Build a cards view for `Movies`. +4. Eject the cards block and add a repeater for the related tags. +5. Add the Tag component inside the repeater and bind it to `{{ Tags Repeater block.Tags.Name }}`. +6. Use [Conditional UI](doc:conditions) to assign a color per tag name. -Navigating back to the *Design* section, add another condition to the tag: Hide component IF +To remove tags: -```javascript -return $("State.RemovedTags")?.[$("Tags Repeater block.Tags._id")+$("Repeater.Movies._id")]; -``` +1. Enable `Allow delete`. +2. Add a `Save Row` action on `On click delete`. +3. Update the `Tags` relationship so the selected tag is removed. +4. Hide the tag when the relationship is empty. -Equals Boolean True. +If you need faster removal feedback, cache the removed tag in [App state](doc:app-state) before syncing the database update. diff --git a/docs/Settings/user-management/scim-provisioning.md b/docs/Settings/user-management/scim-provisioning.md index e58038b8d..644c5d15f 100644 --- a/docs/Settings/user-management/scim-provisioning.md +++ b/docs/Settings/user-management/scim-provisioning.md @@ -108,10 +108,6 @@ Furthermore, make sure you have given your users and groups [Application access] Giving Carol basic app access -{` -
-`}
- ## Managing SCIM ### Initial SCIM Sync Activation @@ -152,4 +148,4 @@ Furthermore, make sure you have given your users and groups [Application access] * Read-Only Fields: Group name (managed via SCIM). * Editable Fields: Icons and other non-synced fields can be edited in Budibase. * Non-SCIM Groups: - * Groups created manually or not matched with SCIM are fully managed in Budibase. \ No newline at end of file + * Groups created manually or not matched with SCIM are fully managed in Budibase. From ededfb4afd04da25bed76b7a8655855e3d6bc5e4 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Thu, 9 Jul 2026 12:47:55 +0100 Subject: [PATCH 10/32] tenth batched update --- docs/Bindings/bindings.md | 6 --- docs/Data/budibasedb/attachments.md | 66 +++++++++------------------ docs/Data/budibasedb/relationships.md | 29 ++++-------- 3 files changed, 30 insertions(+), 71 deletions(-) diff --git a/docs/Bindings/bindings.md b/docs/Bindings/bindings.md index 0870a74ba..5b2131a85 100644 --- a/docs/Bindings/bindings.md +++ b/docs/Bindings/bindings.md @@ -37,12 +37,6 @@ For more information, the full catalogue of helpers is available -`} - ## Tips and tricks It is important to remember that Handlebars does allow quite complex statements, which can make use of comparative logic (especially with our comparison helpers). Below we've detailed a few tips which should help you get started with bindings and Handlebars syntax. diff --git a/docs/Data/budibasedb/attachments.md b/docs/Data/budibasedb/attachments.md index 3d4789eec..55293950b 100644 --- a/docs/Data/budibasedb/attachments.md +++ b/docs/Data/budibasedb/attachments.md @@ -12,47 +12,45 @@ next: --- Almost every web application needs to manage static files in some way. -These could be images, text files, audio files and more. With budibase, you can upload your static files to your budibase applications with ease. We are going to cover how to upload and display your files both inside the budibase builder and in your web applications themselves. +These can include images, text files, audio files, and more. With Budibase, you can upload static files to your apps and display them in the builder or in your published app. ### New Field Types for Attachments -We've recently introduced new field types for attachments, replacing the previous unified attachment field. Now, attachments are categorised into two distinct types: **Attachment** and **Attachment List**. Let's explore the differences: +Budibase now uses two attachment field types: **Attachment** and **Attachment List**. ## Field Types -In Budibase, static files are managed through the Attachment field type. Both attachment and attachment list fields support various static file formats, including images, CSV files, and more. +Both field types support common static file formats, including images, PDFs, CSV files, and more. ### Attachment -This field type allows the upload of a single attachment at a time. You cannot add additional attachments to this field. When looking more into the JSON data related to this field you will see that this is stored as an object were previously it was an array. +This field type allows a single attachment at a time. The stored value is an object. ### Attachment List -Here, you can include multiple attachments of different types, such as CSV files, images, Word documents, and more. +This field type allows multiple attachments of different types, such as CSV files, images, and Word documents. -To create an attachment or attachment list field type, simply add a new column to a new or existing table and select either the Attachment, or Attachment list type. While an attachment field can accommodate as many attachments as needed, please note that the maximum file upload size per file is 20MB. +To create an attachment field type, add a new column and select either `Attachment` or `Attachment List`. The maximum file upload size per file is 20 MB. ## Uploading attachments -When you create a new row in your table you will be presented with a [Dropzone component](https://docs.budibase.com/docs/attachment) for your attachment field that you can use to upload files. +When you create a new row in your table, Budibase shows a [Dropzone component](doc:attachment) for the attachment field. > 📘 > -> A **Dropzone** component is a commonly used file upload component in web applications. It allows you to drop files from your computer into the dropzone area, or to navigate your file system to find the file that you want. +> A **Dropzone** component lets users drop files into the upload area or browse for them on disk. -Your attachments will be displayed like any regular field - inside grids and tables, forms and more Budibase components. +Attachments display like other fields inside grids, tables, forms, and other components. -To see attachments in action, take a look at the following example section. We will build a small app for storing country data using Budibase attachments. - -Attachments are stored in [MinIO](https://docs.budibase.com/docs/accessing-minio). +Attachments are stored in [MinIO](doc:accessing-minio). ## Example -In this example, we will be creating a simple web application that will be used to store information about different countries around the world. +In this example, you will build a small app for storing country data. ### Creating the Countries table and columns -Let's begin by creating a table to store data for our countries. +Start by creating a table for the country data. Next, we need to create columns in our `Countries` table. Let's look at the information we need to include about each country and decide which data types are the best to use for our columns. @@ -61,59 +59,39 @@ Next, we need to create columns in our `Countries` table. Let's look at the info * **Country Flag**: This will require an image file - here is where **Attachment** types come in. * **Travel Guide**: We can store PDF travel guides for each country here. Let's use another **Attachment** type. -Watch the video below to find out how to set up your table as detailed above. - -{` - -`} +Set up the table with the attachment columns before you start adding rows. ## Creating rows and uploading data Now that we have set up our columns, we can start to add some rows to our `Countries` table. You will now notice that on row creation, you will be presented with dropzone components inside the row creation popover for both of our attachment types - `Flag` and `Travel Guides`. -Let's create a row for Spain. Follow along with the video below to find out how. +Create a row for Spain. -Here are the files used in the video below if you don't have your own: +Here are the files used in the example if you don't have your own: * [Spanish Flag Image](https://upload.wikimedia.org/wikipedia/en/thumb/9/9a/Flag_of_Spain.svg/750px-Flag_of_Spain.svg.png) * [Spanish Travel Guide](https://www.madeforspainandportugal.com/wp-content/uploads/2016/01/Spain-with-Made-for-Spain.pdf) -{` - -`} - Muy bien! 🇪🇸 ### Front-end -Navigate over to the *Design* tab in the builder. Add a screen and select `List view`. This will create an [Autogenerated screen](https://docs.budibase.com/docs/table-block#autogenerated-screen). Now we can preview our application and interact with our attachments! +Navigate to the *Design* tab and add a screen with `List view`. This creates an [Autogenerated screen](doc:screens#autogenerated-screen). -Click the preview button on the top right of the builder. You will be navigated to your app in your default browser. Log in with the credentials that you set up when you initially created your app and you will see the homepage of your new app. Navigate to the automatically created "Countries" link in your navbar - you should see your countries listed in a table: - -![](https://files.readme.io/2aeb51f-countries.png "countries.png") +Preview the app, then open the automatically created `Countries` link in the navbar to see the rows in a table. *** ## Manage access -By default, the table **write** access will be *Basic*. This means if you have a public form, you may see an error message: `Session not authenticated` when trying to upload files. +By default, table **write** access is *Basic*. If you use a public form, you may see `Session not authenticated` when uploading files. To fix this, click on the `Manage access` button. -![](https://files.readme.io/520af17-Screenshot_2022-09-23_at_10.36.08.png) - -Set the write access to **public** +Set the write access to **public**. -![](https://files.readme.io/2cdaa92-Screenshot_2022-09-23_at_10.36.59.png) +This allows anyone to upload a file to your app instance, so use it with care. -**Note** this will allow anyone to upload a file to your app instance, so use with caution! +You must also ensure that the table with your target attachment field is selected as the [form schema](doc:forms#form-schema). Budibase needs to know the target field of the attachment upload. -You must also ensure that the table with your target attachment field is selected as the [form schema](https://docs.budibase.com/docs/forms#form-schema). Budibase needs to know the target field of the attachment upload. - -> 👍 -> -> ![](https://files.readme.io/a2430f9-Screenshot_2022-09-23_at_11.10.13.png) - -> ❗ -> -> ![](https://files.readme.io/c4b0208-Screenshot_2022-09-23_at_11.10.35.png) \ No newline at end of file +If the form schema does not match the table that owns the attachment field, Budibase will not know where to store the uploaded file. diff --git a/docs/Data/budibasedb/relationships.md b/docs/Data/budibasedb/relationships.md index 7730b745c..53aa34dbb 100644 --- a/docs/Data/budibasedb/relationships.md +++ b/docs/Data/budibasedb/relationships.md @@ -14,7 +14,7 @@ next: slug: custom-datasource title: Datasource --- -This section covers one of the more complex topics of your Budibase web app, the ability to create relationships between different rows. The relationship is bi-directional, in that when it is created, each row will have a relation to the other one. A row is also allowed to relate to many rows, meaning that many to many relationships can be created in your web app. +This section covers relationships between rows. Relationships are bi-directional, so when one is created, each row can reference the other. A row can also relate to many rows, which lets you create many-to-many relationships. ## Creating a relationship column @@ -32,46 +32,33 @@ This section covers one of the more complex topics of your Budibase web app, the ## Example -In this example, we will be creating a web app for tracking students, teachers, parking spots for teachers and classes in a school - specifically how they relate to each other. +In this example, you will build a school app that tracks students, teachers, parking spots, and classes, and how they relate to each other. -Specifically, we are going to break these down into the three relationship types that can be modelled with Budibase. Below we will map out the relationships that we are going to create, first describing them then walking through how to build them. +The example covers the three relationship types you can model with Budibase. ### One-to-many ![](https://files.readme.io/28d7cbb-one-to-many.png "one-to-many.png") -The second relationship we can model in Budibase is one of the most common, linking a single row to many other rows. Here we can see that a class can only be taught by a single teacher however a teacher is capable of teaching many different classes. +The second relationship type is one-to-many. Here, a class can only be taught by a single teacher, but a teacher can teach many classes. ### Many-to-many ![](https://files.readme.io/57e6b3d-many-to-many.png "many-to-many.png") -The last relationship we can model is arguably one of the most complexes but again very common in real-life systems. Here we can see that students are able to take many classes and each class can have many different students in it. +The last relationship type is many-to-many. Here, students can take many classes and each class can have many students. ### Building it in Budibase -To create this in Budibase all we need to do is: +To create this in Budibase: 1. Create the four tables, students, classes, teachers, and parking spots. In each of these, we will initially create a display text column and mark these as the *Display column -* for example, N*ame* or *Subject*. 2. First, we will create the teacher to parking spot relationship, starting in the teacher table we create a relationship type column, call it `ParkingSpot` and set the table to parking spots - then name the column in the other table `Teacher`. 3. Second, we create the teacher to classes relationship, hopefully, at this point, it should be clear how this is done. Simply create a relationship from the teacher table to the class table, name the column `Classes` and in the other table call the column `Teacher`. 4. Lastly, we create the students to classes relationship, the same as before but set the relationship table to classes, call the column in the students table `Classes` and call the column in the other table `Students`. -As you can see by creating three relationship columns we were able to make a fairly complex web of relationships, which can now be easily managed when creating/updating rows in any of the tables. - -### Video Demonstration - -Based on the example above here is a video showing how easy it is to create in the Budibase Builder! - -{` -
-`}
+By creating three relationship columns, you can model a fairly complex set of relationships that is easy to manage when creating or updating rows. ## Considerations -The Budibase DB in a NoSQL database. As such, there are implicit limitations when it comes to handling relational data for larger more complex applications.\ -Watch the video below for more information on deciding which database type is best to use. - -{` - -`} +Budibase DB is a NoSQL database, so it has limits for larger, more complex relational models. It is better suited to simpler relationship structures. From 5006cf50112fa7b149ba970d9c110eb6d751f376 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 07:48:14 +0100 Subject: [PATCH 11/32] eleventh batched update guides --- .../create-an-audit-table.md | 20 +++---- .../examples-and-guides/lookup-record.md | 28 ++++----- .../notify-user-if-rest-query-fails.md | 42 ++++++------- .../passing-bindings-in-url-parameters.md | 28 ++++----- .../saving-in-progress-form.md | 38 ++++++------ .../scroll-to-form-field.md | 34 +++++------ .../update-date-field-on-change.md | 60 +++++++++---------- 7 files changed, 123 insertions(+), 127 deletions(-) diff --git a/docs/Getting started/examples-and-guides/create-an-audit-table.md b/docs/Getting started/examples-and-guides/create-an-audit-table.md index b45e2cbdb..2832d17c4 100644 --- a/docs/Getting started/examples-and-guides/create-an-audit-table.md +++ b/docs/Getting started/examples-and-guides/create-an-audit-table.md @@ -19,12 +19,12 @@ next: ## Scenario -This guide shows you how to track updates made to patient records by creating an audit log. When a user edits a row in the Patients table, an automation compares the previous and updated data, identifies which fields changed, and writes those changes to the Patient audit table. +Track updates to patient records by writing each change to a separate audit table. When a user edits a row in `Patients`, an automation compares the previous and updated data, identifies the changed fields, and writes them to `Patient audit`. Use this to: -* Maintain a history of edits for compliance or review -* See which fields were changed, what the old value was, and what the new value is +* Maintain a history of edits for review or compliance +* See which fields changed, along with the old and new values {` Challenge:
@@ -70,9 +70,9 @@ Use this to: 1. A table component to view all patients with a create row button - 2. A form page were you can create new patient records - 3. A form page were you can edit existing records by clicking on a row in the table -3. Set Up Automation\ + 2. A form page where you can create new patient records + 3. A form page where you can edit existing records by clicking a row in the table +3. Set up automation\ Navigate to the Automation area and create a new automation: 1. Click the `Updated by` trigger type for your automation @@ -130,10 +130,10 @@ Use this to: - 1. Add looping - 2. Use the output value from the JavaScript step for the loop - 3. Add the looped outputs against each column - 1. | Columns | Binded values | + 1. Add looping. + 2. Use the output value from the JavaScript step for the loop. + 3. Map the looped outputs to each column: + 1. | Columns | Bound values | | :----------- | :------------------------------------ | | Column\_name | `{{ loop.currentItem.Column_name }}` | | Old\_value | `{{ loop.currentItem.Old_value }}` | diff --git a/docs/Getting started/examples-and-guides/lookup-record.md b/docs/Getting started/examples-and-guides/lookup-record.md index c6391b9e7..e423aa8bf 100644 --- a/docs/Getting started/examples-and-guides/lookup-record.md +++ b/docs/Getting started/examples-and-guides/lookup-record.md @@ -20,7 +20,7 @@ next: ## Scenario -In some [Forms](doc:forms), it is important to verify that the entered details are correct before proceeding. For example, you may want to check that an email address matches against a policy through a [REST API](doc:rest) call, or [SQL query](https://docs.budibase.com/docs/data-sources#custom-queries). +Use a lookup query when a form needs to verify entered details before the user continues. Common examples include checking an email address against a policy through a [REST API](doc:rest) call or a [SQL query](https://docs.budibase.com/docs/data-sources#custom-queries). {` Challenge:
@@ -35,10 +35,10 @@ In some [Forms](doc:forms), it is important to verify that the entered details a -2. `Add binding`: 'email' and provide a valid default value -3. Enter your lookup query, e.g. `select * from public."Employees" where "Email" = '{{email}}'` -4. Click `Run Query` and then `Save Query`. -5. Clear the default value of the binding - it is no longer needed now that we have our schema saved. Make sure to `Save Query` again. +2. `Add binding`: `email` and provide a valid default value. +3. Enter your lookup query, for example `select * from public."Employees" where "Email" = '{{email}}'`. +4. Click `Run Query`, then `Save Query`. +5. Clear the default value of the binding once the schema is saved, then save the query again. @@ -49,7 +49,7 @@ In some [Forms](doc:forms), it is important to verify that the entered details a -10. Click the button beside *On click* +10. Click the button beside *On click*. 11. `Add Action`: **Execute Query** 1. Select the *Datasource* 2. Select the *Query* @@ -64,7 +64,7 @@ In some [Forms](doc:forms), it is important to verify that the entered details a return $("Action 1.Query result")?.data?.[0]?.["EMPLOYEE ID"] ``` 13. `Add Action`: **Continue if / Stop if** - 1.
+ 1. Set the continue condition so the next actions only run when the query returns a match. @@ -72,25 +72,25 @@ In some [Forms](doc:forms), it is important to verify that the entered details a 1. Set *Type* to 'Warning' 2. Set *Message* to 'Employee not found!' 3. Check *Auto dismiss* -15. Be sure to `Save` +15. Save the action list. -16. Click on the **Screen** component (root level of the Component Tree). `Add component`: **Repeater Block** -17. In the Settings Panel, select the 'Employees' table, set *Limit* to 1, and click the button beside *Filtering* -18. `Add filter`: 'EMPLOYEE ID' *Equals Binding* `{{ State.EmployeeID }}` and `Save` +16. Click on the **Screen** component (root level of the Component Tree) and add a **Repeater Block**. +17. In the Settings Panel, select the `Employees` table, set *Limit* to `1`, and click the button beside *Filtering*. +18. `Add filter`: `EMPLOYEE ID` *Equals Binding* `{{ State.EmployeeID }}`, then save. -19. Click on the `Conditions` tab, and click `Configure conditions` +19. Click the `Conditions` tab, then click `Configure conditions`. 20. `Add condition`: 1. *Hide component* IF `{{ State.EmployeeID }}` *Is empty* 2. `Save` -21. `Add component`: **Form**, and set *Type* to 'Update', and the *Schema* to the 'Employees' table -22. `Add component`: **Field group** and click `Update form fields` +21. `Add component`: **Form**, set *Type* to `Update`, and set the *Schema* to the `Employees` table. +22. `Add component`: **Field group** and click `Update form fields`. diff --git a/docs/Getting started/examples-and-guides/notify-user-if-rest-query-fails.md b/docs/Getting started/examples-and-guides/notify-user-if-rest-query-fails.md index 05c75d7c2..0d32a624c 100644 --- a/docs/Getting started/examples-and-guides/notify-user-if-rest-query-fails.md +++ b/docs/Getting started/examples-and-guides/notify-user-if-rest-query-fails.md @@ -18,13 +18,9 @@ next: ## Scenario -Typically when executing a REST query, such as creating a new resource with a POST request, the response will come back successfully and the End User can continue with their workflow. +Use this pattern when a REST query needs to return success or failure immediately so the UI can react before the user continues. -There will however be occasions when the request is badly formed, or there is a timeout or server error. Ideally these situations should be caught, and the user should be notified so that they can either try again, or fix their request. - -To accomplish this, we will make use of [Synchronous automations 🔒](doc:synchronous-automations). - -For demonstration purposes, this guide will use a dummy query that will either return a 200 or a 404 in the response body. +The example below uses a dummy query that returns either a 200 or a 404 in the response body. {` Challenge:
@@ -35,15 +31,15 @@ For demonstration purposes, this guide will use a dummy query that will either r ## Steps -1. Go to the [Automations](doc:automation-steps) section of your app, and `Add automation` -2. In the *Create Automation* modal, enter a *Name*, and select `App Action` as the trigger. `Save`. -3. `Add field` for each binding that you will need to pass into your query - 1. In this example we will use a simple pass boolean to determine the 200 or 404 response. +1. Go to the [Automations](doc:automation-steps) section of your app and add a new automation. +2. In the create automation modal, enter a name and choose `App Action` as the trigger. +3. Add the trigger fields your query needs. + 1. In this example, a boolean is used to switch between the 200 and 404 responses. -4. Click the `+` below the trigger step, select `External Data Connector` and `Save` -5. Select your query from the *Query* dropdown, and pass in your trigger fields as the query Bindings, for example: `{{ trigger.fields.pass }}` +4. Click the `+` below the trigger step, select `External Data Connector`, and save. +5. Select your query from the *Query* dropdown and pass in the trigger fields as query Bindings, for example `{{ trigger.fields.pass }}`. @@ -51,36 +47,36 @@ For demonstration purposes, this guide will use a dummy query that will either r Our query with 'resource' binding as seen in the Data section -6. Add the final automation step: **Collect Data**, which will allow us to return the response data to the End User. -7. Under *What to collect* add the following binding: `{{ literal steps.1.response }}`. The literal keyword is used to ensure an object is returned, and not a string. +6. Add a final `Collect Data` step so the response is returned to the End User. +7. Under *What to collect*, add `{{ literal steps.1.response }}` so the response stays structured as an object. -8. With the automation setup, we can now go to the Design section, and `Add component`: **Button** +8. In the Design section, add a `Button`. 9. In the Settings Panel, click the button beside *On click* to open the actions drawer. 10. `Add Action`: **Trigger Automation** - 1. Select the *Automation* you created. You should see an info note: *This automation will run synchronously* + 1. Select the automation you created. You should see an info note that the automation will run synchronously. 2. Pass in any [On demand](doc:app-action) fields 11. `Add Action`: **Update State** - 1. *Set value* 'ResponseCode' to `{{ Action 1.Automation Result.value[0].code }}` (this binding will depend on how your API returns data) + 1. Set `ResponseCode` to `{{ Action 1.Automation Result.value[0].code }}`. The exact binding depends on how your API returns data. 12. `Add Action`: **Continue if / Stop if** - 1. *Continue if* `{{ State.ResponseCode }}` *Equals* 200 -13. Add actions that you want for the continue case, such as **Refresh Data Provider** and **Close Side Panel**. -14. Be sure to `Save` + 1. *Continue if* `{{ State.ResponseCode }}` *Equals* `200` +13. Add the actions you want for the success case, such as **Refresh Data Provider** and **Close Side Panel**. +14. Save the action list. -15. `Add component`: **Headline** for the error scenario +15. Add a `Headline` for the error state. 16. Click on the `Conditions` tab: `Configure conditions` 17. `Add Condition`: - 1. *Show component* IF `{{ State.ResponseCode }}` *Like* 4 - 2. `Save` + 1. *Show component* IF `{{ State.ResponseCode }}` *Like* `4` + 2. Save the condition. diff --git a/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md b/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md index ab90f3db5..9e884dea0 100644 --- a/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md +++ b/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md @@ -16,47 +16,47 @@ next: --- # Try it out! -In this scenario, I will be using the sample data provided in the internal Budibase DB to make a list of staff, each element in the list can be clicked to navigate to a page that displays more detailed information about that particular staff member. Follow along by building your own version, or download the app-export at the end of the page to take a closer look. +Use this pattern when a list screen needs to navigate to a detail screen for a specific row. The example below uses the sample data in Budibase DB, but you can follow along with any table that has a stable row ID. -Firstly, I'll add a `Data Provider`, and nest a `Repeater` component, and then add `Container` component inside the Repeater. +Start by adding a `Data Provider`, then nest a `Repeater` and add a `Container` inside it. ![](https://files.readme.io/c264816-image.png)
-In the Data Provider settings, I'll select the *Employees* table as the *Data* source. Now, any components I add inside the `Repeater` will have access to the bindings that reflect the *Employees* table. +In the data provider settings, select the *Employees* table as the *Data* source. Components inside the repeater will then have access to the employee bindings. -I can set this by going to `Bindings >> New Repeater` and see the column names offered as bindings. I've used a `Headline` component to show *First Name* and *Last name*, and another `Headline` component to show *Employee Level*. With a little bit of styling we can start to see this screen coming together. +Open `Bindings >> New Repeater` to see the available columns. In this example, `Headline` components show *First Name*, *Last name*, and *Employee Level*. ![](https://files.readme.io/6f1b3c9-image.png) -Next, I'll create a new screen that will become the detailed view of each employee. I'll set the URL of the screen to be `/staff/:id`. Pay close attention to the colon `:` - this is how we will denote a variable in a URL. +Next, create a detail screen for each employee and set its URL to `/staff/:id`. The colon `:` marks `id` as a URL variable. ![](https://files.readme.io/236ee22-image.png) -On my new screen, I'll add a `Data Provider` to get information from the *Employees* table, and set a filter for the `_id` from the *Employees* table to match the binding passed in the URL. +On the detail screen, add a `Data Provider` for the *Employees* table and filter `_id` to match the value passed in the URL. -If a user accidentally managed to navigate to the `/staff/:id` screen without a valid `_id` being set, the default setting of "When filter empty: return all rows" would get every row in the table, and display the bindings of the first row it found. It's much better to catch that by returning no rows. I'll also disable pagination on the `Data Provider`. +If the screen opens without a valid `_id`, set "When filter empty" to return no rows. That avoids showing the first row in the table by accident. Disable pagination as well. ![](https://files.readme.io/4da7075-image.png) -Now inside my `Data Provider` I can add components that have access to my Data Provider in the bindings. It's important here to note that the `Data Provider` fetches rows from a table, which are returned as an array of objects, where each object is one row from the table. We will only ever get one row using these filters, but it will still be returned as an array. All that is to say that when digging into the bindings we should index the result of the Data Provider rows. Using `{{ New Data Provider.Rows.0 }}` will return the entire row as an object, and we can prop-drill one level further by adding a column name. +Inside the data provider, remember that rows are returned as an array. Even when the filter returns one row, use `{{ New Data Provider.Rows.0 }}` to access the row object before reading a column value. ![](https://files.readme.io/413c875-image.png)
-I've applied some details to the page, referencing the individual row, and it's now starting to take shape. The last part of this task is the most important. Head back to the `/staff` screen, and on the `Container` component in the `Repeater component`, add an *On Click* action. Set a *Navigate To* action, and open the bindings drawer. In this example the destination will be `/staff/{{ New Repeater.Employees._id }} `, which puts the clicked container's `_id` into the URL, and passes it through to the `/staff/:id` screen. +Add the remaining detail components to the page, then return to the `/staff` screen. On the repeater container, add an *On Click* action with a *Navigate To* step. Set the destination to `/staff/{{ New Repeater.Employees._id }}` so the clicked row ID is passed through to the detail screen. Click the lightning bolt to open the Bindings Drawer... Click the lightning bolt to open the Bindings Drawer... -Now, navigating from `/staff` will actually substitute `:id` for a row id, which the `Data Provider` uses to filter the table and present the information. +When the user navigates from `/staff`, Budibase substitutes `:id` with the row ID and uses it to filter the detail screen. ## A few things to consider... -Think carefully about what you pass into the URL. In this example we passed `_id`. We could have used something more human-readable like email, but that would mean people could manipulate the URL to include an email that they shouldn't have access to, or a sequential number like EMPLOYEE ID. Imagine the URL had been `/staff/:email`, and On Click we navigate to `/staff/{{ New Data Provider.Employees.Email }}` but we only listed staff who were not managers, it would be easy to circumnavigate that by just editing the URL in the browser to an email address of a manager. +Use a stable identifier such as `_id` rather than a human-readable value like email. Human-readable values are easier for users to guess or edit in the browser. ![](https://files.readme.io/ed82c1e-image.png) @@ -64,15 +64,15 @@ Think carefully about what you pass into the URL. In this example we passed `_i
-You might want to remove the path to `/staff/:id` from the navigation bar, otherwise people will be able to visit the page without setting an `_id` +Remove `/staff/:id` from the navigation bar if you do not want users opening the page without a selected row. ![](https://files.readme.io/7fec6d5-image.png) -When working in the builder on the `/staff/:id` screen, no `_id` will have been set or passed, so it can be tricky to know that your variables have been set properly. In this instance, in your `Data Provider`, temporarily set "When filter empty" to "return all table rows", so that you get some values to work with. Make sure to return it to "return no rows" when you're finished. +When working in the builder on `/staff/:id`, no `_id` is set yet. Temporarily change the empty-filter behavior to return all rows while you test, then switch it back to return no rows. ![](https://files.readme.io/00d60ff-image.png) -Try it for yourself, and click below to download the app used to create this guide. +Try it yourself, then use the download below to inspect the example app. {` diff --git a/docs/Getting started/examples-and-guides/saving-in-progress-form.md b/docs/Getting started/examples-and-guides/saving-in-progress-form.md index ef9cb5f74..093e1bce9 100644 --- a/docs/Getting started/examples-and-guides/saving-in-progress-form.md +++ b/docs/Getting started/examples-and-guides/saving-in-progress-form.md @@ -22,11 +22,11 @@ next: ## Scenario -This guide will assume you have a *Create* [Form](doc:forms) with a number of fields added across multiple [Form steps](doc:form-steps), with *back* and *next* buttons configured to navigate between the steps. +Assume you already have a *Create* [Form](doc:forms) with fields spread across multiple [Form steps](doc:form-steps), plus *back* and *next* buttons for navigation. -If End Users close the page, and come back at a later point, you want them to be be able to pick up were they left off. Any field entries should be saved, as well as the active form step. +If End Users close the page and return later, they should resume where they left off. Save both the field values and the active step. -This recipe will make use of the [Spectrum meter](https://docs.budibase.com/docs/form-steps#spectrum-meter) to act as a step counter, as well as [App state](doc:app-state) to cache the form progress. +This recipe uses the [Spectrum meter](https://docs.budibase.com/docs/form-steps#spectrum-meter) as a step counter and [App state](doc:app-state) to cache progress. {` Challenge:
@@ -37,46 +37,46 @@ This recipe will make use of the [Spectrum meter](https://docs.budibase.com/docs ## Steps -1. For each of your **Back Buttons**, click on the *On click* button in the Settings Panel. `Add Action`: **Update State** - 1. Set value 'FormStep' `{{ subtract New Employee Form.Current Step 1 }}` +1. For each **Back Button**, click the *On click* button in the Settings Panel and add an **Update State** action. + 1. Set `FormStep` to `{{ subtract New Employee Form.Current Step 1 }}` 2. Tick *Persist this value* -2. Add another **Update State** action - 1. Set value 'FormValueStep1' `{{ literal New Employee Form.Value }}` +2. Add another **Update State** action. + 1. Set `FormValueStep1` to `{{ literal New Employee Form.Value }}` 2. Tick *Persist this value* - 3. Click `Save` + 3. Click `Save`. > 📘 FormValue state > - > Each form step will need its own *FormValue* state, so form step two should be called 'FormValueStep2', etc. + > Each form step needs its own *FormValue* state, so step two should be called `FormValueStep2`, and so on. > - > Also note the use of the **literal** helper. This tells Budibase that the form value should be treated as an object, and not a string. When using JavaScript bindings, original types are kept. + > The **literal** helper keeps the form value as an object rather than converting it to a string. -3. Do the same for each of your **Next Buttons**, but the 'FormStep' binding in that case would be: `{{ add New Employee Form.Current Step 1 }}` +3. Repeat the same setup for each **Next Button**, but set `FormStep` to `{{ add New Employee Form.Current Step 1 }}`. > 📘 When to save form progress > > This approach will save the form value upon form step navigation, however you could do this [On Change](https://docs.budibase.com/docs/text-inputs#on-change) for more frequent saving, making sure to use the `{{ Field Value }}` binding. -4. When the form is submitted, you will need to clear the in-progress state. Select your **Submit Button**, and click the actions button in the Settings Panel. `Add Action`: **Update State** - 1. Set value 'FormStep' to 1 +4. When the form is submitted, clear the in-progress state. Select your **Submit Button** and add an **Update State** action. + 1. Set `FormStep` to `1` 2. Tick *Persist this value* -5. Add another **Update State** action for the number of form steps - 1. Set value 'FormValueStep1' to *blank* +5. Add another **Update State** action for the saved form values. + 1. Set `FormValueStep1` to *blank* 2. Tick *Persist this value* - 3. Click `Save` + 3. Click `Save`. -6. Click on the **Form** component, and in the Settings Panel set *Initial form step* to `{{ State.FormStep }}` +6. Click the **Form** component and set *Initial form step* to `{{ State.FormStep }}`. -7. For each of your form fields, set the Default Value to `{{ State.FormValueStep1.[Field Name] }}`. - 1. Note that the state binding will depend on the active step +7. For each form field, set the Default Value to `{{ State.FormValueStep1.[Field Name] }}`. + 1. The state binding depends on the active step. diff --git a/docs/Getting started/examples-and-guides/scroll-to-form-field.md b/docs/Getting started/examples-and-guides/scroll-to-form-field.md index fd008f84d..a88c1506b 100644 --- a/docs/Getting started/examples-and-guides/scroll-to-form-field.md +++ b/docs/Getting started/examples-and-guides/scroll-to-form-field.md @@ -1,5 +1,5 @@ --- -title: Scroll to top of screen +title: Scroll to form field excerpt: '' deprecated: false hidden: false @@ -18,7 +18,7 @@ next: ## Scenario -The Scroll To action can be useful when using [Form steps](doc:form-steps), for example when clicking a button for the next step, you want to scroll to the top of the screen. +Use `Scroll To Field` when a step change should also move the view to the next section of the form. {` Challenge:
@@ -30,46 +30,46 @@ The Scroll To action can be useful when using [Form steps](doc:form-steps), for ## Steps 1. `Add component`: **Form** -2. In the Settings Panel set *Schema* to 'Jobs' +2. In the Settings Panel set *Schema* to `Jobs`. 3. `Add component`: **Form Step** 4. `Add component`: **Headline**. Set *Text* to 'Job' 5. `Add component`: **Field Group** -6. In the Settings Panel click on `Update form fields`: `Update` +6. In the Settings Panel click on `Update form fields`: `Update`. -7. Click on the **Form** and set *Schema* to 'Expenses' +7. Click on the **Form** and set *Schema* to `Expenses`. 8. [Duplicate](https://docs.budibase.com/docs/components#editing) the **Form Step** -9. In the Settings Panel set *Step* to 2 +9. In the Settings Panel set *Step* to `2`. -10. Change the **Headline** *Text* to 'Expenses' +10. Change the **Headline** *Text* to `Expenses`. -11. Click on the **Field Group**: `Update form fields`: `Update` +11. Click on the **Field Group**: `Update form fields`: `Update`. -12. `Add component`: **Button** and set *Text* to 'Back' +12. `Add component`: **Button** and set *Text* to `Back`. -13. Set the *On click*: `actions` +13. Set the *On click* actions. -14. `Add Action`: **Change Form Step** - Select the *Form* and set *Step* to 'First step' +14. `Add Action`: **Change Form Step** - select the *Form* and set *Step* to `First step`. -15. `Add Action`: **Scroll To Field** - Select the *Form* and set *Field* to 'Quote Date' +15. `Add Action`: **Scroll To Field** - select the *Form* and set *Field* to `Quote Date`. 16. `Save` -17. [Copy](https://docs.budibase.com/docs/components#editing) the **Button** -18. Click on the **Field Group** in **Form Step 1**. Paste the **Button** -19. In the Settings Panel set *Text* to 'Next' +17. [Copy](https://docs.budibase.com/docs/components#editing) the **Button**. +18. Click on the **Field Group** in **Form Step 1** and paste the **Button**. +19. In the Settings Panel set *Text* to `Next`. 20. Under *On click*: `Define actions` 1. **Change Form Step** - Change *Step* to 'Next step' - 2. **Scroll To Field** - Change *Field* to 'Expense Tags - 3. `Save` + 2. **Scroll To Field** - Change *Field* to `Expense Tags`. + 3. Save the actions. diff --git a/docs/Getting started/examples-and-guides/update-date-field-on-change.md b/docs/Getting started/examples-and-guides/update-date-field-on-change.md index c4b992ce4..6418db61b 100644 --- a/docs/Getting started/examples-and-guides/update-date-field-on-change.md +++ b/docs/Getting started/examples-and-guides/update-date-field-on-change.md @@ -18,7 +18,7 @@ next: ## Scenario -You're building an app and you want to set a project length in days, and then dynamically calculate start and end dates. +Use this pattern when a duration field should update related start and end dates automatically. {` Challenge:
@@ -30,32 +30,32 @@ You're building an app and you want to set a project length in days, and then dy ## Steps 1. `Add component`: **Form** -2. In the Settings Panel set *Schema* to 'Jobs' +2. In the Settings Panel, set *Schema* to `Jobs`. 3. `Add component`: **Container** -4. In the Settings Panel set the layout to flex - 1. Set *Direction* to 'Row' +4. In the Settings Panel, set the layout to flex. + 1. Set *Direction* to `Row`. 5. `Add component`: **Number Field** -6. Manually enter 'Direction' into the *Field* name and set *Label* to 'Days of work' -7. Set *Default value* to 7 +6. Enter `Duration` as the *Field* name and set *Label* to `Days of work`. +7. Set *Default value* to `7`. 8. `Configure validation`: - 1. `Add Rule`: Min value 'Value' 1 *Cannot be less than one day!* - 2. `Add Rule`: Max value 'Value' 365 *Cannot be more than 365 days!* - 3. `Save` + 1. `Add Rule`: Min value `1` with the message `Cannot be less than one day!` + 2. `Add Rule`: Max value `365` with the message `Cannot be more than 365 days!` + 3. Save the validation. 9. `Add component`: **Date Picker** -10. In the Settings Panel select 'Works Start' from the *Field* dropdown -11. Set *Label* to 'Works Start' -12. Untick *Show time* +10. In the Settings Panel, select `Works Start` from the *Field* dropdown. +11. Set *Label* to `Works Start`. +12. Untick *Show time*. 13. [Duplicate](https://docs.budibase.com/docs/components#editing) the **Date Picker** -14. Replace 'Start' with 'End' in the *Field* and *Label* settings +14. Replace `Start` with `End` in the *Field* and *Label* settings. > 👍 > @@ -66,10 +66,10 @@ You're building an app and you want to set a project length in days, and then dy 1. **Validate Form** - make sure to select the form in the dropdown 2. **Update Field Value** - 1. select the *Form* from the dropdown - 2. select 'Set value' as the *Type* - 3. select 'Works Start' as the *Field* - 4. click the lightning bolt icon, and click on the `JavaScript` tab. Provide the following: + 1. Select the *Form* from the dropdown. + 2. Select `Set value` as the *Type*. + 3. Select `Works Start` as the *Field*. + 4. Click the lightning bolt icon, then open the `JavaScript` tab and use the following: ```javascript JavaScript //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date @@ -84,18 +84,18 @@ You're building an app and you want to set a project length in days, and then dy > 📘 > -> The **Validate Form** action will prevent the **Update Field Value** from firing if there's any validation errors. +> The **Validate Form** action prevents the update from running if validation fails. > -> The special `$("Field Value")` binding is used to indicate that the [On change](https://docs.budibase.com/docs/text-inputs#on-change) value should be used, and not the value before the change. +> `$("Field Value")` uses the changed value rather than the previous value. > -> Also note that you may need to replace the `$("Jobs Form.Fields.Duration")` binding to match your form name. +> Update `$("Jobs Form.Fields.Duration")` to match your form name if needed. -16. Select the **Works Start Date Picker**. Under *On change*: `Define actions` +16. Select the **Works Start** date picker. Under *On change*: `Define actions` 1. **Validate Form** - make sure to select the form in the dropdown - 2. **Update Field Value** - similar to before, but this time we are setting the value of the 'Works End' field, and will add days instead of subtracting: + 2. **Update Field Value** - set the value of the `Works End` field and add days instead of subtracting: ```javascript //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date @@ -107,16 +107,16 @@ You're building an app and you want to set a project length in days, and then dy return new Date($("Field Value")).addDays($("Jobs Form.Fields.Duration")); ``` -17. Finally click on the **Number Field**. Under *On change*: `Define actions` +17. Finally, click the **Number Field**. Under *On change*: `Define actions` 1. **Validate Form** - make sure to select the form in the dropdown - 2. **Continue if / Stop if** - 'Stop if' `{{ Jobs Form.Fields.Works Start }}` 'Equals' "" + 2. **Continue if / Stop if** - set `Stop if` to `{{ Jobs Form.Fields.Works Start }}` `Equals` `""` 3. **Update Field Value**: - 1. select the *Form* from the dropdown - 2. select 'Set value' as the *Type* - 3. select 'Works End' as the *Field* - 4. click the lightning bolt icon, and click on the `JavaScript` tab. Provide the following: + 1. Select the *Form* from the dropdown. + 2. Select `Set value` as the *Type*. + 3. Select `Works End` as the *Field*. + 4. Click the lightning bolt icon, then open the `JavaScript` tab and use the following: ```javascript //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date @@ -131,9 +131,9 @@ You're building an app and you want to set a project length in days, and then dy > 📘 > -> In this case we first check that the number of days is a valid number. +> This action checks that the number of days is valid. > -> Next we use the [Stop if](https://docs.budibase.com/docs/chaining-actions#continue-if--stop-if) action to make sure a 'Works Start' date has been chosen, because we need to know the start date in order to calculate the end date. +> The [Stop if](https://docs.budibase.com/docs/chaining-actions#continue-if--stop-if) action prevents the update until a `Works Start` date has been chosen.
From d12e9a8f615353a846fc5e5c2b075e800f33be74 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 09:40:53 +0100 Subject: [PATCH 12/32] twelfth batched update --- .../calculate-field-value-on-save.md | 44 +++++++++---------- .../cascading-dropdown-filters.md | 40 ++++++++--------- .../filter-table-block-with-options-picker.md | 30 ++++++------- .../populate-form-fields-on-select.md | 30 ++++++------- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md b/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md index 2347c57fb..e888a9f02 100644 --- a/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md +++ b/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md @@ -18,9 +18,9 @@ next: ## Scenario -[Forms](doc:forms) will often have [number fields](https://docs.budibase.com/docs/text-inputs#number-field) for inputting measurements, which could be in different units such as ounces and kilograms, centimetres and inches, or even different currencies. +[Forms](doc:forms) often include [number fields](https://docs.budibase.com/docs/text-inputs#number-field) for measurements that may be entered in different units, such as ounces and kilograms, centimetres and inches, or even different currencies. -This guide will demonstrate how to allow an End User \<\End User
choose a unit of measurement, convert the value automatically, and still save everything in meters. {` Challenge:
@@ -31,36 +31,36 @@ This guide will demonstrate how to allow an End User \<\ - Add two columns to your events table - a text column called "event" and a number column called "distance" + Add two columns to your table: a text column called `event` and a number column called `distance`. -3. Go to the app screen, create a new app called Calculate field value on save -4. Create a new blank screen (if you haven't already), and add a Form component (not to be confused with a Form Block). Set type to "create" and the schema to your events table. +3. Create a new app called `Calculate field value on save`. +4. Create a new blank screen and add a `Form` component. Set the type to `Create` and the schema to your `Distance` table. -5. Add a **Field Group** component, and click "Update form fields" - this will fetch the columns from your table and create an input field for each. Set the "Type" option to 3 Columns. +5. Add a **Field Group** component and click `Update form fields` to generate inputs for the table columns. Set the `Type` option to `3 Columns`. -6. Add an Options Picker as a child of your form, and set the field and label to "unit". Set the Options Source to custom, and click "define options. +6. Add an `Options Picker` as a child of the form and set the field and label to `unit`. Set the Options Source to `Custom` and click `Define options`. - Add 3 options: + Add three options: | Units | Value | | :----- | :---- | | Meters | 1 | | Yards | 0.914 | | Feet | 0.30 | -7. Be sure to set the default value to 1, and uncheck "Alphabetical" -8. Add an "On change" action to the options picker using the "Update Field Value" action\ - i. Select the *Form*\ - ii. Set *Type* to 'Set value'\ - iii. Select the *Distance* form field\ - iv. Click the lightning bolt and select the *JavaScript* tab. Add the following: +7. Set the default value to `1` and uncheck `Alphabetical`. +8. Add an `On change` action to the options picker using `Update Field Value`. + 1. Select the *Form*. + 2. Set *Type* to `Set value`. + 3. Select the *Distance* form field. + 4. Click the lightning bolt and open the `JavaScript` tab, then add the following: ```javascript JavaScript const previousUnit = $("New Form.Fields.units"); @@ -78,29 +78,29 @@ This guide will demonstrate how to allow an End User \<\ > `$("Field Value")` is the new value that will update the field when the *on change* finishes. -8. Add a "required" Validation setting to the options picker - the default error message is simply "Error", so be sure to add something useful like "Please specify units" to help the user understand the issue. +9. Add a required validation setting to the options picker. The default error message is just `Error`, so replace it with something clearer such as `Please specify units`. -9. As a child-component of your form, and a sibling of your field group, add a new button. Update the button text to "Save", and add an Icon "save-3-fill". +10. Add a button as a sibling of the field group. Set the button text to `Save` and add the `save-3-fill` icon. -10. Add an On Click action "Save Row" to save the information from your form into your table - (If you don't specify any columns, all fields will be saved by default). In our case we want to select the 'Distance column' and provide the following binding: `{{ multiply New Form.Fields.Distance Form.Fields.units }}` in order to save all distances in meters. +11. Add an `On Click` action, `Save Row`, to save the form data to the table. If you do not specify columns, Budibase saves every field by default. In this case, select the `Distance` column and use `{{ multiply New Form.Fields.Distance Form.Fields.units }}` so all values are saved in meters. ![](https://files.readme.io/88a94978f705527876863326f28c6b196c8d4ed08d3186e9110ff8906ccaec3d-image.png)
-11. Add another On Click action to validate your form +12. Add another `On Click` action to validate the form. ![](https://files.readme.io/653e918e5fd0fa53a32968c1dd5a92bca25eaf7a98112c5387f481d73da7403a-image.png) -12. It's also good practice to clear a form after submitting. Add another action "Clear Form" and chose your form to be reset. +13. Clear the form after submitting by adding a `Clear Form` action and choosing the form to reset. ![](https://files.readme.io/4a17d674a17f59f6bd25c6841e08506e186c0ed92bf3d24078c4b07969a032d0-image.png) -13. Add a table at the base-level of the component tree, as a sibling of your form component, and set it to fetch data from the events table. Initially it will be empty, but you can now publish your app and add new events using Meters, Feet or Inches. +14. Add a table at the base level of the component tree, as a sibling of the form, and set it to fetch data from the `Distance` table. Initially it will be empty, but you can now publish the app and add new records using meters, feet, or yards. @@ -137,4 +137,4 @@ This guide will demonstrate how to allow an End User \<\ -`}
\ No newline at end of file +`} diff --git a/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md b/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md index 04c3e8dab..28213515d 100644 --- a/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md +++ b/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md @@ -18,9 +18,9 @@ next: ## Scenario -You have a **Country** table and a **City** table, with a relationship defined between them as *One Country -> Many Cities*. +Use this pattern when one picker should control the available values in another. In this example, a **Country** table and a **City** table are linked as *One Country -> Many Cities*. -Your form will have an [Options picker](doc:option-picker) that will allow the end-user to select a country, which will then populate a second [Relationship picker](https://docs.budibase.com/docs/pickers#relationship-picker) with the cities that relate to the chosen country. +The form uses an [Options picker](doc:option-picker) to select a country, then populates a second [Relationship picker](https://docs.budibase.com/docs/pickers#relationship-picker) with the matching cities. {` Challenge:
@@ -32,36 +32,36 @@ Your form will have an [Options picker](doc:option-picker) that will allow the e ## Steps 1. `Add component`: **Form** -2. In the Settings Panel, set *Schema* to 'Country' +2. In the Settings Panel, set *Schema* to `Country`. 3. `Add component`: **Data provider** -4. In the Settings Panel, set *Data* to the 'Country' table -5. Set the *Limit* to 200, and untick *Paginate* +4. In the Settings Panel, set *Data* to the `Country` table. +5. Set the *Limit* to `200` and untick *Paginate*. 6. `Add component`: **Options Picker** -7. In the Settings Panel, enter 'Country' for the *Field*, and add a *Label* -8. Tick *Autocomplete* -9. Set *Options source* to 'Data provider' -10. Set *Label column* to 'country' and set *Value column* to 'country\_id' +7. In the Settings Panel, enter `Country` for the *Field* and add a *Label*. +8. Tick *Autocomplete*. +9. Set *Options source* to `Data provider`. +10. Set *Label column* to `country` and *Value column* to `country_id`. -11. `Add component`: **Relationship Picker** and select the 'Cities' from the *Field* dropdown +11. `Add component`: **Relationship Picker** and select `Cities` from the *Field* dropdown. 12. Click the button beside *Filtering* 13. `Add filter`: - 1. 'country\_id' Equals Binding `{{ Country Form.Fields.Country }}` - 2. Be sure to `Save` + 1. `country_id` Equals Binding `{{ Country Form.Fields.Country }}` + 2. Save the filter. 14. Click on the `Conditions` tab and click `Configure conditions` 15. `Add condition`: - 1. 'Update Setting Disabled' TO \[✓] IF `{{ Country Form.Fields.Country }}` 'Is empty' - 2. Be sure to `Save` + 1. `Update Setting Disabled` to `✓` if `{{ Country Form.Fields.Country }}` `Is empty`. + 2. Save the condition. @@ -71,12 +71,12 @@ Your form will have an [Options picker](doc:option-picker) that will allow the e > > More on field layout in this recipe: [Display multiple fields in one row](doc:display-mutiple-fields-in-one-row) -16. Finally we want to clear the selected cities when the country changes. Click on the **Country Options Picker**, and click the button beside the *On change* setting +16. Clear the selected cities when the country changes. Click the **Country Options Picker** and then the button beside *On change*. 17. Add the **Update Field Value** action: - 1. Select the *Form* - 2. Set *Type* to 'Reset to default value' - 3. Select the 'Cities' *Field* from the dropdown - 4. Be sure to `Save` + 1. Select the *Form*. + 2. Set *Type* to `Reset to default value`. + 3. Select the `Cities` field from the dropdown. + 4. Save the action. @@ -111,4 +111,4 @@ Your form will have an [Options picker](doc:option-picker) that will allow the e background-color: #2e64c9; } -`}
\ No newline at end of file +`} diff --git a/docs/Getting started/examples-and-guides/filter-table-block-with-options-picker.md b/docs/Getting started/examples-and-guides/filter-table-block-with-options-picker.md index 9ad86a01a..70e366501 100644 --- a/docs/Getting started/examples-and-guides/filter-table-block-with-options-picker.md +++ b/docs/Getting started/examples-and-guides/filter-table-block-with-options-picker.md @@ -18,9 +18,9 @@ next: ## Scenario -The Table component allows you to use the head of each column as a search field, however there are cases were you may want to use different type of field for searching, such as an [Options picker](doc:option-picker). +The Table component can search from each column header, but some workflows need a different control, such as an [Options picker](doc:option-picker). -This guide will show you how to add search that will display results for a selected *Region* from a preset list of values, or countries matching a *Country* field. +Use this pattern to filter results by a selected *Region* from a fixed list, or by countries that match a *Country* field. {` Challenge:
@@ -32,24 +32,24 @@ This guide will show you how to add search that will display results for a selec ## Steps 1. Download the following .csv file containing the sample data for this guide [Sample Data](https://drive.google.com/file/d/1Pl8WQ14L4_7jVzD4UgHLMc032TfKlK0y/view?usp=sharing) -2. In the Data tab of your Budibase workspace, click "Create new table", and select the "Create a Table from a CSV or JSON file" to upload the sample data. You may need to reject columns that have been unsuccessfully imported, and choose a display column. +2. In the Data tab, click `Create new table` and choose `Create a Table from a CSV or JSON file` to upload the sample data. You may need to reject columns that import incorrectly and choose a display column. 1. -3. You may need to reject columns that were unsuccessfully imported, and select a Display Column. +3. If needed, reject any failed imports and select a display column. ![](https://files.readme.io/8452873586fc5d800ad6bfd9ccd0213bb9d6089213b56e7212cf5d1a73ec5e8e-image.png) -4. When the data has been successfully imported, you should see a table of sample sales data populated in the Data Tab. -5. Create a new app -6. Create a new blank screen. Add a new Table component, and set the Data option to Sales. +4. Once the data is imported, you should see the sample sales table in the Data tab. +5. Create a new app. +6. Create a new blank screen. Add a `Table` component and set the Data option to `Sales`. -7. Next, add a Form component\* and add an Options Picker as a child of the form.\ +7. Add a `Form` component and add an `Options Picker` as a child of the form.\ \*Form components are not to be confused with Form Blocks -8. In the settings of the Options Picker, you'll need to add a field value, and you should add a label - we'll set both to "Region". -9. Set the Options Source to Custom. +8. In the `Options Picker` settings, add a field value and label. Set both to `Region`. +9. Set the Options Source to `Custom`. ![](https://files.readme.io/ccceae83f7577e14b24240c57bff967d28d08b3c5cf22d9ae50a8c565ba02864-image.png) -10. Click Define options: `Add Option` for each region: +10. Click `Define options`, then add an option for each region: 1. Australia and Oceania 2. Central America and the Caribbean @@ -58,12 +58,12 @@ This guide will show you how to add search that will display results for a selec 5. Asia 6. North America 7. Europe -11. Head back to the Table settings, and add a filter. +11. Return to the table settings and add a filter. ![](https://files.readme.io/c4957e4a84ec7c8b1dd38d12aa088eca78256fae0070e923ce2aeef952f04c78-image.png) -12. Once the filter is set, you'll be able to select a region from the dropdown from within the builder, but to fully test you should click the preview button to take a closer look. +12. Once the filter is set, you can select a region from the dropdown in the builder. Use preview to test the full flow. -You may also decide that you want to filter by multiple region, for example when looking for sales in Europe and Asia - In this case, you should use a Multi-Select Picker component, and your filter should use the "Is In" operator. +To filter by multiple regions, such as Europe and Asia, use a `Multi-Select Picker` and the `Is In` operator. ![](https://files.readme.io/1938cfa4d4d6644cd7212336107828c04d4b3eece342f22c048b903691f97e99-image.png) @@ -98,4 +98,4 @@ You may also decide that you want to filter by multiple region, for example when background-color: #2e64c9; } -`}
\ No newline at end of file +`} diff --git a/docs/Getting started/examples-and-guides/populate-form-fields-on-select.md b/docs/Getting started/examples-and-guides/populate-form-fields-on-select.md index a50219f24..2cf73b303 100644 --- a/docs/Getting started/examples-and-guides/populate-form-fields-on-select.md +++ b/docs/Getting started/examples-and-guides/populate-form-fields-on-select.md @@ -18,9 +18,9 @@ next: ## Scenario -Have a [Form block](doc:form-block) that displays some fields for a table record, you want the End User to be able to select a record from an [Options picker](doc:option-picker) and update the form fields with the correct information. +Use this pattern when a [Form block](doc:form-block) should display details for a selected record. The End User chooses a row from an [Options picker](doc:option-picker), and the form fields update automatically. -[App state](doc:app-state) will be used to allow communication between our search field, and the details form. +[App state](doc:app-state) passes the selected row ID from the picker to the details form. {` Challenge:
@@ -33,33 +33,33 @@ Have a [Form block](doc:form-block) that displays some fields for a table record 1. `Add component`: **Form** 2. `Add component`: **Data Provider** -3. In the Settings Panel, select the 'Employees' table -4. Untick *Paginate* +3. In the Settings Panel, select the `Employees` table. +4. Untick *Paginate*. 5. `Add component`: **Options Picker** -6. In the Settings Panel, type in a *Field* name and *Label* -7. Check *Autocomplete* -8. Select 'Data provider' as the *Options source* -9. Select 'Email' as the *Label column* and '\_id' as the *Value column* +6. In the Settings Panel, type in a *Field* name and *Label*. +7. Check *Autocomplete*. +8. Select `Data provider` as the *Options source*. +9. Select `Email` as the *Label column* and `_id` as the *Value column*. -10. In the **Data** section, right-click the 'Employees' row you want to be the Default Value. Click `Copy row _id`. +10. In the **Data** section, right-click the `Employees` row you want to use as the Default Value, then click `Copy row _id`. -11. Back to the **Design** section, paste the row **\_id** you copied into the *Default value* setting of the **Options Picker** -12. Click the button beside *On change*. `Add Action`: **Update State** - 1. *Set value* 'SelectedEmployee' to `{{ Field Value }}` - 2. Be sure to `Save` +11. Return to the **Design** section and paste the copied row `_id` into the *Default value* setting of the **Options Picker**. +12. Click the button beside *On change* and add an **Update State** action. + 1. Set `SelectedEmployee` to `{{ Field Value }}`. + 2. Save the action. 13. Click on the **Screen** component (root level of the Component Tree). `Add component`: **Form Block** -14. In the Settings Panel, set *Type* to 'View', and *Table* to 'Employees' -15. Set *Row ID* to `{{ State.SelectedEmployee }}` +14. In the Settings Panel, set *Type* to `View` and *Table* to `Employees`. +15. Set *Row ID* to `{{ State.SelectedEmployee }}`. From ac4db6f66a0f19f6e8765ea23967387f866ee8d9 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 09:56:02 +0100 Subject: [PATCH 13/32] last batch of guides --- .../calculate-field-value-on-save.md | 10 +-- .../passing-bindings-in-url-parameters.md | 2 +- .../save-two-linked-tables-in-one-form.md | 67 +++++++++---------- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md b/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md index e888a9f02..a93a258f8 100644 --- a/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md +++ b/docs/Getting started/examples-and-guides/calculate-field-value-on-save.md @@ -20,7 +20,7 @@ next: [Forms](doc:forms) often include [number fields](https://docs.budibase.com/docs/text-inputs#number-field) for measurements that may be entered in different units, such as ounces and kilograms, centimetres and inches, or even different currencies. -This guide shows how to let an End User choose a unit of measurement, convert the value automatically, and still save everything in meters. +Use this pattern when you want the user to work in one unit but always save a standardised value in the table. {` Challenge:
@@ -72,13 +72,13 @@ This guide shows how to let an End User choose a unit of me > 📘 Previous and new values on change > -> It's worth bringing attention to the use of the options picker bindings. +> The options picker uses separate bindings for the previous value and the new value. > -> `$("New Form.Fields.UnitPicker")` will get the value of the field before the change occurs. +> `$("New Form.Fields.UnitPicker")` gets the value before the change occurs. > -> `$("Field Value")` is the new value that will update the field when the *on change* finishes. +> `$("Field Value")` is the new value that updates the field when the *on change* action finishes. -9. Add a required validation setting to the options picker. The default error message is just `Error`, so replace it with something clearer such as `Please specify units`. +9. Add a required validation setting to the options picker. Replace the default `Error` message with something clearer, such as `Please specify units`. diff --git a/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md b/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md index 9e884dea0..35d550a24 100644 --- a/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md +++ b/docs/Getting started/examples-and-guides/passing-bindings-in-url-parameters.md @@ -30,7 +30,7 @@ Open `Bindings >> New Repeater` to see the available columns. In this example, ` ![](https://files.readme.io/6f1b3c9-image.png) -Next, create a detail screen for each employee and set its URL to `/staff/:id`. The colon `:` marks `id` as a URL variable. +Create a detail screen for each employee and set its URL to `/staff/:id`. The colon `:` marks `id` as a URL variable. ![](https://files.readme.io/236ee22-image.png) diff --git a/docs/Getting started/examples-and-guides/save-two-linked-tables-in-one-form.md b/docs/Getting started/examples-and-guides/save-two-linked-tables-in-one-form.md index 12fac1318..6896d8338 100644 --- a/docs/Getting started/examples-and-guides/save-two-linked-tables-in-one-form.md +++ b/docs/Getting started/examples-and-guides/save-two-linked-tables-in-one-form.md @@ -18,7 +18,7 @@ next: ## Scenario -When creating a new job, you want the option of creating and linking a new employee to that job in the one form. For this example you should use the sample data supplied in the internal BudibaseDB tables. +Use this pattern when one form needs to create a parent row and optionally create a related child row at the same time. In this example, a new job can also create a linked employee. {` Challenge:
@@ -35,18 +35,17 @@ When creating a new job, you want the option of creating and linking a new emplo 2. In the Settings Panel, select the 'Jobs' *Table* ![](https://files.readme.io/2654464d95cf2a4178f13f3a78fb391687a9ccb1804e78026993fa53b043809d-image.png) -3. At the very bottom of the settings panel, click `Eject` - this will break down the Form Block into it's constituent parts. We can see this in the component tree. +3. At the very bottom of the settings panel, click `Eject` to break the Form Block into its constituent parts. 4. `Add component`: **Options Picker** -5. In the Settings Panel, enter 'ExistingEmployee' as the *Field*. +5. In the Settings Panel, enter `ExistingEmployee` as the *Field*. ![](https://files.readme.io/0171c19a436369c489145c20cf8fad6da0fc1137c16ae7d547c7aab0b0e236d0-image.png) -6.
-7. Set *Type* to 'Radio buttons' -8. Set *Direction* to 'Horizontal' -9. Set *Default value* to 'SELECT' -10. Uncheck *Alphabetical* -11. Set *Options source* to 'Custom' -12. `Define options`: +6. Set *Type* to 'Radio buttons' +7. Set *Direction* to 'Horizontal' +8. Set *Default value* to 'SELECT' +9. Uncheck *Alphabetical* +10. Set *Options source* to 'Custom' +11. `Define options`: 1. | Label | Value | | :----------------------- | :----- | | Select existing employee | SELECT | @@ -54,58 +53,58 @@ When creating a new job, you want the option of creating and linking a new emplo -13. In the component tree, drag the **Relationshipfield** below the **Options Picker** -14. Click on the `Conditions` tab -15. `Configure conditions`: `Add condition` +12. In the component tree, drag the **Relationship field** below the **Options Picker**. +13. Click the `Conditions` tab. +14. `Configure conditions`: `Add condition` 1. Hide component IF `{{ Form.Fields.ExistingEmployee }}` Equals Binding NEW 2. `Save` -16. `Add component`: **Container** -17. Click on the `Conditions` tab -18. `Configure conditions`: `Add condition` +15. `Add component`: **Container** +16. Click the `Conditions` tab. +17. `Configure conditions`: `Add condition` 1. Hide component IF `{{ Form.Fields.ExistingEmployee }}` Equals Binding SELECT 2. `Save` -19. `Add component`: **Headline**. Set *Text* to 'New Employee' -20. `Add component`: **Field Group** +18. `Add component`: **Headline**. Set *Text* to `New Employee`. +19. `Add component`: **Field Group** -21. Click on the **Form** and set the *Schema* to 'Employees' +20. Click on the **Form** and set the *Schema* to `Employees`. -22. Click on the newly added **Field Group** and click `Update form fields` -23. Set *Type* to `Two columns` -24. [Delete](https://docs.budibase.com/docs/components#editing) the **Jobs** field +21. Click on the newly added **Field Group** and click `Update form fields`. +22. Set *Type* to `Two columns`. +23. [Delete](https://docs.budibase.com/docs/components#editing) the **Jobs** field. -25. You may also need to replace the *Text Field* for Address with a *Long Form Field* if it displays as an error. -26. Click on the **Form** and set the *Schema* back to 'Jobs' +24. Replace the *Text Field* for Address with a *Long Form Field* if it displays as an error. +25. Click on the **Form** and set the *Schema* back to `Jobs`. ![](https://files.readme.io/b74f57abf58076446e979882cb67e8132c93db235ce8c82dedd6821da1d42b3b-image.png) -27. Click on the 'Save' **Button**, enter the settings using the cog-icon and `Define actions` -28. Click the `X` beside each actions so that only the **Validate Form** and **Save Row** actions remain -29. `Add Action`: **Navigate To** *Screen* '/jobs' -30. `Add Action`: **Continue if / Stop if** +26. Click the `Save` **Button**, open the settings using the cog icon, and choose `Define actions`. +27. Click the `X` beside each action so that only **Validate Form** and **Save Row** remain. +28. `Add Action`: **Navigate To** *Screen* `/jobs` +29. `Add Action`: **Continue if / Stop if** 1. Continue if `{{ Form.Fields.ExistingEmployee }}` Equals NEW -31. `Add Action`: **Save Row** +30. `Add Action`: **Save Row** - 1. Set *Table* to 'Employees' + 1. Set *Table* to `Employees`. 2. `Add Column` for each form field in the Employees **Field Group**. Set the *Value* to the form field bindings, e.g. `{{ Form.Fields.First Name }}` - 3. `Add Column` for the 'Jobs' column. Set *Value* to `{{ Action 2.Saved row._id }}`. This will get the **\_id** of the Job that was saved in second action. - 4. `Save` your actions! + 3. `Add Column` for the `Jobs` column. Set *Value* to `{{ Action 2.Saved row._id }}` so the employee row links to the saved job. + 4. Save the actions. ![](https://files.readme.io/a0ac370f616d059a211b0d235214546520b7273875a1d9c586107789682ec86c-image.png) > 📘 Employee validation > -> As the select form schema is for the *Jobs* table, you will need to add [custom validation rules](https://docs.budibase.com/docs/form-validation#custom-validation-rules) to the *Employee* fields you want validated. +> Because the select form schema is based on the *Jobs* table, add [custom validation rules](https://docs.budibase.com/docs/form-validation#custom-validation-rules) to any *Employee* fields you want validated. > -> The same is also true for options that are defined by the table schema, such as *Employee Level* in this case. +> The same applies to options defined by the table schema, such as *Employee Level*.
From 483a50f4612e3efa218802820114f0d2c1e6510e Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 10:16:43 +0100 Subject: [PATCH 14/32] thirteenth batched update --- .../automation-actions/branching.md | 57 ++++++------- docs/Automation/synchronous-automations.md | 46 +++++----- docs/Getting started/quickstart.md | 84 +++++++++---------- docs/References/deployment-information.md | 17 ++-- .../sso-with-keycloak.md | 40 ++++----- docs/Settings/user-settings.md | 13 ++- 6 files changed, 124 insertions(+), 133 deletions(-) diff --git a/docs/Automation/automation-actions/branching.md b/docs/Automation/automation-actions/branching.md index 5c26f921e..3ab8ce815 100644 --- a/docs/Automation/automation-actions/branching.md +++ b/docs/Automation/automation-actions/branching.md @@ -7,66 +7,64 @@ excerpt: >- deprecated: false hidden: false metadata: - title: 'banana' + title: '' description: '' robots: index next: description: '' --- -The automation branching feature introduces a powerful new way to control the flow of your automation processes. Branching dramatically improves flexibility and efficiency by allowing you to create multiple conditional paths within a single automation workflow. Instead of progressing through a linear sequence of steps, you can now define different paths based on specific conditions, enabling dynamic and adaptive workflows. +Branching lets you split an automation into multiple conditional paths instead of running every step in a single line. -With this new feature, you can create branches by clicking the Branching Icon to the left of the "+" symbol on an existing step. This creates two branching paths that originate from the selected step. Additionally, an Add Additional Branch button allows you to add more branching conditions to the right of the existing branches. Each branch operates independently, with its own set of conditions that can be configured to control the automation flow. +Create a branch from an existing step by clicking the branching icon to the left of the `+` symbol. This starts with two paths, and you can add more with **Add Additional Branch**. ## Key features -1. **Create Multiple Conditional Paths**: You can split your automation into two or more paths based on specified conditions. This mimics the behavior of conditional statements, providing flexibility to route different inputs or events down other paths. -2. **Add Additional Branches**: Beyond just two initial paths, you can continue adding branches by clicking the Add Additional Branch button, allowing you to handle complex workflows with multiple potential outcomes. -3. **Configurable Conditions**: Each branch has its own set of conditions configured by clicking the Add Condition button. This opens a modal with a [dynamic filtering](doc:dynamic-filter) form, where you can compare values (e.g., if a value is equal to or not equal to a specified parameter) to determine the path that should be followed. Conditions are optional; if no conditions are defined for a branch, it will always evaluate as true and execute its steps if evaluation reaches that branch. -4. **Order of Execution**: Arrows within the branching step allow you to change the order of conditions being evaluated. This ensures that you have control over which branch is checked first, giving you priority management for condition evaluation. -5. **Deletion and Tooltip**: Branches can be deleted when no longer needed, and a helpful tooltip explains that "Only the first branch which matches its condition will run." This ensures users understand that the evaluation stops once a condition is met, preventing unnecessary steps. +1. **Multiple conditional paths**: Split one automation into two or more paths based on specific conditions. +2. **Add more branches**: Use **Add Additional Branch** to handle more than two outcomes. +3. **Configurable conditions**: Click **Add Condition** to open a [dynamic filtering](doc:dynamic-filter) form and define when a branch should run. If a branch has no condition, it always evaluates to true. +4. **Execution order**: Use the arrows in the branching step to change which branch is checked first. +5. **Delete branches**: Remove branches you no longer need. Only the first matching branch runs. ## Branching benefits -Greater flexibility: In older versions of Budibase, automation progressed linearly, where each step was executed sequentially without the ability to branch off into different directions. This often meant creating long, repetitive automation to handle different scenarios, which wasn't efficient and difficult to maintain. The new branching system in Budibase is more efficient as it allows the automation to split into multiple paths based on conditions, reducing the need for long, repetitive chains of steps. +Branching is useful when different inputs need different actions. Instead of building long linear flows, you can route each case through its own path and keep the automation easier to maintain. -The new branching system solves this by allowing the automation to split into multiple paths based on dynamic conditions. You no longer need to create long chains of steps to cover every possibility, which is done by setting conditions. This reduces complexity, saves time, and offers more powerful workflow customisation. - -It supports complex use cases. The ability to add numerous branches means that you can design automations that handle highly complex use cases. Whether you need to route customer requests based on various criteria, trigger different actions depending on product type, or segment workflows based on user attributes, automation branching enables this level of complexity without requiring a cumbersome setup. +It also works well for more complex workflows. You can route customer requests by type, trigger different actions by product, or segment workflows by user attributes without duplicating the full automation. ## Branching Tutorial -In this tutorial, we will create a customer support ticketing system. The aim here is to use branching to route tickets to different teams based on various factors; **type**, **urgency**, and **customer priority level**. We will be using the internal Budibase data source for this tutorial +In this tutorial, you will create a customer support ticketing system. Use branching to route tickets based on **type**, **urgency**, and **customer priority level**. This tutorial uses the internal Budibase data source. 1. Create a table called Support\_tickets 2. Create 5 fields - 1. Title - text type field + 1. Title - text field 2. Ticket\_type - Single select - 1. Bug - Default to this value + 1. Bug - default value 2. Feature request 3. Enquiry 4. Other 3. Urgency - Single select - 1. Low - Default to this value + 1. Low - default value 2. Medium 3. High 4. Customer\_priority\_level - Single select - 1. Low - Default to this value + 1. Low - default value 2. Medium 3. High - 5. Notes - Long form text field + 5. Notes - long text field The table setup screen should show the five fields listed above. 3. Click the **Automations** button shown in the table setup screen 4. Click **Generate automation** - The automation picker should open next. + The automation picker opens. 5. Click **Row is created** Select the row-created trigger for the table. 6. You should now be redirected to the automations area with the correct automation type. -7. Now lets start setting up our conditional branches +7. Set up the conditional branches 1. Click the branching icon beside the + symbol - 2. Add an extra branch (By default you start with 2) + 2. Add an extra branch. You start with 2 by default. 3. Click the Add condition button to add conditions 1. The first will cover bugs that are medium or high where the customer level is high @@ -75,17 +73,16 @@ In this tutorial, we will create a customer support ticketing system. The aim he Use a fallback branch for other bug tickets that do not match the first condition. 3. The last will handle any non bug related ticket submissions Use a final branch for all non-bug tickets. - 4. Provide a descriptive name to each of the branches so you know what they do -8. For this tutorial I will just output a different backend log for each branch. You can add any step or run any process here e.g. email, updating a row or even triggering a different automation to handle a specific flow. - 1. Add different text to each backend log -9. Head back to your data area and click screens in your table + 4. Give each branch a descriptive name. +8. For this tutorial, output a different backend log for each branch. You can add any step here, such as sending email, updating a row, or triggering another automation. + 1. Add different text to each backend log. +9. Return to your data area and click screens in your table 10. Click **Generate app screen** 11. Click Generate on your selected table -12. Click side panel and then click done - Select the side panel layout, then confirm. -13. This will bring you to an app screen where it has auto generated a screen. -14. Click publish at the top right of your screen and then click the button publish inside -15. Navigate to your published app and create 3 different records +12. Select the side panel layout, then click Done +13. This opens the generated app screen. +14. Click Publish in the top right, then click Publish again in the dialog. +15. Open the published app and create 3 different records 1. The first is a high-priority bug for a high-priority customer. This should output the first branch's backend log. 2. Create a bug that is high but for a medium-priority customer. This should output the second branch's backend log. 3. Create a `support_type` value that is anything other than a bug. This should output the last branch's backend log. diff --git a/docs/Automation/synchronous-automations.md b/docs/Automation/synchronous-automations.md index a9ca2c135..fd0791f86 100644 --- a/docs/Automation/synchronous-automations.md +++ b/docs/Automation/synchronous-automations.md @@ -16,9 +16,9 @@ next: `}
-Synchronous automations allow users to receive feedback from their automation, in the Design section or via a webhook response. +Use synchronous automations when the caller needs a result from the automation run, either in the Design section or from a webhook response. -Automations are usually asynchronous, this means that when an automation runs, it does so in the background and the user is unable to access its result, but with synchronous automations the result is available to the user. +Most automations run asynchronously, so the caller does not get the result directly. A synchronous automation returns the result to the caller. > 📘 Licensing🔒 > @@ -30,17 +30,17 @@ Automations are usually asynchronous, this means that when an automation runs, i ## Creating a Synchronous Automation -You can make an automation synchronous by adding a **Collect Data** step. +Add a **Collect Data** step to make an automation synchronous. -A **Collect** step will simply return whatever binding or value is passed to it. +A **Collect Data** step returns the binding or value passed into it. -Once this step has been added, you can access the result of your automation as a Budibase user, or external user depending on whether your automation trigger is [On demand](doc:app-action) or [Webhook](doc:webhook). +Once the step is added, you can access the automation result as a Budibase user or as an external caller, depending on whether the trigger is [On demand](doc:app-action) or [Webhook](doc:webhook). > 📘 Last step > -> As the **Collect Data** action returns data from your automation, it must be the last step. Otherwise you will see that the action is greyed out: +> The **Collect Data** action must be the last step in the automation. Otherwise the action is greyed out: > > @@ -48,25 +48,25 @@ Once this step has been added, you can access the result of your automation as a ## Webhook -When using the [Webhook](doc:webhook) trigger, you can return data to the caller of the trigger URL. +With the [Webhook](doc:webhook) trigger, you can return data to the caller of the trigger URL. -For example, consider this webhook automation that queries an Employees table, filtering on the *city* value that is passed into the trigger: +For example, this webhook automation queries an Employees table and filters on the *city* value passed into the trigger: ![](https://files.readme.io/3ca2a7a2d1761fa3b65d63ee7582ec98ba3a1556fe7f50015b371140a21b1230-image.png) ![](https://files.readme.io/a4e4ece382d3fb981ba94430276c28fb45e7ae4526f2b7173a448de896c256ca-image.png) -We can then specify data that should be returned to the caller of the trigger, in this case simply all of the rows matching the city provided. +You can then choose which data the trigger returns. In this example, it returns all rows matching the provided city. -After publishing this automation, we can see the result in our POST request: +After publishing the automation, the POST request returns the collected data: ![](https://files.readme.io/65975b456d3b96f5cdf20fc35633eacb4edabb31412730ae1e7e9a092e50c7de-image.png) -You can now see the response from the **Collect Data** step has been provided in the response of the trigger call. Note that value in this case is a string - this is because **Handlebars always return strings.** +The response includes the value from the **Collect Data** step. In this case it is a string because **Handlebars always return strings**. -If you want to ensure that the correct typing is returned, such as for numbers and arrays, then you can use a JavaScript binding instead. +If you need a specific type, such as a number or array, use a JavaScript binding instead. Making sure an array is returned Making sure an array is returned @@ -80,7 +80,7 @@ And now the result: ## On demand -For users to access the result of your automations in a published Budibase app, you will need to configure an [On demand](doc:app-action) trigger within the *Design* section. Let's start off by creating a very simple automation that will get a specific row based on the \_id we are passing to it. +To use the result in a published Budibase app, configure an [On demand](doc:app-action) trigger in the *Design* section. In this example, the automation gets a specific row based on the `_id` passed to it. ![](https://files.readme.io/210e91308bf6e0799e5f5c7b1d8a67f84ada077a4b5182e095777b26c8b44bba-image.png) @@ -88,34 +88,34 @@ For users to access the result of your automations in a published Budibase app, Filter attached to the query rows step -With this done we can start setting up our screen. Create a new screen and add a button component. Select the component. The button's settings side panel should show up on the right of your screen. Then click on the button beside the label `On click` called `No actions set`. This will open the actions drawer. Add a new trigger automation action and select our newly created On demand automation. +With the automation ready, create a new screen and add a button component. Select the button, open the action drawer from `On click`, and add a trigger automation action that uses the new On demand automation. ![](https://files.readme.io/6c4d0b235c13af62487b3dd037b6c19dd8c11ff2bc6a2fd86a4cb793eaa94d20-image.png) > 🚧 Timeout > -> As shown in the screenshot, a synchronous automation can run for up to 120 seconds, or less if required. +> A synchronous automation can run for up to 120 seconds, or less if required. -Because we have a collect step at the end of the automation, a binding with the result of the automation can be provided to any of the following actions, through [Chaining actions](doc:chaining-actions). +Because the automation ends with a collect step, you can pass the result into later actions through [Chaining actions](doc:chaining-actions). -In this example, we will use the binding to add the result of an automation into [App state](doc:app-state) and then display it in a paragraph component. +In this example, the binding adds the result to [App state](doc:app-state) and then displays it in a paragraph component. ![](https://files.readme.io/e50ca9214018f782819c4fb3f7a5d1d7f848623e4abb1be0d7db9e4c67109cc0-image.png) -When the button with these actions attached is clicked, state will now be updated with a key called `result` that contains the result of our automation. +When the button is clicked, state updates with a `result` key that contains the automation result. -To display this we now simply to need bind the state to the Text component. +Bind that state to the Text component to display it. -We can now preview our app and click the [Button](doc:button) for which our actions are defined. +Preview the app and click the [Button](doc:button) with the actions attached. ![](https://files.readme.io/5c4d20c0699da9f18db9550f80e66f4b1b4b6f8367d2e395d203cd1807c2e172-image.png) -The automation result is stored in state, and due to the binding of that state to the text component, appears on screen whenever the `Trigger` button is clicked. +The automation result is stored in state and appears in the text component whenever the `Trigger` button is clicked. -Instead of displaying the result in a component, you could just as easily use the **Show Notification** action, or any other combination of actions. +Instead of displaying the result in a component, you could use **Show Notification** or any other action combination. > 📘 Automation Result > -> The automation result binding will only be available if your automation has a **Collect Data** step. \ No newline at end of file +> The automation result binding is only available if the automation has a **Collect Data** step. diff --git a/docs/Getting started/quickstart.md b/docs/Getting started/quickstart.md index 7c3929154..3036c74da 100644 --- a/docs/Getting started/quickstart.md +++ b/docs/Getting started/quickstart.md @@ -10,15 +10,15 @@ metadata: next: description: '' --- -This tutorial will take less than 5 minutes, and at the end, you will have successfully built a complete CRUD application. +This quickstart shows how to build a basic CRUD app from sample data in a few minutes. -We will use the [Sample data](doc:data-sources#sample-data), which includes a few tables with various data types to look at. +We use the [Sample data](doc:data-sources#sample-data), which includes a few tables and common field types. ## **Getting started** -1. Create a new account at [https://account.budibase.app/register](https://account.budibase.app/register) (onboarding takes a few seconds). -2. Once registered, log in. -3. Step through the first Workspace wizard, selecting *Budibase Sample data*. +1. Create a new account at [https://account.budibase.app/register](https://account.budibase.app/register). +2. Log in after registration. +3. In the first Workspace wizard, select *Budibase Sample data*. Expected result: @@ -29,13 +29,13 @@ Expected result: ## **Agents** -If agents are your main use case, configure them early in the same workspace. +If Agents are part of your setup, configure them in the same workspace before you build further. | Step | What to do | | :--- | :--------- | | Configure models | Add an AI provider under **Settings > Connections > AI models** | | Create an agent | Open **AI > Agents**, create an agent, and connect a model | -| Test and deploy | Validate behavior, then use `Set live` to deploy | +| Test and deploy | Validate the agent, then use `Set live` to deploy | | Add user access | Enable Agent Chat or embed chat with the Chatbox component | Useful guides: @@ -46,79 +46,73 @@ Useful guides: ## **Data** -Most of the columns in our sample data, for example *First Name*, *Last Name* and *Email*, are [Text](doc:text) data types, which is the most common. +Most sample columns, such as *First Name*, *Last Name*, and *Email*, use the [Text](doc:text) data type. -Other types include [Number](doc:number), [Date/Time](doc:datetime), and more. +Other common types include [Number](doc:number), [Date/Time](doc:datetime), and more. -The values of some fields are highlighted in a coloured pill. This indicates the value to be either a [Multi-select](doc:multi-select) value such as *Employee Level* in the **Employees** table, or a [Relationships](doc:relationships) link such as *Assigned* in the **Jobs** table. +Some fields display in a coloured pill. This usually means the field is a [Multi-select](doc:multi-select) value such as *Employee Level* in the **Employees** table, or a [Relationships](doc:relationships) link such as *Assigned* in the **Jobs** table. -In Budibase, data sources are shared across their Workspace. This means that we can utilize them within any App or Automation in the same Workspace. +Data sources are shared across the Workspace, so you can use them in any app or automation. ## **External datasource** -If you want to connect to external datasources, have a look at our [Datasources](doc:data-sources) section for a list of available connectors. -Further information can be found in the [Introduction to Data](doc:data) page. +If you want to connect to external data sources, see [Data sources](doc:data-sources) for the available connectors. +For more detail, see [Introduction to Data](doc:data). *** ## **Apps** -As we have some data, we can now start building out end-user apps. This is done in the Apps section, which can be navigated to via the tab on the left-hand side of the page. +Now that the workspace has data, you can start building an app in the Apps section. -Here, we’re prompted to create our first app. - -Within the app builder, the left-hand panel includes two core areas for building out your apps: +The left-hand panel includes two core areas: 1. [Screens](doc:screens) 2. [Components](doc:components) -When building apps, you will mostly be focused on the *Screen* and *Component* views. +Most app work happens in the *Screen* and *Component* views. -When the *Screen* is selected in the component tree, basic settings are available in the right-hand side panel. +When a *Screen* is selected in the component tree, its settings appear in the right-hand panel. -You can access navigation settings under `Navigation`. +Navigation settings are available under `Navigation`. ### **Autogenerated screens** -To get started quickly, click `Add screen`. Next, select `Table` to create new CRUD (Create, Read, Update, Delete) screens for each of your tables. - -These autogenerated CRUD screens make use of the [Table](doc:table) and [Side panels](doc:side-panel) for fast, all-in-one data interaction. +To get started, click `Add screen` and select `Table` to generate CRUD screens for each table. -When auto-generating, screens inherit the access level from the underlying data source. +These screens use the [Table](doc:table) and [Side panels](doc:side-panel) components for fast data interaction. -You can read more about [screen access levels](doc:screens#access-level), but in this tutorial, we will stick to the defaults. +Generated screens inherit the access level from the underlying data source. -Upon clicking `Done`, a new screen is generated for each table selected. +For this tutorial, keep the default [screen access levels](doc:screens#access-level). ### **Components** -With the screens created, you can view and edit the components for each. +Once the screens are created, you can view and edit their components. -With the Table component selected, you can edit its settings via the Settings Panel. Here you can change the *Data Source*, *Filters*, *Column*, and more. These settings are explained on the [Table](doc:table) page. +With the Table component selected, use the Settings panel to change the *Data Source*, *Filters*, *Column*, and more. See the [Table](doc:table) page for details. -You can also click the `+` icon in the bottom right to add another component to your screen. You can view a list of available core [Components](doc:components) and learn more about [Data in design](doc:working-with-data). +You can also click the `+` icon in the bottom right to add another component. For a list of core components, see [Components](doc:components). To bind data in the builder, see [Data in design](doc:working-with-data). ### **Blocks** -In Budibase, there is a category of components known as [Blocks](doc:blocks), which are collections of pre-built components designed to make building your apps easier and faster. - -A list of them can be found in the *Blocks* section of the components view. +Blocks are pre-built groups of components that speed up app building. -Sometimes you will find yourself needing to make a fine-grain tweak that cannot be done through the settings panel alone. +You can find them in the *Blocks* section of the components view. -If you want to edit the form fields in the side panel of a Form Block, for example, click the [Eject](doc:blocks#ejecting-blocks) button to pop open the block, exposing its constituent components. +If you need to make a change that is not available in the Settings panel, use [Eject](doc:blocks#ejecting-blocks) to open the block and edit its components directly. *** ## **Preview and Publish** -During development you may wish to test out your app so far. Click `Preview` in the top-right to open the app in a modal. The app preview always opens the screen selected within the builder. +During development, use `Preview` to test the app in a modal. Preview opens the screen selected in the builder. -You will also notice that navigation links are automatically added to the nav bar when autogenerated screens are created. +Autogenerated screens also add navigation links to the nav bar. -To view the app with a different permission level, change the `View as` option. +Use `View as` to test a different permission level. -When you are happy with your app, use `Set live` to deploy your app into production. +When you are ready, use `Set live` to deploy the app. | Control | Where | Outcome | | :------ | :---- | :------ | @@ -130,17 +124,17 @@ When you are happy with your app, use `Set live` to deploy your app into product ## **Automate** -Automations are not needed for all use-cases, however they offer powerful workflow options such as [Cron jobs](doc:cronjob) and [Webhooks](doc:webhook) integrations. +Automations are optional, but they add workflow options such as [Cron jobs](doc:cronjob) and [Webhooks](doc:webhook). -In Budibase, Automations can interact with all data and apps in their Workspace. +Automations can interact with all workspace data and apps. -More information can be found in the [Automations](doc:contextual-bindings) page. +For more detail, see [Automations](doc:contextual-bindings). *** ## **Settings** -The settings tab includes a variety of options for your workspace. These include: +The Settings tab includes workspace options such as: * [Automations](doc:logs) * [Backups 🔒](doc:backups-1) @@ -151,9 +145,9 @@ The settings tab includes a variety of options for your workspace. These include ## **Further exploration** -At this point, you can see the speed and convenience with which Budibase allows you to get your users interacting with data. +At this point, you have the basics needed to build an app around your data. -There is, however, much more to explore, and a broad range of possibilities. If you wish to add logic and interactivity to your apps, these docs pages may be a good place to check out: +If you want to add more logic or interactivity, these pages are a good next step: * [Forms](doc:forms) * [Bindings](doc:introduction-to-bindings) @@ -163,4 +157,4 @@ There is, however, much more to explore, and a broad range of possibilities. If ## **The Budibase community** -If you have any questions or want to browse what other people have been building, please reach out to us on [GitHub Discussions](https://github.com/Budibase/budibase/discussions) or join our [Discord server](https://discord.com/invite/ZepTmGbtfF). +If you have questions or want to see what others have built, visit [GitHub Discussions](https://github.com/Budibase/budibase/discussions) or join our [Discord server](https://discord.com/invite/ZepTmGbtfF). diff --git a/docs/References/deployment-information.md b/docs/References/deployment-information.md index 8d8762843..805d77e30 100644 --- a/docs/References/deployment-information.md +++ b/docs/References/deployment-information.md @@ -10,21 +10,22 @@ metadata: next: description: '' --- -A common question asked about deployment is how does it work and where does it go - an important question to ask before considering a platform to build your tools on top of. +Deployment questions usually come down to two things: where the app goes and what gets deployed. ## Where deployments go ### Self-hosted -In the case of a self-hosted deployment, the answer is very simple, the app, attachments and all data will be uploaded to the self-hosted platform, this data will be spread between your MinIO and CouchDB services, being served by the Budibase apps service. +For a self-hosted deployment, the app, attachments, and data are uploaded to your own platform. They are stored across MinIO and CouchDB and served by the Budibase apps service. ## How does deployment work -Another important question is the technical side of what actually happens when your app is deployed. Here I'll give a quick overview of the steps taken by the Budibase builder and platform to get your app live! This process is nearly identical whether you're deploying to a self-hosted service or if you're deploying to the Budibase Cloud; the only differences being around how Budibase keeps everyone's apps separate and within user quota limits in the Cloud. +The deployment process is mostly the same whether you deploy to self-hosted infrastructure or Budibase Cloud. The main differences are how apps are separated and how Cloud quotas are enforced. -1. First the builder sends up your hosting/API key to confirm you have access to the platform, if accepted the platform will return tokens to allow for a one-time deployment to the various services -2. Next the builder uses these tokens to talk through our proxy service to the database and object store engines, storing app data, metadata about the app and the Budibase client, the Svelte app that is the base of every Budibase app. -3. All metadata and app data is stored in [CouchDB](https://couchdb.apache.org), a NoSQL database that importantly supports [replication](https://docs.couchdb.org/en/stable/replication/protocol.html). We replicate the data from your builder to the CouchDB service, meaning we can merge data from existing apps with any updates you've made in the builder as well as deploying fresh apps. -4. Lastly the builder confirms if the deployment was successful and returns the information about how to access the app to the user. This will also include working our the URLs for any webhooks which are now running in the deployed app. +1. The builder sends your hosting or API key to confirm access. +2. If the request is accepted, the platform returns deployment tokens. +3. The builder uses those tokens to write app data, metadata, and the Budibase client through the proxy service. +4. App and metadata storage live in [CouchDB](https://couchdb.apache.org), which supports [replication](https://docs.couchdb.org/en/stable/replication/protocol.html). Budibase replicates data from the builder to CouchDB so updates can be merged with existing apps. +5. The builder confirms the deployment and returns access details, including webhook URLs for the deployed app. -As you can see the deployment process is quite simple, secure, upload, and then confirm, then you're ready to start using the app! \ No newline at end of file +The process is simple: authenticate, upload, confirm, and then use the deployed app. diff --git a/docs/Settings/authentication-and-sso/sso-with-keycloak.md b/docs/Settings/authentication-and-sso/sso-with-keycloak.md index 4a444b9af..95dd17e22 100644 --- a/docs/Settings/authentication-and-sso/sso-with-keycloak.md +++ b/docs/Settings/authentication-and-sso/sso-with-keycloak.md @@ -20,35 +20,35 @@ next: ### Realm Setup -It's advised to use a realm other than the `master` realm in keycloak. The `master` realm in Keycloak contains your admin user and is meant to only be used as a top level admin space, where you can provision and manage other admin users and new realms. +Use a realm other than `master`. In Keycloak, `master` is reserved for top-level administration. -To create a new realm, log in as your admin user at `/admin` and go to the realm dropdown on the left. Click "Create realm" and name your new realm, then save. +To create a new realm, sign in at `/admin`, open the realm dropdown on the left, click "Create realm", and save the new realm name. ### Add a Client -The first step of configuring Keycloak for OIDC in Budibase is to create a client. Log into Keycloak admin console with your admin credentials: +Create a client in Keycloak before you configure Budibase. -Visit the 'Clients' pane on the left side of your Keycloak admin console and click the 'Create client' button. +Open the **Clients** pane in the Keycloak admin console and click **Create client**. -Give your new client an ID and select 'OpenID Connect' from the dropdown. Then click next. This client ID will be the one you use in Budibase to connect your Keycloak instance for OIDC authentication. +Give the client an ID, select **OpenID Connect**, and continue. Use this client ID in Budibase. -(If you have a client already created, bypass this step.) +If you already have a suitable client, skip this step. ### Capability config -In the Capability config screen, toggle on 'Client authentication'. This will generate a **secret key** for the client, which you will use within the Budibase OIDC configuration later. Click the 'next' button. +In the Capability config screen, enable **Client authentication**. This generates the client secret you will use in Budibase. -Next, we will get the Callback URL that we need to paste into Keycloak. You will find this in your Budibase portal under Settings > Auth > OpenID Connect. +Next, copy the callback URL from your Budibase portal under **Settings > Auth > OpenID Connect**. -Copy the callback URL and add it to the 'Valid Redirect URIs' field in Keycloak then click 'Save'. +Add the callback URL to **Valid Redirect URIs** in Keycloak, then save. @@ -56,34 +56,36 @@ Copy the callback URL and add it to the 'Valid Redirect URIs' field in Keycloak #### Client ID -The Client ID field in Budibase shuld be the same ID as you gave the Client in Keycloak earlier. +The Client ID in Budibase should match the client ID you created in Keycloak. #### Client Secret -You can find the Client Secret from the Credentials tab in the Client Configuration screen +Find the Client Secret on the **Credentials** tab in the client configuration screen. -Add this to the "Client secret" field in your Budibase OIDC panel. +Add it to the **Client secret** field in the Budibase OIDC panel. #### Configuration URL -Visit the 'Realms settings' pane on the left hand side of your Keycloak admin console. Click into the general tab at the top of this page. Scroll down to the bottom and then click on the **OpenID Endpoint Configuration** link and copy the URL. +Open **Realm settings** in the Keycloak admin console, then open the **General** tab. Scroll to **OpenID Endpoint Configuration** and copy the URL. -You can then paste this URL into your Budibase OIDC Config as the Configuration URL, and Budibase will be integrated with Keycloak for OIDC. +Paste the URL into the **Configuration URL** field in Budibase. -# Managing Users +## Managing Users -Now that Budibase is set up to authenticate using OIDC through Keycloak, we need to make sure we have users set up in our realm. To create a new user, you need to go to the **Users** tab in the Keycloak admin panel under your realm, and click "Create user" +After Budibase is set up, create users in the Keycloak realm. -Make sure you enter a username and email address for your user. +Open the **Users** tab in the Keycloak admin panel and click **Create user**. + +Enter a username and email address. -To add a password for the user, click the "Credentials" tab of the new user, and add a password by clicking the "Set Password" button. If you don't want the user to have to change the password on first log in, make sure to toggle the "Temporary" toggle off. +To add a password, open the **Credentials** tab and click **Set Password**. Turn off **Temporary** if the user should not change the password on first sign in. -Now the user is created, you can sign in as that user through Budibase OIDC using Keycloak! +You can now sign in through Budibase using Keycloak. diff --git a/docs/Settings/user-settings.md b/docs/Settings/user-settings.md index 5e3f5c5ed..f33b15edc 100644 --- a/docs/Settings/user-settings.md +++ b/docs/Settings/user-settings.md @@ -10,29 +10,26 @@ metadata: next: description: '' --- -Budibase provides some options for configuring your user account. Access the user settings menu by clicking on your profile dropdown in the top right of the builder. +Use the User settings menu to update your account details and developer options. Open it from your profile dropdown in the top right of the builder. 1389 -Let's go through the options one by one. - ### Update user information -Update your first and last name for your user account. This is useful for things like email templates within Budibase, and will allow other people in your organisation to identify you. +Update your first and last name. This helps with email templates and makes it easier for other people in your organisation to identify you. 384 ### Update password -Here, you can update the password for your own user account. +Use this option to change your password. 384 ### Toggle developer mode (Developer/Admin users only) -As a developer/admin, you can switch between viewing the portal in **developer mode** and **standard mode**. Find out more about the different budibase [Portal](doc:portal) modes. +As a developer or admin, you can switch between **developer mode** and **standard mode**. For more detail, see [Portal](doc:portal). ### View API key -Displays the API key with a handy copy button. -This is a required header when using the [Public API](doc:public-api) \ No newline at end of file +Displays the API key and a copy button. Use this value as the required header for the [Public API](doc:public-api). From 0553d667b909b7299e058a08f7cdf5e69e57fc76 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 12:37:01 +0100 Subject: [PATCH 15/32] another batched update --- .../data-in-automations.md | 64 +++++++------------ docs/Automation/trigger/app-action.md | 32 +++++----- docs/Data/environment-variables.md | 60 ++++++----------- .../Getting started/quickstart-budibase-ai.md | 6 +- .../user-management/scim-provisioning.md | 52 ++++++++------- 5 files changed, 84 insertions(+), 130 deletions(-) diff --git a/docs/Automation/contextual-bindings/data-in-automations.md b/docs/Automation/contextual-bindings/data-in-automations.md index ecd461963..53fd817a3 100644 --- a/docs/Automation/contextual-bindings/data-in-automations.md +++ b/docs/Automation/contextual-bindings/data-in-automations.md @@ -10,73 +10,57 @@ metadata: next: description: '' --- -Automations in Budibase deal a lot with data. Something [Triggers](doc:trigger) the automation, and then actions can be performed based on that. But how do you deal with data inside automation? - -This in-depth guide will explain the best way to deal with data in automations. +Automations in Budibase often move data between triggers and actions. This guide shows how to work with that data inside an automation. ## Trigger Data -Let's begin to look at the data coming in through a trigger. We're going to be looking at the `Row Created` action, but this same flow also works for all other actions. +Start with data coming in through a trigger. This example uses the `Row Created` trigger, but the same pattern works for other triggers too. > 👍 Follow along > > To follow along with our example, load the csv-data from the [Quickstart](doc:quickstart) guide. -First, define a `Row Created` Trigger. - - - -We've selected the table `Fleet` which we want to monitor, and then our `Trigger` is defined correctly. - -Next step, create an action. Choose any action you want, but in our example we're going to be adding a `Condition` action to make sure we're only running this action on cars that are newer than 2015. Alternatively, you can apply filters to the initial trigger. If whatever filter provided doesn't match the automation simply won't run. - -Inside the `Condition` action you can see the field `Reference Value`, this is where the [Bindings](doc:bindings) come in. When clicking the lightning icon you can select from the predefined value of `Trigger.row`. This is what we want to use, as that is an object containing the data from the table. +First, define a `Row Created` trigger. -Look at the table to see what the data-structure is and what the name of the column is, then add that to your binding. +Select the `Fleet` table you want to monitor. - +Next, add an action. This example uses a `Condition` action so the automation only continues for cars newer than 2015. You can also apply filters to the trigger instead. -Comparing it to the current year using the \{\{ now }} binding. This outputs a UTC timestamp value to compare against. +Inside the `Condition` action, use the `Reference Value` field. Click the lightning icon and select `Trigger.row`, which contains the row data from the table. - +Check the table to confirm the column name, then add it to the binding. -And then of course we're setting our value `2015` and the `greater than` condition accordingly. +Compare it to the current year using the `{{ now }}` binding. This returns a UTC timestamp. - +Set the value to `2015` and use the `greater than` condition. > 👍 Trigger.row > -> `Trigger.row` will always contain the row from the trigger, in an object format, when the action is row-related. No matter how many actions you've added in between, the data will be there to be used as an object. +> `Trigger.row` always contains the row from the trigger when the action is row-related. The value remains available even after additional actions. ## Querying data with trigger data as filter -Next, now that we've set our arbitrary condition, we're going to do an arbitrary query on the `Fleet` table from the same year as the newly added car. For this, we'll need to use the `Trigger row` data to match this. +Now query the `Fleet` table for the same year as the newly added car. Use the `Trigger.row` data to match the year. -First, let's add the `Query Rows` action, and select the same table, `Fleet` as the source for querying. Then, we're going to define a filter. +Add the `Query Rows` action and select the `Fleet` table as the source. Then define a filter. -Click the `Define Filters` button in the `Query Rows` action to get started +Click `Define Filters` in the `Query Rows` action to get started. - +A modal opens where you can add a filter for `Year`. Use the `binding` property and enter `{{ trigger.row.Year }}`, or click the lightning bolt to use the [Bindings](doc:bindings) overlay. -A modal will be presented, in which we're going to add a filter for `Year`. Use the `binding` property, and enter \`\{\{ trigger.row\.Year }}\`\`, or click the lightning bolt to use the [Bindings](doc:bindings) overlay. +Click save and the filter is ready. Set the query limit to 1 and configure sorting as needed. - - -Click save, and your filter is now defined to take the newly created car as a source for querying. Complete the setup for `Query Rows` by setting the limit to 1, and then setting sorting to your own wishes. - -Now you can test your automation to see what data is returned. In the `output` section you should see a JSON representation of returned data from the `Fleet` table. - - +Test the automation to see what data is returned. In the `output` section, you should see a JSON representation of the returned `Fleet` data. ## Using Automation Step Data -Every automation step generates data you can use, from `booleans` if things went successful, to query data. Each step generates an item in the bindable `Steps` object available throughout the automation. Take the condition action we've defined in the `Trigger Data` step above. Considering the output is only a boolean, it will return a boolean. But as the condition halts automation execution, we only will ever see `true` returned, nonetheless, this boolean can be found under `Steps.1.success`. +Every automation step generates data you can use, from booleans to query results. Each step adds an item to the bindable `Steps` object available throughout the automation. In the condition action from the `Trigger Data` step above, the boolean result is available under `Steps.1.success`. -Next of course is the more logical data to use, the car queried in step 2. For the purpose of demonstration, we're going to send a Discord Notification with the Make and Model of the car we just queried. +Next, use the row returned in step 2. For this example, send a Discord notification with the Make and Model of the car you queried. -Enter the Discord Webhook URL and bot-name accordingly, and then we're going to the fun part. Binding data from the `Query Rows` in step 2. +Enter the Discord Webhook URL and bot name, then bind data from the `Query Rows` step. -Step 2, or `steps.2` in [Bindings](doc:bindings), contains a `rows` array, giving you the results of the query. Considering we have limited the query to 1 item, we're going to have to use `steps.2.rows.0` to reach the data. +Step 2, or `steps.2` in [Bindings](doc:bindings), contains a `rows` array. Because the query is limited to 1 item, use `steps.2.rows.0` to reach the data. ```handlebars Your {{ steps.2.rows.0.Make }} {{ steps.2.rows.0.Model }} {{steps.2.rows.0.[License Plate]}} was just automatically queried @@ -88,10 +72,8 @@ And with that handlebars expression, I just received the following message in Di ## Using Query Result as a condition -Of course in the example above we've used the "Happy Path" as an example. We know we're going to get results with the query, but you might want to halt the automation if you get no results. - -You can do this by adding a `condition` action in between the Discord Notification and the Query Rows action, and then bind the `Success` state of the Query Rows as a condition as shown below. +The example above uses the "happy path". You might want to halt the automation if the query returns no results. - +You can do this by adding a `condition` action between the Discord notification and the `Query Rows` action, then binding the `Success` state of `Query Rows` as a condition. -By comparing the `success` state of a query with `true` you can continue automation if you have a result, or abort the automation if you have not. \ No newline at end of file +By comparing the `success` state of a query with `true`, you can continue the automation if you have a result or stop it if you do not. diff --git a/docs/Automation/trigger/app-action.md b/docs/Automation/trigger/app-action.md index 0f588be6a..e615d631f 100644 --- a/docs/Automation/trigger/app-action.md +++ b/docs/Automation/trigger/app-action.md @@ -12,13 +12,13 @@ metadata: next: description: '' --- -The On demand trigger runs when invoked from the UI of your Budibase application, or by an agent workflow. +Use the On demand trigger when you want an app action or agent workflow to start an automation. > 📘 Fire and forget > -> Automations run asynchronously on a background thread; therefore, once an automation is triggered from the client, there will be no returned response by default. +> On demand automations run asynchronously. By default, they do not return a response to the client. > -> To receive a response, you can make use of [Synchronous automations 🔒](doc:synchronous-automations). +> If you need a response, use [Synchronous automations 🔒](doc:synchronous-automations). ## Creating the Automation @@ -26,36 +26,36 @@ Create a new automation in the Automation section, choose `On demand` as the tri ## Defining Fields -Click the trigger step to open the right-hand panel and define your fields. These fields are the input data passed into your automation for use in later steps. +Click the trigger step to open the right-hand panel and define your fields. These fields are the input data passed into your automation for later steps. Supported field types are `Text`, `Number`, `DateTime`, `Boolean`, and `Array`. -You can use these fields in the next steps, check the [Working with data in automations guide](doc:data-in-automations) to learn how. +You can use these fields in later steps. For more detail, see [Working with data in automations](doc:data-in-automations). ## Populating Fields from the UI -Now that you have defined fields to be used in your automation, you can call this automation from the UI and populate the fields you just selected. +Now that the fields are defined, you can call the automation from the UI and populate those values. Add a button in the Design section, then open its `No actions set` option in the Settings Panel. -A modal will open where you can define [Actions](doc:actions). Create a new action by choosing `Trigger Automation` from the options and clicking the `Add Action` button. +A modal opens where you can define [Actions](doc:actions). Create a new action by choosing `Trigger Automation` and clicking `Add Action`. -Then select your On demand automation from the dropdown list. Only On demand automations will appear in this list. +Then select your On demand automation from the dropdown list. Only On demand automations appear here. -After selecting your On demand automation and any fields you created, they will be pulled through below the select automation. You can freely type the values you wish to pass. Or you can use any available bindings and pass those to the automation instead. +After selecting the automation and fields, they appear below the selector. You can enter static values or use bindings instead. -After selecting the field you want to populate, you can enter the value. This can be static text, or through [Bindings](doc:bindings). You could even use [JavaScript Bindings](doc:javascript) for it. +After selecting a field, enter the value. This can be static text, a [Binding](doc:bindings), or a [JavaScript Binding](doc:javascript). -Whatever you choose for bindings, you will receive the result back in your automation, which you can then use in the next steps. +Whatever values you choose, the automation can use them in later steps. ## Using Trigger Fields -This subject touches upon [working with data in automations](doc:data-in-automations), but I wanted to highlight the specific data that comes in with this trigger. +This section focuses on the data that comes in with the trigger. For related guidance, see [Working with data in automations](doc:data-in-automations). -One popular thing to do with an `On demand` trigger is creating one or multiple database rows. You could use this action to populate various tables, or even Data Sources at once. +One common use for an `On demand` trigger is creating one or more database rows. You can use it to populate tables or even Data Sources at once. -Let's take a look at the `Create Row` action. Click the step to open its settings, select your table, and use [Bindings](doc:bindings) with `trigger.fields` to map incoming values. +The `Create Row` action is a good example. Click the step to open its settings, select your table, and use [Bindings](doc:bindings) with `trigger.fields` to map incoming values. -As you can see, we're using the same names for the fields we defined in the first step. +Use the same field names you defined in the trigger step. -And if you want, at this stage, you could create another `Create Row`, or another action to create a row in another table, or somewhere else entirely. This could also be a good moment to duplicate data to [MongoDB](doc:mongodb). \ No newline at end of file +You can also add another `Create Row` action, or send data to another table or data source. This is also a good place to duplicate data to [MongoDB](doc:mongodb). diff --git a/docs/Data/environment-variables.md b/docs/Data/environment-variables.md index 89c502062..fac2639e7 100644 --- a/docs/Data/environment-variables.md +++ b/docs/Data/environment-variables.md @@ -10,74 +10,50 @@ metadata: next: description: '' --- -Environment variables provide a mechanism for easily re-using secrets/datasource configuration across different Workspaces, as well as allowing for different values to be used in development apps versus production apps. The environment variable configuration can be found under Settings, then Environment. +Environment variables let you reuse secrets and data source configuration across different Workspaces. They also let you use different values in development and production. Find them under Settings, then Environment. -This feature is most useful when working with data that is already used in production or updating an app that is already being used. For example lets say you have two Postgres databases, one used locally for testing and one used in production for the applications real data. Environment variables can be utilised in this scenario to allow the connection details for the two different databases to be parameterised and changed depending on whether the app is in development, or in production. +This feature is most useful when you have separate development and production systems. For example, you might use one Postgres database for testing and another for live data. Environment variables let you switch connection details based on the app environment. ## Unlocking environment variables -If you are using the free tier you will see the following under the environment variables section: +If you are using the free tier, environment variables are locked. - - -You can click [Upgrade](doc:usage) to unlock environment variables or click `View Plans` to navigate to the [pricing page](https://www.budibase.com/pricing) to see the full range of options in more detail. +Click [Upgrade](doc:usage) to unlock them, or click `View Plans` to open the [pricing page](https://www.budibase.com/pricing). ## Managing environment variables -Once you have navigated to the environment variable section of the Budibase portal, you will see an option to add a new variable as shown below, but you can also edit and delete your environment variables too. - - - -Once the modal opens you'll be able to set the environment variable name and its value in production and development. Note that once these values have been set they will be encrypted (uses **AES-256** encryption), stored and you will no longer be able to retrieve it. By default this will use the same value for development as production, incase you have not yet setup two separate datasources, this way you can build your apps utilising environment variables, then later update them if you want to separate the development and production values. +In the Budibase portal, you can add, edit, and delete environment variables from the environment variable section. -![](https://files.readme.io/543d5d3-image.png) +Once the modal opens, set the variable name and the values for production and development. These values are encrypted with **AES-256** and cannot be retrieved after saving. By default, development uses the same value as production until you change it. > 🚧 Environment variable naming > -> It is important to pick recognisable names for your environment variables, as these will be how you pick which variables to use within your apps. Your variables also cannot contain spaces, we recommend the use of underscores instead. +> Choose clear variable names. They cannot contain spaces, so we recommend using underscores. -At this point you should have created your required environment variables and they should have appeared within the variable table list. From here you can also edit or delete an environment variable, it is important to note the change will be immediate, if you change a value or remove an environment variable, production apps will be affected. +Once the variables are created, they appear in the list. Edits and deletions apply immediately, so production apps are affected as soon as you save the change. -![](https://files.readme.io/07c2455-image.png) - -To edit or delete an existing environment variables, click the `Edit` button. - - +To edit or delete an existing environment variable, click `Edit`. ## Using environment variables in datasources -Once you've configured some environment variables we can progress to creating or updating an app to use these new variables. Enter an app and create or update a [datasource](doc:data-sources) from the data section, in this example we will be creating a Postgres connection. Below you can see the default Postgres connection details, you will also notice that the small key icon on the end of the input field. - -![](https://files.readme.io/013c423-image.png) +Once you have configured some environment variables, create or update an app to use them. In this example, configure a Postgres [datasource](doc:data-sources). The key icon at the end of each field opens the variable picker. -Clicking on this icon will open the environment variable menu, which allows you to select from a list of variables that have been created. You will also have the option to create a new environment variable. +Click the icon to open the environment variable menu. You can select an existing variable or create a new one. -![](https://files.readme.io/a98e757-image.png) +Once configured, the input fields are disabled and show the selected variable. -Once configured the input fields will be disabled, with the environment variable contained within, as shown below. +Environment variables may look like bindings, but they are only available in specific locations. They cannot be used everywhere bindings can. After saving the datasource, it uses the selected variable. -![](https://files.readme.io/9dd0d24-image.png) - -It is important to note that while they appear to look like bindings, they cannot be used as such. The environment variable values are only available in a few key locations and cannot be used in the same way that bindings function. Once this is complete you can save the datasource and it will now utilise the variable. - -At this point your app is now utilising these environment variables, within the app builder you will be using the development values, once you publish the app it will utilise the production values. It is important to note that these environments are entirely independent, you can be using the builder, with the development values for your datasources while your users are utilising the currently released version of your app and the production values. +In the builder, your app uses the development values. After you publish, it uses the production values. The two environments are independent. ## Using environment variables in queries -Another useful feature of environment variables is their ability to be used in [queries](https://docs.budibase.com/docs/data-sources#custom-queries) as well as datasource configuration. If you open the [binding drawer](doc:bindings) you will see a new environment section has been added, as seen below. - -![](https://files.readme.io/8ee9866-image.png) +Environment variables can also be used in [queries](https://docs.budibase.com/docs/data-sources#custom-queries). Open the [binding drawer](doc:bindings) to see the environment section. -Expanding the environment section will list all of the variables which are available to the query, unlike datasource configuration, these can be used as normal bindings in queries. In the example below we have configured a header in [REST query](doc:rest) to use an environment variable. +Expand the environment section to see the variables available to the query. Unlike datasource configuration, these can be used as normal bindings. In the example below, a [REST query](doc:rest) header uses an environment variable. -![](https://files.readme.io/0398294-image.png) - -These can also be used in an [SQL query](https://docs.budibase.com/docs/data-sources#custom-queries), in the same format as the binding drawer, like `{{ env.env_variable }}` this is shown below. - -![](https://files.readme.io/d36d61a-image.png) +You can also use them in an [SQL query](https://docs.budibase.com/docs/data-sources#custom-queries) with the same format as the binding drawer, for example `{{ env.env_variable }}`. ## Using environment variables in automations -The last place that variables can be accessed is as part of an [automation](doc:automation-steps) run. This can be very useful if connecting to an external service, or triggering a notification e.g. Slack or Discord. Like queries environment variables can be used as [bindings](doc:bindings) within automation steps. Below we have configured a Discord step in an automation, which utilises an environment variable for the webhook URL. Not only is this more re-usable and secure, but it also allows using different URLs for testing and for production. - - \ No newline at end of file +Environment variables can also be accessed in an [automation](doc:automation-steps). This is useful when connecting to external services or sending notifications such as Slack or Discord. In the example below, a Discord step uses an environment variable for the webhook URL. This keeps the setup reusable and secure, and lets you use different URLs for testing and production. diff --git a/docs/Getting started/quickstart-budibase-ai.md b/docs/Getting started/quickstart-budibase-ai.md index 89b1f0776..04fc1bfaf 100644 --- a/docs/Getting started/quickstart-budibase-ai.md +++ b/docs/Getting started/quickstart-budibase-ai.md @@ -1,9 +1,7 @@ --- title: 'Quickstart: Budibase AI' excerpt: >- - This page will help you get Budibase AI up and running quickly so you can - start generating code or database tables or creating LLM-powered automations - in your Workspace + Set up Budibase AI and use it in columns, bindings, automations, and agents. deprecated: false hidden: false metadata: @@ -20,7 +18,7 @@ next: slug: generating-javascript-with-ai title: Generating JavaScript with AI --- -Use Budibase AI after you connect a model provider in your workspace settings. +Connect a model provider in your workspace settings before you use Budibase AI. ## Enable AI diff --git a/docs/Settings/user-management/scim-provisioning.md b/docs/Settings/user-management/scim-provisioning.md index 644c5d15f..816669b5b 100644 --- a/docs/Settings/user-management/scim-provisioning.md +++ b/docs/Settings/user-management/scim-provisioning.md @@ -10,89 +10,87 @@ metadata: next: description: '' --- -SCIM (System for Cross-domain Identity Management) is an open standard for managing user identity information. +SCIM (System for Cross-domain Identity Management) lets you manage users and groups in an external identity provider and sync them into Budibase. -It allows you to manage your users and groups outside of Budibase using any Identity and Access Management service that supports SCIM. Examples include *Azure Active Directory* and *Okta*. +Common providers include *Azure Active Directory* and *Okta*. -Changes to users and groups made in your external IAM can be synced across to Budibase users and groups through a process known as **provisioning**. +SCIM provisioning is one way. Once it is enabled, synced users and groups are managed in your identity provider, not in Budibase. -It's worth noting that this is a one-way process. Once SCIM is enabled, you will no longer be able to edit AD users and groups within Budibase, any changes must be made via your external identity provider. - -You can still manually add or import users outside your organization; these users will remain fully configurable within Budibase. +You can still manually add or import users outside your organization. Those users remain fully configurable in Budibase. ## Unlocking SCIM provisioning -Contact sales to enquire about upgrading to the enterprise plan [https://budibase.com/contact/](https://budibase.com/contact/) +Contact sales to upgrade to the enterprise plan: [https://budibase.com/contact/](https://budibase.com/contact/) ## Enable SCIM -Login to the Budibase portal, and click on the `Settings` tab. Select the `Auth` tab. +Log in to the Budibase portal, then open `Settings` and `Auth`. -Scroll to the bottom of the page, and under SCIM toggle *Activated* on. The provisioning *URL* and *Token* will become available to quickly copy using the clipboard buttons to the right of the fields. +Scroll to the bottom of the page and turn on *Activated* under SCIM. The provisioning *URL* and *Token* then appear with copy buttons. > 👍 Enforced SSO > -> When using SCIM, users can only log-in to Budibase using [SSO](doc:authentication-and-sso). With this in mind, we recommend that you [Enforce SSO 🔒](doc:enforced-sso). +> When using SCIM, users can only log in to Budibase using [SSO](doc:authentication-and-sso). We recommend that you [Enforce SSO 🔒](doc:enforced-sso). *** ## Example: Azure Active Directory -This example will look at provisioning active directory users from Azure into Budibase +This example provisions Azure Active Directory users and groups into Budibase. ### Step 1 - Create an enterprise application -First, we need to create an Enterprise application to manage the users and groups that we want to provision for Budibase. +First, create an enterprise application in Azure Active Directory for the users and groups you want to provision. -Log in to Azure Active Directory, and Navigate to `Enterprise applications`. +Log in to Azure Active Directory and open `Enterprise applications`. -Click on `New application` +Click `New application`. -Then click on `Create your own application`. A side panel should appear on the right hand side of your screen. +Then click `Create your own application`. A side panel appears on the right-hand side of the screen. Create new application Create new application -Select the *(Non-gallery)* option and give your app a name. +Select the *(Non-gallery)* option and give the app a name. -Assuming you already have some users in your active directory, you can now add them to your enterprise application. +If you already have users in Active Directory, add them to the enterprise application. -Click on your application, and then click `Users and groups` under the *Manage* section. You can then click on `Add user/group` to add users individually or as user groups. +Open your application, then select `Users and groups` under *Manage*. Click `Add user/group` to add individual users or groups. ### Step 2 - Provisioning -Under the *Manage* section, click on `Provisioning`. Then click `Connect your application`. +Under *Manage*, open `Provisioning` and click `Connect your application`. -Copy and paste the URL and Token from the Budibase settings page as the admin credentials. +Copy the URL and Token from the Budibase settings page into the admin credentials fields. -Click `Test Connection` to verify everything is correct. If all the information is correct, a notification will appear saying the connection was successful. The Create button at the bottom of this page will change from grayed out to blue when you successfully test the Budibase connection. Click the `Create` button. +Click `Test Connection` to verify the setup. When the connection succeeds, the `Create` button becomes active. Click `Create`. -You will then be redirected to the Overview area for Provisioning. You can now click `Start provisioning` to sync your users and groups from your Azure enterprise app into Budibase. +You are then redirected to the Provisioning overview. Click `Start provisioning` to sync users and groups into Budibase. -The Budibase portal now shows the users who have synced under the `Users` tab. +The Budibase portal now shows the synced users under the `Users` tab. -There is also a note in this section indicating that users are being synced from your AD. +This section also shows that the users are being synced from Active Directory. -If you provide a first and last name for your Azure users, this will also be passed through, however other settings such as [User roles](doc:user-roles) and [App roles](https://docs.budibase.com/docs/user-roles#app-specific-roles) must be set within Budibase. +If you provide first and last names for your Azure users, those values are also synced. Other settings such as [User roles](doc:user-roles) and [App roles](https://docs.budibase.com/docs/user-roles#app-specific-roles) must still be set in Budibase. @@ -100,9 +98,9 @@ If you provide a first and last name for your Azure users, this will also be pas ### Step 3 - Setup SSO and give app access -Finally, we need to ensure that provisioned users can log in to Budibase. In this case, you can follow the [SSO with Azure AD](doc:sso-with-azure-ad) guide. +Finally, make sure provisioned users can log in to Budibase by following the [SSO with Azure AD](doc:sso-with-azure-ad) guide. -Furthermore, make sure you have given your users and groups [Application access](doc:application-access). +Also make sure the users and groups have [Application access](doc:application-access). Giving Carol basic app access Giving Carol basic app access From 0930a15afb15ccac391c16e4628def92e6c1f925 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 12:49:30 +0100 Subject: [PATCH 16/32] more batched updates --- docs/References/budibase-architecture.md | 32 ++++----- docs/References/troubleshooting-sql.md | 30 ++++----- .../azure-container-instances.md | 6 +- .../hosting-methods/google-cloud-run.md | 36 +++------- docs/Self-hosting/hosting-methods/linode.md | 65 ++++++------------- docs/Self-hosting/migrations.md | 20 +++--- 6 files changed, 66 insertions(+), 123 deletions(-) diff --git a/docs/References/budibase-architecture.md b/docs/References/budibase-architecture.md index 6b03a72ec..384e4913d 100644 --- a/docs/References/budibase-architecture.md +++ b/docs/References/budibase-architecture.md @@ -10,33 +10,33 @@ metadata: next: description: '' --- -The Budibase architecture comprises of a few key Budibase services and a collection of open source technologies that Budibase is built on top of. +Budibase architecture is made up of a few core services and the open source technologies they depend on. ## Hosted architecture -In this section, we will cover the core services that make up the Budibase self-hosted platform and how this architecture fits together. +This section covers the core services that make up the Budibase self-hosted platform. -1. [App service](https://github.com/Budibase/budibase/tree/master/packages/server) - this is the core of the Budibase infrastructure, the apps service hosts your web apps when they have been deployed as well as providing the REST API that your web apps will use to access/store their data. -2. [Worker service](https://github.com/Budibase/budibase/tree/master/packages/worker) - a small custom Budibase service which currently handles platform security, making sure users attempting to deploy have permission to do so. -3. [Database (CouchDB)](https://couchdb.apache.org) - this is the primary database of Budibase, it is a NoSQL highly scalable and reliable platform which supports simple [data replication](https://docs.couchdb.org/en/stable/replication/protocol.html) and [partitioning](https://docs.couchdb.org/en/stable/partitioned-dbs/index.html). We utilise data replication when deploying apps as well as it being particularly useful for synchronising a cluster for large scale deployments. We partition the CouchDB service into databases specific to each app, meaning we can keep data separated easily and securely. -4. [Object store (MinIO)](https://min.io) - it is possible to store large files in Budibase apps, as well as the apps being built on top of a specific version of the Budibase Client (the Svelte app at the core of every Budibase web app). To store these files we make use of MinIO, which works similarly to AWS S3. -5. [Proxy (NGINX)](https://nginx.com) - To simplify the deployment and usage of the Budibase platform we route all requests through a proxy engine which sits at the front of the Budibase architecture. No service is communicated with directly, this also allows us to load balance the services as the system grows if necessary. -6. [Cache (Redis)](https://redis.io/) - We utilise Redis as a cache store, for information that is commonly accessed such as app metadata. We also store some information about active user sessions in Redis, as these are required with every user request to confirm their identity/authentication. +1. [App service](https://github.com/Budibase/budibase/tree/master/packages/server) - hosts deployed web apps and provides the REST API used to access and store data. +2. [Worker service](https://github.com/Budibase/budibase/tree/master/packages/worker) - handles platform security and checks whether deployment requests are allowed. +3. [Database (CouchDB)](https://couchdb.apache.org) - stores app data and supports [replication](https://docs.couchdb.org/en/stable/replication/protocol.html) and [partitioning](https://docs.couchdb.org/en/stable/partitioned-dbs/index.html). Budibase uses separate databases per app to keep data isolated. +4. [Object store (MinIO)](https://min.io) - stores uploaded files and other large assets. It works similarly to AWS S3. +5. [Proxy (NGINX)](https://nginx.com) - routes requests through a single entry point and can load balance services as the system grows. +6. [Cache (Redis)](https://redis.io/) - stores commonly accessed metadata and active session data. -This architecture will look the same no matter the method of self hosting, all of the above services are required for Budibase to function. +This architecture is the same across self-hosting methods. All of the above services are required. ## Optional architecture -Some services are not included in all installations - they are optional, they may only provide a service which is useful to that particular environment. +Some services are optional and only apply to specific installations. -1. [Updates (Watchtower)](https://containrrr.dev/watchtower/) - For self hosted docker-compose updates Watchtower can be used. This image is only provided in our docker-compose setup and is entirely optional, if you plan to update using the Budibase CLI, or manually this container can be removed. It can be used to perform updates to the Budibase images (app and worker services) via the UI, however if this method is used we recommend checking periodically whether or not your docker-compose scripts require updates as well; watchtower can only update image versions. +1. [Updates (Watchtower)](https://containrrr.dev/watchtower/) - used in the docker-compose setup to update Budibase images. If you update with the Budibase CLI or manually, you can remove this container. ## Web app architecture -Lastly the most important component of Budibase, the apps you make! Each Budibase app is made up of a few core libraries: +Each Budibase app is made up of a few core libraries: -1. [Svelte](https://svelte.dev) - Budibase loves Svelte, and all our web apps at their core are built with Svelte. -2. [Client library](https://github.com/Budibase/budibase/tree/master/packages/client) - as with the builder each Budibase app has a version of the client library that it was built with, this provides the interactivity and data connections you need for your app to function. -3. [Component library](https://github.com/Budibase/bbui) - we want to make it easy to build consistent web apps quickly; for this reason, we provide a core set of components that apps can be built out of - this is included in your app. +1. [Svelte](https://svelte.dev) - the core framework used by Budibase web apps. +2. [Client library](https://github.com/Budibase/budibase/tree/master/packages/client) - provides the interactivity and data connections your app needs. +3. [Component library](https://github.com/Budibase/bbui) - provides the reusable components used to build apps consistently. -Hopefully, this overview has explained how the Budibase platform works, from the builder to your deployed web apps. +This overview shows how the Budibase platform fits together, from the builder to deployed web apps. diff --git a/docs/References/troubleshooting-sql.md b/docs/References/troubleshooting-sql.md index 0498b169a..e23b667c8 100644 --- a/docs/References/troubleshooting-sql.md +++ b/docs/References/troubleshooting-sql.md @@ -10,11 +10,11 @@ metadata: next: description: '' --- -Within this section we will discuss how to troubleshoot issues with your SQL database - this will likely be with the help of a member of the Budibase team. If you are experiencing an issue one of the best ways to resolve it is to raise an [issue on Github](https://github.com/Budibase/budibase/issues/new?assignees=\&labels=bug\&projects=\&template=bug_report.md\&title=). +This section covers common SQL troubleshooting steps. If you need help, raise an [issue on GitHub](https://github.com/Budibase/budibase/issues/new?assignees=\&labels=bug\&projects=\&template=bug_report.md\&title=). ## Minimum SQL versions -Budibase has some core requirements, specifically for searching, that it cannot operate without. For Budibase versions 2.31+ you must be using a minimum version of: +Budibase has minimum database version requirements for search and related features. For Budibase 2.31 and later, use at least: 1. SQL Server - SQL Server 2016 and onwards 2. MySQL - MySQL 8.0 and onwards @@ -22,9 +22,9 @@ Budibase has some core requirements, specifically for searching, that it cannot 4. Oracle - Oracle Database 19c and onwards 5. Postgres - Postgres 9.4 and onwards -This is primarily for aggregate functions and Common Table Expressions (CTE) which are required for Budibase to function. +These requirements are mainly for aggregate functions and Common Table Expressions (CTEs). -Other dialect "compatible" databases may work, but we cannot guarantee support for these in future versions of Budibase. If you need guaranteed support, please reach out to [sales](https://budibase.com/contact/) to discuss options. +Other compatible databases may work, but we cannot guarantee future support. If you need guaranteed support, contact [sales](https://budibase.com/contact/). ## Log SQL queries @@ -32,7 +32,7 @@ Other dialect "compatible" databases may work, but we cannot guarantee support f > > This feature is designed for investigating issues with Budibase accessing data in your SQL database, we recommend only enabling this when needed and disabling in production environments. -It is possible to log the queries that Budibase is sending to your SQL database, to investigate issues or performance problems you're encountering when accessing a database. This can only be enabled in self host environments. To enable this set the environment variable `SQL_LOGGING_ENABLE` to `1` on your app services (docker-compose or Kubernetes) or if using the single image simply supply this environment variable to the container. Once you have restarted the server/container you will see SQL queries being logged in a format like: +You can log the queries Budibase sends to your SQL database to investigate issues or performance problems. This is only available in self-hosted environments. Set `SQL_LOGGING_ENABLE=1` on your app services or on the container if you are using the single image. After restarting, queries are logged in a format like: `[SQL] [PG] query="select * from table limit $1" values="100"` @@ -42,24 +42,18 @@ It is possible to log the queries that Budibase is sending to your SQL database, > > This feature is designed to help the Budibase team resolve issues with your schema - we want to provide the best experience possible for every user out of the box and providing your schema helps to debug issues with typing, relations and other unique scenarios. -In this article we will cover how to export the schema of your database through Budibase - this can be done manually with tools like `pg_dump` for Postgres, but we have provided a tool within Budibase to export what is most helpful when debugging issues. We would also like to highlight that this export is *only* the structure and schema of your tables and does not contain any data; however if you have any sensitive table or column names please discuss this with the Budibase team. +You can export your database schema through Budibase to help debug issues. You can also do this manually with tools such as `pg_dump` for Postgres, but Budibase includes a schema export that is easier to use for support cases. The export contains only table structure and schema, not data. If you have sensitive table or column names, discuss that with the Budibase team. -It is worth noting while the export is a good representation of your data, it is not designed to be used to replicate your data within a production environment, we have designed this to extract the information needed for debugging, not a perfect mirror of the database. +The export is useful for debugging, but it is not intended to reproduce your data in a production environment. ## Exporting your schema -This feature is currently available exclusively for self-hosted instances of Budibase. It is unlikely that this capability will be added to cloud instances of Budibase. +This feature is currently available only for self-hosted instances of Budibase. -To start exporting your schema you will need to click into your database that you are experiencing an issue with. To start, click into the datasource from the "Data" section of the app builder. +To export your schema, open the affected datasource from the Data section of the app builder, then open the datasource **Settings** tab. This is only available for SQL-based datasources. -![](https://files.readme.io/4919ff4-image.png) +Click the download button to export the schema. The export includes all accessible tables, not just the ones imported into Budibase. -Within a datasource you will be able to look at its settings, tables, relationships and queries. Within these options you can select the "Settings" tab of your datasource - this will only be available SQL based datasources. +The resulting file is named something like `PostgresSQL-dump.sql`. You can open it to inspect the schema. -![](https://files.readme.io/4514cb7-image.png) - -From here clicking the download button will trigger a schema export from your database. This will export all of the tables that can be accessed, not necessarily just the ones that are imported into Budibase. - -From here, you will have a file named like `PostgresSQL-dump.sql` - you can open this file see the schema of your tables depicted. - -As above, this does contain all of the tables/columns within your database, we have not edited this in anyway as it could inhibit our ability to debug/discuss with you about your problem. If you do not wish to provide your schema publicly as say part of a Github issue, you can email the schema to [support@budibase.com](mailto:support@budibase.com) including a reference to the issue/discussion that this is related to. \ No newline at end of file +The export includes your table and column names. If you do not want to share it publicly, email it to [support@budibase.com](mailto:support@budibase.com) and include a reference to the issue or discussion. diff --git a/docs/Self-hosting/hosting-methods/azure-container-instances.md b/docs/Self-hosting/hosting-methods/azure-container-instances.md index a366c7718..da89c1743 100644 --- a/docs/Self-hosting/hosting-methods/azure-container-instances.md +++ b/docs/Self-hosting/hosting-methods/azure-container-instances.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -Azure supports several container runtimes including AAS, ACA and ACI. In this guide we will run Budibase on the ACI service persisting data to an Azure Storage Account File Share. The File Share will be a CIFS file share as NFS file shares are not yet supported on Azure. +Azure supports several container runtimes, including AAS, ACA, and ACI. This guide runs Budibase on ACI and stores data on an Azure Storage Account file share. Azure does not yet support NFS file shares here, so this example uses CIFS. Set some environment variables: @@ -68,7 +68,3 @@ az container create ``` If you receive any errors you may want to try substituting the forward slash for a backslash i.e. `/home` becomes `\home` - - - - diff --git a/docs/Self-hosting/hosting-methods/google-cloud-run.md b/docs/Self-hosting/hosting-methods/google-cloud-run.md index 0ed562ea2..cf0599e37 100644 --- a/docs/Self-hosting/hosting-methods/google-cloud-run.md +++ b/docs/Self-hosting/hosting-methods/google-cloud-run.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -[Cloud Run](https://console.cloud.google.com/run) is Google’s managed container service and in this guide we will install Budibase with persistent storage using [Google File Store](https://cloud.google.com/filestore). We will also install using the gcloud cli tool but the console UI could be used as an alternative. +[Cloud Run](https://console.cloud.google.com/run) is Google’s managed container service. This guide installs Budibase with persistent storage using [Google File Store](https://cloud.google.com/filestore) and the `gcloud` CLI. ### Set Global Variables @@ -54,11 +54,11 @@ Next we set the zone for our file store: gcloud config set filestore/zone $ZONE ``` -At this point you may wish to check that billing is enabled for the new project. +Check that billing is enabled for the new project. ### Create the File Store and File Share -The command below will create an NFS file store instance. You may change the storage tier to reduce latency and suit the needs of your audience ([details](https://cloud.google.com/filestore/docs/service-tiers)). +Create an NFS file store instance. You can change the storage tier to suit your latency and capacity needs. See the [service tiers](https://cloud.google.com/filestore/docs/service-tiers) for details. ``` gcloud beta filestore instances create $PROJECT_NAME \ @@ -67,17 +67,9 @@ gcloud beta filestore instances create $PROJECT_NAME \ --network=name="default" ``` -During creation of the file store you may be prompted to enable the file api on your project as shown below: +During creation, you may be prompted to enable the File API on your project. -![](https://files.readme.io/fab6036-image.png) - -After some time you will get confirmation that the file store instance has been created: - -![](https://files.readme.io/393c6a2-image.png) - -The file store configuration may also be viewed in the UI: - -![](https://files.readme.io/0b7f2c0-image.png) +Wait for the file store instance to finish creating before continuing. Next we want to store the IP address of the file store instance to a variable: @@ -91,8 +83,6 @@ Then create a VPC connector: gcloud compute networks vpc-access connectors create $PROJECT_NAME --project $PROJECT_NAME --region $REGION --range "10.8.0.0/28" ``` -![](https://files.readme.io/d6f52b8-image.png) - And next create a service account: ``` @@ -101,7 +91,7 @@ gcloud iam service-accounts create $PROJECT_NAME --project $PROJECT_NAME ### Container Registry -With the file storage configured our next step is to make the Budibase container image available in a registry accessible to the Cloud Run service. Fetch the docker hub image with: +With file storage configured, make the Budibase container image available in a registry accessible to Cloud Run. Fetch the Docker Hub image with: ``` docker pull --platform=linux/amd64 budibase/budibase @@ -113,7 +103,7 @@ Then tag that image with the path to GCR for your project: docker tag budibase/budibase gcr.io/$PROJECT_NAME/budibase/budibase:latest ``` -Next we want to instruct docker to use gcloud for autheticating to GCR : +Next, configure Docker to use `gcloud` for authenticating to GCR: ``` gcloud auth configure-docker @@ -127,7 +117,7 @@ docker push gcr.io/$PROJECT_NAME/budibase/budibase:latest ### Run the Container -With the image available in GCR we can now run the container service. Notice that we are passing in environment variables for the NFS file share IP address and share name. +With the image available in GCR, deploy the container service. Pass the NFS file share IP address and share name as environment variables. ``` gcloud beta run deploy $PROJECT_NAME --image gcr.io/$PROJECT_NAME/budibase/budibase:latest \ @@ -142,11 +132,7 @@ gcloud beta run deploy $PROJECT_NAME --image gcr.io/$PROJECT_NAME/budibase/budib --update-env-vars FILESHARE_IP=$FILESTORE_IP_ADDRESS,FILESHARE_NAME=$FILESHARE_NAME ``` -![](https://files.readme.io/970946b-image.png) - -Allow a few minutes for the service to initialise then visit the Service URL as output by the command above or as found on the UI. - - +Allow a few minutes for the service to initialise, then visit the service URL shown by the command or in the Cloud Run console. ### Cleaning Up @@ -164,6 +150,4 @@ gcloud projects delete $PROJECT_ID ### Troubleshooting -The 'Cloud Run' service **Logs** tab can be used to look out for errors while mounting the file storage or running the app. - - \ No newline at end of file +Use the Cloud Run **Logs** tab to look for errors while mounting the file storage or running the app. diff --git a/docs/Self-hosting/hosting-methods/linode.md b/docs/Self-hosting/hosting-methods/linode.md index 7bd0c1eba..813944985 100644 --- a/docs/Self-hosting/hosting-methods/linode.md +++ b/docs/Self-hosting/hosting-methods/linode.md @@ -13,82 +13,55 @@ next: --- ### Launch Marketplace App -After logging in to your Linode account choose [Marketplace](https://cloud.linode.com/linodes/create?type=One-Click) from the menu. +After logging in to your Linode account, choose [Marketplace](https://cloud.linode.com/linodes/create?type=One-Click) from the menu and select the Budibase app. -Select the Budibase app as shown below: - - - -Scroll down the page to set options for the Budibase app including: +Set the Budibase app options: * **Budibase Port**: The default port is 80 but you can choose another port number if you plan to add a load balancer or proxy in front of your installation * **Select an Image**: The base operating system you would like Budibase installed on. Choose from Debian 11 or Ubuntu 22.04 * **Region**: Choose to launch the app in a region close to your intended audience - - Choose a plan to match your requirements and budget: +Provide a **Linode Label** such as the domain name you plan to use, set a **Root Password**, and add your public **SSH Key** if you want SSH access. - - -Under **Linode Label** provide a useful reference such as the domain name you will use and enter a **Root Password** that can be used if you need to manage your server instance over SSH - - - -Add your public **SSH Key** that can be used if you need to manage your server instance over SSH. There are many guides and videos online demonstrating how to generate SSH keys for your own desktop operating system. - - +The remaining choices are optional. Consider enabling **Backups** if you do not have another backup strategy. -The remaining choices are optional. You may wish to choose to add **Backups** unless you have an alternative backup strategy. +When the options are set, click **Create Linode**. - - -With all the options set, click the '**Create Linode**' button at the bottom of the page: - - - -You will see a summary of your Linode server instance and a status indicating that it is currently provisioning. Please allow a few minutes for the provisioning of the server to complete. +You will see a summary of the server and a status showing that it is provisioning. Wait for provisioning to complete. Note that the summary shows: -* **IP Addresses** of your server ( 139.162.155.223 in the example below ). We will use this IP address in a web browser to display Budibase but if you have already purchased a domain name this would be a good time to use the DNS settings of your domain name provider to add a DNS A record pointing to the IP address you have been provided by Linode. -* **SSH Access** command that you can use from your computer’s command-line terminal to connect to the server - -![](https://files.readme.io/e0f4a8a-image.png) +* **IP Addresses** of your server. Use this IP address in a browser to access Budibase. If you already have a domain name, add a DNS A record that points to this IP address. +* **SSH Access** command you can use from a terminal to connect to the server. -When the status appears as **Running** please allow a further few minutes for the Budibase installation to complete. +When the status is **Running**, wait a few more minutes for the Budibase installation to complete. - +Then open the IP address or domain in a browser to create the initial admin user. -When the server status is shown as **Running** you can visit the IP address (or the domain name if you created a DNS entry) in a web browser to create the initial admin user: - - - -Next login as the admin user to start creating Budibase applications. There are many templates to help you get started and you can learn more about connecting to existing database and building your own custom apps from the Budibase Docs. +Sign in as the admin user to start creating Budibase applications. ### Further Configuration -If you would like to examine the installation you can SSH to the server using the IP address supplied by Linode and the SSH key you provided during the setup. Running `docker ps` should display the list of docker containers that run Budibase: - -![](https://files.readme.io/71466bd-image.png) +If you want to inspect the installation, SSH to the server using the IP address and SSH key you provided during setup. Running `docker ps` shows the Budibase containers. -You may wish to examine the files under `/opt/budibase` +You may wish to examine the files under `/opt/budibase`. -* `docker-compose.yml` Use this file for future management/customisation of your budibase install -* `.env `The .env file contains the passwords used to access various budibase components. +* `docker-compose.yml` Use this file for future management or customisation of your Budibase install. +* `.env` The `.env` file contains the passwords used to access various Budibase components. ### SMTP -By default Linode will block connections to external SMTP ports to reduce abuse by spammers. You will need to open a support ticket with Linode to unblock your Linode server if you want to send emails via an SMTP server. +By default, Linode blocks connections to external SMTP ports. Open a support ticket with Linode if you need SMTP access. ### Backups -Backing up your data is beyond the scope of this introduction but you should investigate storing regular copies of your docker volumes stored under `/var/lib/docker/volumes` +Backing up your data is beyond the scope of this introduction, but you should store regular copies of your Docker volumes under `/var/lib/docker/volumes`. ### Security -Server security is beyond the scope of this introduction but you should investigate methods to secure your server by regularly applying operating system updates with: `apt update && apt upgrade` You should also add a firewall and intrusion prevention utilities such as fail2ban. +Server security is beyond the scope of this introduction, but you should regularly apply operating system updates with `apt update && apt upgrade`. You should also add a firewall and intrusion prevention tools such as fail2ban. ### HTTPS -Although beyond the scope of this introduction there are a variety of ways to add a certificate to your installation including using a Linode NodeBalancer or Cloudflare. There is also the possibility of using Let’s Encrypt certbot on the server and configuring an nginx proxy listening on port 443 to proxy traffic to your Budibase container. \ No newline at end of file +Although beyond the scope of this introduction, there are several ways to add HTTPS, including Linode NodeBalancer, Cloudflare, or Let’s Encrypt with an NGINX proxy on port 443. diff --git a/docs/Self-hosting/migrations.md b/docs/Self-hosting/migrations.md index 7e938f8e4..d209fbd9b 100644 --- a/docs/Self-hosting/migrations.md +++ b/docs/Self-hosting/migrations.md @@ -10,19 +10,15 @@ metadata: next: description: '' --- -Occasionally as part of a Budibase update we will need to make an update to the infrastructure which is used by the platform - in self host this can impact you. +Budibase updates sometimes require infrastructure changes. In self-hosted installations, those changes can affect your deployment. -Budibase will warn you that your installation is not up to date/is missing components of the infrastructure, this warning will look like: - -Your installation requires an upgrade - Your installation requires an upgrade - +Budibase will warn you if your installation is missing required infrastructure components. Below is a list of migrations which may be needed for your installation. ## Budibase DB SQL Support -If you have reached this page then you have been alerted to an issue with your self-host installation. As of version 2.33.0, Budibase relies on a service called the Structured Query Server ([SQS](https://neighbourhood.ie/products-and-services/structured-query-server)). This runs alongside CouchDB to provide relational searching functionality. +If you have reached this page, your self-hosted installation needs an update. As of version 2.33.0, Budibase relies on the Structured Query Server ([SQS](https://neighbourhood.ie/products-and-services/structured-query-server)) running alongside CouchDB to provide relational search. Below is what's required for each installation method to get SQS running. @@ -32,9 +28,9 @@ If you are using any of the [single image/docker install methods](/docs/docker) ### `docker-compose` -You need to update your `docker-compose.yaml` file - the quickest way to do this is using the [Budibase CLI](/docs/updating-budibase#budibase-cli-docker-compose). If you would prefer to do this manually then you will need to make sure your CouchDB installation is using the latest version of the `budibase/couchdb` image. This image runs SQS for you. +Update your `docker-compose.yaml` file. The quickest way is to use the [Budibase CLI](/docs/updating-budibase#budibase-cli-docker-compose). If you update manually, make sure your CouchDB service uses the latest `budibase/couchdb` image, which includes SQS. -You will also need to set a new environment variable called `TARGETBUILD`. Here's how your `couchdb-service` block in your `docker-compose.yaml` file should look: +You also need to set the `TARGETBUILD` environment variable. Your `couchdb-service` block should look like this: ```yaml docker-compose.yaml couchdb-service: @@ -50,9 +46,9 @@ couchdb-service: ### Kubernetes -You will need to make sure you are using the latest version of the Budibase Helm chart alongside the latest version of the Budibase images. **If your upgrade workflow for Kubernetes involves just updating image tags in your`values.yaml` file, this will break your installation.** +Make sure you are using the latest version of the Budibase Helm chart and the latest Budibase images. Updating only the image tags in `values.yaml` will break the installation. -If you followed the steps in [Kubernetes](doc:kubernetes-k8s), you'll need to run the following commands to update your Helm chart. +If you followed the steps in [Kubernetes](doc:kubernetes-k8s), run the following command to update your Helm chart. ```shell helm upgrade -n budibase budibase oci://ghcr.io/budibase/charts/budibase @@ -60,4 +56,4 @@ helm upgrade -n budibase budibase oci://ghcr.io/budibase/charts/budibase *** -If you are still having issues and have confirmed that your installation is running the latest `budibase/couchdb` image for your CouchDB service then please reach out to Budibase support for further help, in the meantime you can downgrade to the previously used version safely. \ No newline at end of file +If you are still having issues after confirming that your CouchDB service uses the latest `budibase/couchdb` image, contact Budibase support. You can safely downgrade to the previous version in the meantime. From 69f55998e775227838730b169ccd5ecc0f144660 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 13:01:44 +0100 Subject: [PATCH 17/32] batched update --- docs/AI/agent-building-101.md | 42 ++++----- docs/Automation/automation-actions/discord.md | 93 ++++++------------- .../automation-actions/slack-notification.md | 2 +- docs/Automation/trigger/cronjob.md | 52 ++++------- .../examples-and-guides/public-form.md | 30 +++--- docs/References/feature-flags.md | 10 +- 6 files changed, 88 insertions(+), 141 deletions(-) diff --git a/docs/AI/agent-building-101.md b/docs/AI/agent-building-101.md index f5bc408ec..0a112b89c 100644 --- a/docs/AI/agent-building-101.md +++ b/docs/AI/agent-building-101.md @@ -6,16 +6,16 @@ metadata: description: kba_5v2bm robots: index --- -In Budibase, Agents enable AI to interact with the data, tools, and automations in your Workspace. +In Budibase, Agents let AI interact with data, tools, and automations in your Workspace. -In this guide, we’ll build a simple AI Service Desk Agent that can: +In this guide, you will build a simple AI Service Desk Agent that can: * Answer questions about tickets * Categorise and summarise new tickets * Update ticket statuses * Escalate urgent issues automatically -Along the way, we’ll learn how to: +Along the way, you will learn how to: * Configure an Agent’s instructions * Connect Workspace data as tools @@ -23,8 +23,6 @@ Along the way, we’ll learn how to: * Trigger automations from Agent actions * Test and iterate safely -Let’s jump in. - ## Before you start Make sure you have: @@ -49,15 +47,15 @@ Make sure you have: ### Setting up our data layer -In Budibase, Agents can interact with any tables, API calls, or automations within your Workspace, as long as they’re explicitly given access. +In Budibase, Agents can interact with any tables, API calls, or automations within your Workspace, as long as they are explicitly given access. -Before creating an Agent, it’s important to understand the data it will work with and define what actions it should be allowed to perform. +Before creating an Agent, define the data it will work with and the actions it should be allowed to perform. -Take a look at our [Introduction to Data ](https://docs.budibase.com/docs/data) documentation to learn more about how data works in Budibase. +See [Introduction to Data](https://docs.budibase.com/docs/data) for more detail on how data works in Budibase. #### Our tickets table -For this guide, we’ll use a Budibase DB table called Tickets. +For this guide, use a Budibase DB table called Tickets. This contains the following columns: @@ -74,20 +72,20 @@ This contains the following columns: ### Creating our agent -Onto creating our first Agent. Make sure you have done the initial setup of selecting a provider and configuring a model before doing this. You can find out how to do this [here](doc:agents-config). +To create your first Agent, make sure you have selected a provider and configured a model first. See [Agents config](doc:agents-config). 1. Click on the **Agents** link on the left side of the screen 2. Click the **+ New Agent** button at the top right of your screen -3. Provide a name. We're going with **Service Desk Agent** +3. Provide a name. This guide uses **Service Desk Agent** 4. This will redirect you to a new screen specifically for your Agent ### Configuring instructions -Before configuring instructions, ensure your Agent is connected to an LLM. If you haven’t done this yet, click Connect AI Model at the top of the screen. Alternatively, if you have already set this up, select the LLM you are using. More information on connecting an LLM can be found [here](doc:agents-config). +Before configuring instructions, ensure your Agent is connected to an LLM. If you have not done this yet, click **Connect AI Model** at the top of the screen. If you have already set this up, select the LLM you are using. See [Agents config](doc:agents-config) for more detail. -By default, Budibase provides a structured instruction template to help you define your Agent clearly. More information on this can be found [here](doc:agent-instructions-guide#recommended-template). +By default, Budibase provides a structured instruction template to help you define your Agent clearly. See [Agent instructions guide](doc:agent-instructions-guide#recommended-template) for more detail. -For now we will use the below instructions: +Use the following instructions for this guide: ```markdown instructions **Agent role** @@ -119,13 +117,13 @@ When categorising or prioritising, return structured JSON: - Use British English where possible ``` -After configuring and adding the above instructions, run a test and confirm that everything is working. +After adding the instructions, run a test and confirm that everything works. ### Adding tools Tools allow an Agent to retrieve and modify real data inside your Workspace. -When you connect data sources to an Agent, Budibase automatically makes relevant operations available as tools. As your Workspace grows, your Agent can be granted access to more tools, but it’s important to only enable what’s necessary for the task. +When you connect data sources to an Agent, Budibase automatically makes relevant operations available as tools. As your Workspace grows, you can grant access to more tools, but only enable what you need for the task. For this example, we’ll give our Agent access to three tools from the Tickets table: @@ -139,13 +137,13 @@ Together, these allow the Agent to: * Retrieve specific ticket details * Update ticket status, priority, or resolution notes when required -> As a best practice, only enable the minimum set of tools required. Limiting tool access helps ensure predictable and safe behaviour. +> As a best practice, only enable the minimum set of tools required. Limiting tool access helps keep behaviour predictable and safe. #### Updating our instructions -Once these tools are enabled, Budibase injects them into the Agent’s execution context. We now need to guide the Agent on when to use them. +Once these tools are enabled, Budibase injects them into the Agent’s execution context. You then need to guide the Agent on when to use them. -Here is our updated instruction prompt: +Use the following updated instruction prompt: ```markdown instructions **Agent role** @@ -188,7 +186,7 @@ Optionally, test again with some data and see how it handles the process. ### Managing multiple operations -As your agent grows more complex, you can define multiple **Operations**, each with its own niche instructions and set of tools. +As your agent grows more complex, you can define multiple **Operations**, each with its own instructions and set of tools. When an agent has multiple live operations, Budibase uses an internal router to detect the intent of the user's request. It will: - **Select a specific operation** if the request clearly matches one operation's focus. @@ -199,7 +197,7 @@ You do not need to manually configure this routing; it is handled automatically ### Testing the agent -Now that our Agent has instructions and tools, we can test whether it behaves safely and predictably. +Now that your Agent has instructions and tools, you can test whether it behaves safely and predictably. Start with a few representative prompts: @@ -254,4 +252,4 @@ Once this foundation is working, use these guides to improve quality and safety: * [Agent embedding models](doc:agent-embedding-models) * [Agent vector databases](doc:agent-vector-databases) * [Agent testing guide](doc:agent-testing-guide) -* [Agent troubleshooting](doc:agent-troubleshooting) \ No newline at end of file +* [Agent troubleshooting](doc:agent-troubleshooting) diff --git a/docs/Automation/automation-actions/discord.md b/docs/Automation/automation-actions/discord.md index c0d63f7fa..02b612e2a 100644 --- a/docs/Automation/automation-actions/discord.md +++ b/docs/Automation/automation-actions/discord.md @@ -1,6 +1,6 @@ --- title: Discord -excerpt: This tutorial will help you add a Discord automation to your Budibase app. +excerpt: Add Discord notifications to your Budibase automations. deprecated: false hidden: false metadata: @@ -10,7 +10,7 @@ metadata: next: description: '' --- -The Discord notification is a webhook that allows you to send notifications from your Budibase app to a Discord channel. +The Discord notification is a webhook that sends messages from your Budibase app to a Discord channel. ## Settings @@ -36,16 +36,9 @@ The Discord [Action](doc:automation-actions) has four settings: - Add your Discord Webhook URL. + Add your Discord Webhook URL. - To find your Discord Webhook URL: - - * Open your Server Settings and head into the Integrations tab. - * Navigate to the Webhooks section and either View Webhooks or Create a new webhook. - - Further information and directions on how to find your Discord webhook URL: - - [https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) + To find the URL, open Server Settings, go to Integrations, and open the Webhooks section. You can then view an existing webhook or create a new one. @@ -55,7 +48,7 @@ The Discord [Action](doc:automation-actions) has four settings: - Copy the name of your bot from Discord + Copy the name of your bot from Discord. @@ -65,11 +58,7 @@ The Discord [Action](doc:automation-actions) has four settings: - To give your bot an avatar, add your image link to the Bot Avatar field. For example: - - [https://res.cloudinary.com/daog6scxm/image/upload/v1632818347/logo/budibase-icon-500\_svrfwf.png](https://res.cloudinary.com/daog6scxm/image/upload/v1632818347/logo/budibase-icon-500_svrfwf.png) - - On Discord, the avatar size is 128 x 128 pixels. However, you'll actually want to upload a larger square image. Discord will automatically scale your image down to the appropriate dimensions, but you'll retain high-quality resolution in the process. + Add an image URL to the Bot Avatar field if you want a custom avatar. Discord scales the image automatically, so use a larger square image for best results. @@ -79,7 +68,7 @@ The Discord [Action](doc:automation-actions) has four settings: - The content you would like to send to your Discord channel when your automation is triggered. + The content you want to send to your Discord channel when your automation is triggered. @@ -93,68 +82,46 @@ The Discord [Action](doc:automation-actions) has four settings: ## Tutorial - When a new record is added, send a Discord notification -The following tutorial will demonstrate how to send a Discord notification when a new record is created. We will assume you have your data setup and design screens built. If you don't, check out the [Quickstart: Budibase DB](doc:build-a-crud-app). +This tutorial shows how to send a Discord notification when a new record is created. It assumes your data and screens are already set up. If not, see the [Quickstart: Budibase DB](doc:build-a-crud-app). Our Discord notification automation will consist of two automation blocks: 1. Trigger - Row created 2. Action - Discord notification -Click the add automation icon. - - - -  - ### Add Trigger - Row created -Give your new automation a name - we will name ours `Discord notification`. Select the 'Row Created' trigger. Then click 'Save'. +Give your new automation a name. This example uses `Discord notification`. Select the `Row Created` trigger, then click `Save`. - - -Now click the Row created automation a side panel on the right will appear, and select your table - in our case Sales. - -{597} - trigger setup - +Open the `Row created` automation and select your table. In this example, the table is `Sales`. ### Add Action - Discord -Now click the small plus icon button under the Trigger automation step, select Discord, then click Save. - -{1200} - Add discord action to budibase - +Click the small plus icon under the Trigger automation step, select Discord, then click `Save`. -Now it's time to set up our Discord action. If you don't have a Discord channel, [please set one up](https://discord.com/blog/starting-your-first-discord-server#:~:text=To%20make%20a%20new%20channel,and%20choose%20%E2%80%9Ccreate%20channel.%E2%80%9D). +Now set up the Discord action. If you do not have a Discord channel, create one first. #### Get your incoming Webhook -Open your Server Settings and head into the Integrations tab. Click on View Webhooks, select your Webhook, and click 'Copy Webhook Url'. - -![](https://files.readme.io/6449cc6-CleanShot_2022-04-27_at_12.16.062x.png "CleanShot 2022-04-27 at 12.16.06@2x.png") +Open your Server Settings, go to the Integrations tab, open Webhooks, select your webhook, and click `Copy Webhook Url`. #### Create a new Discord Webhook -If you don't have a Webhook to connect to, click the "Create Webhook" button to create a new webhook. +If you do not have a webhook yet, click `Create Webhook`. -You'll have a few options here. You can: +You can: * **Edit the avatar:** By clicking the avatar next to the Name in the top left * **Choose what channel the Webhook posts to:** By selecting the desired text channel in the dropdown menu * **Name your Webhook:** Good for distinguishing multiple webhooks for multiple different services. -Discord will generate you a webhook. Click the 'Copy Webhook URL' button. - -![](https://files.readme.io/dad41fa-CleanShot_2022-04-27_at_12.15.162x.png "CleanShot 2022-04-27 at 12.15.16@2x.png") +Discord will generate a webhook. Click `Copy Webhook URL`. -Paste your Discord Webhook URL into the Discord Webhook Url input within your [Action](doc:automation-actions) automation step. +Paste your Discord Webhook URL into the Discord Webhook URL input in the [Action](doc:automation-actions) step. -In the Bot name field, add the name of your Bot. We've not got an avatar, so we'll leave the Bot avatar field blank. +In the Bot name field, add the name of your bot. Leave the Bot avatar field blank if you do not want one. - - -In the Message input, add the message you would like Budibase to post to your Budibase channel when a new row is created. You can bind values from the newly created record to your message. For our use case, I want to send the following notification to our channel: +In the Message input, add the message Budibase should post when a new row is created. You can bind values from the new record. In this example, use: ```handlebars We just made a new sale in {{ trigger.row.Country }} @@ -163,30 +130,24 @@ Check out the sale using the link below: https://joe.budibase.app/app/tutorials#/sales/{{ trigger.id }} ``` -From the above, you can see I have used automation [bindings](doc:bindings) to pull data into our message. Check out the following documentation to learn more about how to use [Data in automations](doc:contextual-bindings). - - +The example uses automation [bindings](doc:bindings) to pull data into the message. For more detail, see [Data in automations](doc:contextual-bindings). #### Trigger output bindings - Trigger.Row -To pull data from your Trigger record, you can use Trigger Output helpers (see Gif above). Using the helper `trigger.row` I now have access to that data from our newly created record. I add the field/column title to the binding to pull a specific field back: `trigger.row.Country`. +To pull data from your trigger record, use `trigger.row`. Add the field or column name to the binding to target a specific value, such as `trigger.row.Country`. -To allow users to access the specific record page, we must add a link to our message. +To let users open the specific record page, add a link to the message. -**To create a link, we must first Publish our application.** Save the automation, click the Publish app button. Now, go back to the app portal page (Click the Budibase icon). Locate your app, click the more icon, and click View published app. Copy your base URL - We will improve this experience soon. +To create a link, publish the application first. Save the automation, click `Publish app`, open the published app, and copy the base URL. #### Trigger output bindings - Trigger.ID -Now, click into your app and go back to the automation we were just creating and into the message section (where we were above). Paste your URL, and append it with the Trigger ID output. Click Save. +Go back to the automation message, paste your base URL, append the Trigger ID output, and click `Save`. ### Test automation -Click `Finish and test automation`. **Then select your table from the dropdown.** - - - -In the Column/Field you referenced in your trigger.row binding above (we used Country), add a value - we'll add `Budiland` to the 'Country field'. Click 'Test'. You should now see a message on your Discord channel. +Click `Finish and test automation`, then select your table from the dropdown. -If you are happy, click 'Publish app'. Add a new record within your app, and like magic, watch as a new Discord notification appears within your channel. +In the column or field you referenced in your `trigger.row` binding, add a value. This example uses `Budiland` in the `Country` field. Click `Test` to send a message to your Discord channel. -![](https://files.readme.io/839f2a1-CleanShot_2022-04-27_at_12.25.212x.png "CleanShot 2022-04-27 at 12.25.21@2x.png") +If everything looks correct, click `Publish app`. Add a new record in your app and confirm that a Discord notification appears in your channel. diff --git a/docs/Automation/automation-actions/slack-notification.md b/docs/Automation/automation-actions/slack-notification.md index bf93ae5d8..d947f16cd 100644 --- a/docs/Automation/automation-actions/slack-notification.md +++ b/docs/Automation/automation-actions/slack-notification.md @@ -1,6 +1,6 @@ --- title: Slack -excerpt: This tutorial will help you add a Slack automation to your Budibase app. +excerpt: Add Slack notifications to your Budibase automations. deprecated: false hidden: false metadata: diff --git a/docs/Automation/trigger/cronjob.md b/docs/Automation/trigger/cronjob.md index a62111432..80080901e 100644 --- a/docs/Automation/trigger/cronjob.md +++ b/docs/Automation/trigger/cronjob.md @@ -10,21 +10,19 @@ metadata: next: description: '' --- -The schedule trigger is ideal for periodically running queries, fetching data, or even sending emails. +The schedule trigger is ideal for periodically running queries, fetching data, or sending emails. -For this guide, we will fetch the Stargazer count of a GitHub repository every working day at 9 a.m. and send a Discord notification. +This guide fetches the Stargazer count of a GitHub repository every working day at 9 a.m. and sends a Discord notification. ## Creating the automation -To create an automation with the schedule trigger, head over to the Automation Section and create a new Automation by clicking the `+` icon in the left-hand menu. A dialog will pop up, in which you can enter the name of your automation, and you can select the `Schedule` trigger. +To create an automation with the schedule trigger, go to the Automation section and create a new automation by clicking the `+` icon in the left-hand menu. Enter a name and select the `Schedule` trigger. - - -Then, click `Save`, and a new automation will be created using a `Schedule Trigger`. +Then click `Save` to create the automation. ## Configuring the schedule -The schedule trigger provides several ways to define when your automation should run. You can choose from a variety of presets or provide a custom cron expression. +The schedule trigger provides several ways to define when your automation should run. You can choose from presets or provide a custom cron expression. ### Period @@ -38,15 +36,15 @@ You can select the frequency of your schedule using the **Period** dropdown: ### Timezone -By default, schedules use **UTC**. You can select a specific timezone (e.g., `Europe/London`, `America/New_York`) to ensure your automation runs at the correct local time, accounting for daylight savings shifts automatically. +By default, schedules use **UTC**. You can select a specific timezone, such as `Europe/London` or `America/New_York`, to run at the correct local time. ### Next Executions -The configuration panel displays a list of the next four scheduled execution times in your selected timezone. This helps you verify that your schedule is configured correctly. +The configuration panel displays the next four scheduled execution times in your selected timezone. ## Advanced: Cron expressions -If you select the **Cron expression** period, you can enter a series of numbers or stars. The order is from small to big: +If you select the **Cron expression** period, you can enter a series of numbers or stars. The order is from smallest to largest: * Minutes * Hours @@ -54,11 +52,11 @@ If you select the **Cron expression** period, you can enter a series of numbers * Month * Day of the Week -We have presets available within the cron builder that can be selected to generate a cron expression for you. Additionally, for Premium or Enterprise tenants, you can use the AI assistant to generate expressions from a natural language prompt. +The cron builder includes presets that can generate an expression for you. For Premium or Enterprise tenants, you can also use the AI assistant to generate expressions from a natural language prompt. -Cron Scheduling can be very powerful, but you'll need to understand syntax. For every field, you can use the following expressions: +Cron scheduling can be powerful, but you need to understand the syntax. For every field, you can use the following expressions: -* **Plain numbers**: From 0 to 59 for minutes, 0-23 for hours, and 1-12 for Months. +* **Plain numbers**: From 0 to 59 for minutes, 0-23 for hours, and 1-12 for months. * **Ranges**: `5-10` in the minutes section would mean every minute from the 5th until the 10th minute. * **Separations**: Multiple numbers or ranges, like `4,8,12` in the months column would be the 4th, 8th and 12th month only. Separations can also have ranges, such as `5-10,35-40` in the minutes column, which would be every minute between the 5th and 10th minute, and every minute between the 35th and 40th minute. * **A `*`**: This means `every`. So if you have only stars everywhere, that means every minute, of every hour, of every day of every month. @@ -68,25 +66,19 @@ Example: To run a job every working day at 3 a.m. UTC, you would use the followi ## Timestamp binding A binding is available for the timestamp of when the schedule job was triggered. -This returns the number of
epoch milliseconds - - +This returns the number of epoch milliseconds. ## Performing an API call -Now that we've set up our `Schedule Trigger`, it is time to perform a REST call to fetch some information. For this tutorial, we've created a new [REST API](doc:rest) Data Source, added [Bindings](doc:rest-bindings) to the API call to allow customization, and we've set up a [Transformer](doc:transformers) to turn the data into quick, usable data. But you can set up whatever you want here, even regular queries to Data Sources. +Now that you have set up the `Schedule Trigger`, perform a REST call to fetch some information. For this tutorial, create a new [REST API](doc:rest) data source, add [Bindings](doc:rest-bindings) to the API call, and set up a [Transformer](doc:transformers) to turn the data into usable output. You can also use regular queries to Data Sources. -If you want to read more about setting up a REST API, Bindings, and Transformers, we recommend checking out the linked pages. +If you want to read more about REST APIs, bindings, and transformers, see the linked pages. We end up with something like this: - - -When running a test you can see the API call and the transformer worked as expected, and it returns the stargazer count of the Github repository of choice. +When you run a test, you can see the API call and transformer return the stargazer count for the chosen GitHub repository. - - -For reference, we've transformed the result from the public Github Search API like this: +For reference, the result from the public GitHub Search API is transformed like this: ```javascript return data.items[0].stargazers_count @@ -94,18 +86,14 @@ return data.items[0].stargazers_count ## Using the data -Now we have a scheduled trigger and an API call is done at that exact time. The only thing that remains is using the result of the API call. For this purpose, we're going to be firing a Discord notification. - -First, we're retrieving a DIscord Webhook URL, setting the botname, optionally add a nice profile picture, and then set the binding to display the number of stars. +Now that the scheduled trigger runs the API call, use the result to send a Discord notification. - +First, retrieve a Discord Webhook URL, set the bot name, optionally add a profile picture, and then set the binding to display the number of stars. -As you can see, we formulated a nice message, and used the `value` from the API call from `step 1`. Our binding ends up to look like this: +The message uses the `value` from the API call in `step 1`. The binding looks like this: ```handlebars You now have {{ steps.External Data Connector.response }} stargazers ``` -And this works, because our Discord bot just sent this message - - \ No newline at end of file +That works because the Discord bot sends the message. diff --git a/docs/Getting started/examples-and-guides/public-form.md b/docs/Getting started/examples-and-guides/public-form.md index b0e295457..2cbfcdca8 100644 --- a/docs/Getting started/examples-and-guides/public-form.md +++ b/docs/Getting started/examples-and-guides/public-form.md @@ -23,7 +23,7 @@ next: ## Scenario -This is for situations where you want to collect data from unauthenticated users, but want to keep your table secure so that only App admins can see the submitted data. With the release of Budibase 3.0, table RBAC has been streamlined, so we'll use automations to write this data securely to the table. It's ideal for public forms like surveys where a user submits data and doesn't ever have to see it again. +Use this pattern when you want to collect data from unauthenticated users but keep the table secure so only app admins can see the submitted data. Budibase 3.0 streamlined table RBAC, so this guide uses an automation to write form data securely to the table. It is a good fit for public forms such as surveys. {` Challenge:
@@ -34,36 +34,36 @@ This is for situations where you want to collect data from unauthenticated users ## Steps -1. In the Data section, create a **new table** with columns for the data you want to capture. By default, only App admins can access this table, which is fine for our example. +1. In the Data section, create a **new table** with columns for the data you want to capture. By default, only app admins can access this table, which is fine for this example. -2. In the newly created app, create a **new screen** for your form -3. Set the screen's **Access** to `Public user` -4. Build a **Form** with field components that suit your table's schema. +2. In the new app, create a **new screen** for your form. +3. Set the screen's **Access** to `Public user`. +4. Build a **Form** with field components that match your table's schema. > ℹ️ Generating fields from the Form Schema > -> You can use your table as the Form Schema to generate the relevant field components in a Field Group, but please note that a public user won't have access to that schema, so they may see errors when using the app. Once you have created your form fields, switch the Form Schema to Custom to prevent any issues for public users. +> You can use your table as the Form Schema to generate the relevant field components in a Field Group, but a public user will not have access to that schema, so they may see errors when using the app. After you create the form fields, switch the Form Schema to Custom to prevent issues for public users. -5. In the Automation section, create a **new automation** that is triggered by an *App Action* +5. In the Automation section, create a **new automation** triggered by an *App Action*. -6. **Change the role** for this automation to `Public user` -7. **Add fields** that match the fields in your form +6. **Change the role** for this automation to `Public user`. +7. **Add fields** that match the fields in your form. -8. **Add a Create Row step** to the automation -9. Select the relevant table and use the relevant bindings from your automation trigger for each column value +8. **Add a Create Row step** to the automation. +9. Select the relevant table and use the bindings from your automation trigger for each column value. -10. Go back to your screen in the Data section and add a **Button component,** which we'll use to submit your form -11. **Add a*Trigger Automation* On click action** to the Button that triggers the automation we made -12. **Add bindings** from your Form fields to send them to the automation +10. Go back to your screen in the Data section and add a **Button component** to submit your form. +11. **Add a Trigger Automation** On click action to the Button and select the automation you created. +12. **Add bindings** from your form fields to send them to the automation. -13. **Publish the app** and test the public form in a private window +13. **Publish the app** and test the public form in a private window.
diff --git a/docs/References/feature-flags.md b/docs/References/feature-flags.md index 366514434..269113088 100644 --- a/docs/References/feature-flags.md +++ b/docs/References/feature-flags.md @@ -7,10 +7,10 @@ metadata: description: kba_5hjpe robots: index --- -We release features behind feature flags, before they are generally available. +We release some features behind feature flags before they are generally available. - Flagged features are still under development. We cannot guarantee their stability and they are subject to change. We recommend that you use them in a test environment. Proceed at your own risk! + Flagged features are still under development. They may change and are not guaranteed to be stable. Use them in a test environment. ## Enabling a feature flag on self-host @@ -31,11 +31,11 @@ Copy this line exactly. This will pass the value from the `.env` file, into your ## Enabling a feature flag on Budibase Cloud -We will need to enable this from our end. Contact [support@budibase.com](mailto:support@budibase.com). Make sure to include +We need to enable this from our side. Contact [support@budibase.com](mailto:support@budibase.com) and include: * The name of the feature flag that you'd like enabled. * The URL of your Budibase tenant. -We cannot guarantee that we will enable the feature on your account - we will consider on a case-by-case basis. +We cannot guarantee that we will enable the feature on your account. We review requests case by case. -
\ No newline at end of file +
From d59f832adfa5a551ab85f483cdbf96b3539ea751 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Tue, 14 Jul 2026 14:03:54 +0100 Subject: [PATCH 18/32] more batched updates --- .../automation-building-101.md | 108 ++++++------------ .../snippets/time-ago-snippet-function.md | 20 ++-- docs/Bindings/url-parameters.md | 37 +++--- docs/Data/transformers.md | 56 ++++----- 4 files changed, 79 insertions(+), 142 deletions(-) diff --git a/docs/Automation/automation-steps/automation-building-101.md b/docs/Automation/automation-steps/automation-building-101.md index 70a29db00..1670213cd 100644 --- a/docs/Automation/automation-steps/automation-building-101.md +++ b/docs/Automation/automation-steps/automation-building-101.md @@ -10,73 +10,57 @@ metadata: next: description: '' --- -Budibase Automations are defined workflows that can be triggered by user actions, system events, database operations, or incoming HTTP requests. +Budibase automations are defined workflows that can be triggered by user actions, system events, database operations, or incoming HTTP requests. -When triggered, we can use Automations to apply logic, process data, and take actions within Budibase or across integrated platforms. +When triggered, automations can apply logic, process data, and take actions within Budibase or across integrated platforms. -Automations can be used within end-user applications or as standalone solutions for systematically carrying out tasks using connected data. +Automations can be used in end-user applications or as standalone workflows for connected data. -In this guide, we’ll be outlining how to create a simple automation rule for generating and sending a weekly sales report email. +This guide shows how to create a simple automation rule for generating and sending a weekly sales report email. -Along the way, we’ll outline the basics of working with triggers and actions, as well as seeing different examples of how we can utilize data within Budibase Automations. You can take a look at our [Introduction to Automations](https://docs.budibase.com/docs/automation-steps) docs to start learning about triggers, actions, and data in more depth. +Along the way, you will learn the basics of triggers and actions, with examples of how to use data in automations. For more detail, see [Introduction to Automations](https://docs.budibase.com/docs/automation-steps). -To do this, we’ll: +To do this, you will: * Create a CRON trigger to run our automation rule at a specified time each week. * Send a REST request to retrieve the sales data for the relevant time period. * Call an LLM to extract and format our required data. * Send the output of this to the required colleagues using an email action. -Let’s get started. - ## Creating a new automation rule and defining a trigger -We’re starting in the `Automations` section of our Budibase Workspace. Here, we’re prompted to create our first Automation. - - - -When we choose this option, we’re prompted to give our new rule a name and choose a trigger. We’re calling it `Sales Report Generator` and selecting `CRON/Schedule` from the list of available triggers. +Start in the `Automations` section of your Budibase Workspace. There, you are prompted to create your first automation. - +Choose a name for the new rule and select a trigger. This guide uses `Sales Report Generator` and `CRON/Schedule`. -The `CRON/Schedule` trigger accepts a single argument called `CRON expression`, as well as giving us the option to use a preset. +The `CRON/Schedule` trigger accepts a single `CRON expression` and also gives you the option to use a preset. -We want to configure our Automation to run every Monday at 9 AM, so we’re using `0 9 * * 1`. - - +Configure the automation to run every Monday at 9 AM using `0 9 * * 1`. ## Populating and sending a REST request -Next, we want to add an automation action to send a predefined REST request. As you can see below, we’ve already set this up in the Data section of our Workspace. - -This will send a `POST` request with two bindings called `startDate` and `endDate`. +Next, add an automation action to send a predefined REST request. In this example, it is already set up in the Data section of the Workspace. -We’ll use these to dynamically add values to the request body, so that the right time period is selected when we send our request from the Automation section. +This sends a `POST` request with two bindings called `startDate` and `endDate`. - +Use these to dynamically add values to the request body so the correct time period is selected. -To learn more, check out our documentation page on working with [REST data sources](https://docs.budibase.com/docs/rest). +For more detail, see [REST data sources](https://docs.budibase.com/docs/rest). -Back in the Automation section, we’ll add an `API Request` action and choose our `Sales Report` endpoint. +Back in the Automation section, add an `API Request` action and choose the `Sales Report` endpoint. - +In Budibase, each automation action can use data from previous steps. Use that data as bindable values with Handlebars or JavaScript expressions. -In Budibase, individual automation actions are exposed to all data outputs from previous steps. We can use this data as bindable values, with either Handlebars or JavaScript expressions. +Click the lightning bolt icon to assign values to the two bindings. -We’ll hit the lightning bolt icon to assign values to our two bindings. - - - -For our `endDate`, we’ll use the following JavaScript to return the current date and time. +For `endDate`, use the following JavaScript to return the current date and time. ```javascript var date = new Date() return date ``` - - -For `startDate`, we’ll use a similar expression, returning seven days before the current date. +For `startDate`, use a similar expression that returns seven days before the current date. ```javascript var date = new Date(); @@ -84,39 +68,31 @@ date.setDate(date.getDate() - 7); return date; ``` -When we run a test, we can see that our API request returns an array of objects containing the sales figures for individual locations, along with their respective targets. +When you run a test, the API request returns an array of objects containing the sales figures for each location and its target. ## Calling an LLM for data processing -Now that we have our raw data, we’re going to use an LLM prompt to extract and format key details, ready to include in an email automation. - -We’re going to use Budibase AI to power this, although we could also connect another provider through **Connections > AI models**. - -Learn more about [Budibase AI](doc:quickstart-budibase-ai). +Now that you have the raw data, use an LLM prompt to extract and format the key details for the email automation. -We’ll start by adding an `LLM Prompt` automation step. +This example uses Budibase AI, but you can also connect another provider through **Connections > AI models**. - +See [Budibase AI](doc:quickstart-budibase-ai) for more detail. -This accepts a single argument, called `Prompt`. +Start by adding an `LLM Prompt` automation step. - +This accepts a single argument called `Prompt`. -Within the Bindings menu, we can see the structure of the output from our previous step. +In the Bindings menu, you can see the structure of the output from the previous step. - - -The first part of our prompt will pass the relevant parts of this to our LLM, using the following instruction. +The first part of the prompt passes the relevant data to the LLM using the following instruction. ``` {{ steps.API Request.response.0.locations }} is a JSON object representing our weekly sales. ``` - - -We’ll then outline the specific information that we want to include in our final report, as well as how we need it to be formatted. +Then outline the information you want in the final report and how it should be formatted. So, our final prompt will be: @@ -132,36 +108,20 @@ Return a summary of this, including: Format as markdown, ready to include in an email automation in as concise a manner as possible. ``` -
- - - -We can then test our Automation again to verify that we’re happy with the information our `LLM Prompt` step outputs. +Test the automation again to verify the output from the `LLM Prompt` step. ## Setting up our email action -Lastly, we want to use this output to populate the body of an email, which we’ll send to our head office team. - -We’ll start by adding a `Send Email (SMTP)` action. Check out our documentation on [SMTP setup](https://docs.budibase.com/docs/email) to learn more about this. - - - -Within this, we can set key fields including the `Send To` and `Send From` addresses, the `Email Subject`, and the `Message`. First, we’ll add static values for our `Send To`, `Send From`, and `Subject` fields. - - - -We’ll then bind our `Message` to \`\{\{ steps.LLM Prompt.response }} - -
+Finally, use this output to populate the body of an email for your head office team. - +Add a `Send Email (SMTP)` action. See [SMTP setup](https://docs.budibase.com/docs/email) for more detail. -
+Set the `Send To` and `Send From` addresses, the `Email Subject`, and the `Message`. Start by adding static values for `Send To`, `Send From`, and `Subject`. -\`. +Then bind the `Message` to `{{ steps.LLM Prompt.response }}`. -Now, when we check our emails, we can see that the data we need has been extracted and formatted correctly. +When you check your email, you should see the extracted and formatted report. diff --git a/docs/Bindings/snippets/time-ago-snippet-function.md b/docs/Bindings/snippets/time-ago-snippet-function.md index 8387bff05..f4a411c8e 100644 --- a/docs/Bindings/snippets/time-ago-snippet-function.md +++ b/docs/Bindings/snippets/time-ago-snippet-function.md @@ -10,20 +10,20 @@ metadata: next: description: '' --- -This quick guide demonstrates how to create a JavaScript snippet that converts date times into hours, days, minutes, and seconds from the current moment. +This quick guide shows how to create a JavaScript snippet that converts date times into hours, days, minutes, and seconds from the current moment. ## Steps -1. Create a Budibase internal table this should include some form of date (In my case I will theme this around a blog) -2. Add data to your table +1. Create a Budibase internal table that includes a date field. In this example, it is based on a blog. +2. Add data to your table. 3. Go to the design screen and add a [Card block](doc:card) -4. Fill in the relevant bindings for Title, description etc +4. Fill in the relevant bindings for Title, description, and other fields. 5. Go to the subtitle bindable area. -6. Switch the tab from text to javaScript -7. Click on the `` icon and create a new snippet called `timeago` -8. Paste the below code into it and click save +6. Switch the tab from text to JavaScript. +7. Click the `` icon and create a new snippet called `timeago`. +8. Paste the code below into it and click save. ```Text JavaScript return function(pastTimeString) { @@ -60,11 +60,11 @@ return function(pastTimeString) { } ``` -9. Click the snippet and add the date binding you wish to use inside its brackets -10. Then click save +9. Click the snippet and add the date binding you want to use inside its brackets. +10. Click save. -## The end result! +## The end result diff --git a/docs/Bindings/url-parameters.md b/docs/Bindings/url-parameters.md index 056194be6..f038356d3 100644 --- a/docs/Bindings/url-parameters.md +++ b/docs/Bindings/url-parameters.md @@ -10,54 +10,45 @@ metadata: next: description: '' --- -Sometimes you need to pass information between screens. This takes two main forms: +Sometimes you need to pass information between screens. There are two common ways to do that: 1. [Link element](doc:link) 2. 'Navigate To' Action -A common example is opening a detailed view for a row entry. +One common example is opening a detailed view for a row. ## Navigate To -Some templates such as the *Client Contact List* app use row buttons instead of links. Tables also allow you to define actions [on row click](https://docs.budibase.com/docs/table-block#on-row-click). +Some templates, such as the *Client Contact List* app, use row buttons instead of links. Tables also let you define actions [on row click](https://docs.budibase.com/docs/table-block#on-row-click). In these cases, navigation is controlled by the navigation action: -![](https://files.readme.io/39afb8b-Screenshot_2022-04-20_at_17.05.15.png "Screenshot 2022-04-20 at 17.05.15.png") +Here, pass the client's row ID into the URL path. -Here we are passing the row id of the client into the URL path. +In the `/clients/:id` details screen, you can use that row ID. A word prefixed with a colon in a route denotes a path variable. -In the `/clients/:id` details screen we will be able to make use of this row id.\ -A word prefixed with a colon within a route denotes a path variable. +Access the ID using the `{{ URL.id }}` Binding. -The id is accessed using the `{{ URL.id }}` Binding +For example, if you only want to show the chosen client, add the following Filter to the client's Data Provider. -For example, because we only want to show the chosen client, we can add the following Filter to the clients' Data Provider - -![](https://files.readme.io/e0eff42-Screenshot_2022-04-20_at_19.01.31.png "Screenshot 2022-04-20 at 19.01.31.png") - -This can then be used in conjunction with a [Repeater](doc:repeater) to access the fields of the filtered client: +Use it with a [Repeater](doc:repeater) to access the fields of the filtered client. ## Multiple variables -Whilst passing a row id is the most common use case, you can pass many variables into the URL, with each being separated by a slash, e.g. `/clients/:id/:companyId/:timestamp/:customName/:etc` +While passing a row ID is the most common use case, you can pass multiple variables in the URL, each separated by a slash, for example `/clients/:id/:companyId/:timestamp/:customName/:etc`. -A detailed example can be found in this [discussion](https://github.com/Budibase/budibase/discussions/5299#discussioncomment-2530261). +A detailed example is available in this [discussion](https://github.com/Budibase/budibase/discussions/5299#discussioncomment-2530261).
## Testing URL Variables -A `Temporary URL variables` input has been added to the Screen Settings area. This feature displays a preview of how a URL will be structured, such as `edit/{variable}`, allowing users to pass variables dynamically while building screens. - - - -This feature lets you see real-time data population within components without previewing or publishing changes. This helps you quickly understand how different records affect the layout of your screens. +A `Temporary URL variables` input is available in the Screen Settings area. It previews how a URL is structured, such as `edit/{variable}`, so you can pass variables while building screens. - +This lets you see data populate components without previewing or publishing changes. It helps you understand how different records affect the layout. ### Benefits: -* Eliminates the need to hit "Preview repeatedly" or "Publish" to test variable driven screens. +* Eliminates the need to repeatedly use Preview or Publish to test variable-driven screens. * Speeds up development by reducing context switching. -* Provides instant feedback on how records populate within components. \ No newline at end of file +* Provides instant feedback on how records populate within components. diff --git a/docs/Data/transformers.md b/docs/Data/transformers.md index 978eed97d..1bb32d918 100644 --- a/docs/Data/transformers.md +++ b/docs/Data/transformers.md @@ -10,72 +10,60 @@ metadata: next: description: '' --- -In this section, we will cover how to use Budibase data transformers, which can be used as part of data source queries. It is often a requirement when retrieving data from various sources to transform to fit your app's use case - from simply extracting properties from deeper JSON objects to enriching your data with more information transformers can be used for a wide variety of applications. +Use data transformers to shape query results before they reach your app. They are useful when you need to extract properties from nested JSON or enrich data with additional values. > 📘 This section requires JavaScript knowledge > -> We recommend the Modern [JavaScript Tutorial ](https://javascript.info/)to pick up the basics, for transformers you will specifically benefit from knowledge around data types, such as [Arrays](https://javascript.info/array), [Array Methods](https://javascript.info/array-methods) and [Objects](https://javascript.info/keys-values-entries). +> We recommend the Modern [JavaScript Tutorial](https://javascript.info/) for the basics. For transformers, knowledge of [Arrays](https://javascript.info/array), [Array Methods](https://javascript.info/array-methods), and [Objects](https://javascript.info/keys-values-entries) is especially useful. -To create a transformer first you need to create an external data source and a query, steps for this can be found in the [External Data Sources](doc:data-sources) section. +To create a transformer, first create an external data source and a query. See [External Data Sources](doc:data-sources) for the setup steps. ## Accessing bindings -It is possible to access the bindings that your query received when it was called, through the `params` object that is available in the transformer context. For example if I've added a binding of `lastName` then I can access this property in the transformer under `params.lastName`. You can see a full example of this below. - - +You can access query bindings through the `params` object in the transformer context. For example, if you add a binding called `lastName`, access it as `params.lastName`. ## Tutorial -In the example below we will be transforming some data from the [Open Brewery Database](https://www.openbrewerydb.org/) - we will be creating an app that has tallies of the number of breweries by US state. - -When you first create a query you'll see the transformer code editor in its own section, as seen below. +In the example below, we transform data from the [Open Brewery Database](https://www.openbrewerydb.org/) to build an app that shows the number of breweries by US state. -![](https://files.readme.io/d0712b5-transformers.png "transformers.png") +When you create a query, the transformer code editor appears in its own section. > 📘 > -> There are two properties that are accessible by default within the transformer. First, the data which as its name suggests contains the data retrieved by the query. Secondly, params, which contain the query bindings/parameters that were provided when it was called. +> Two properties are available by default in the transformer: `data`, which contains the query results, and `params`, which contains the bindings passed to the query. -This will return the data exactly the way it is retrieved from the data source, it is recommended to get your query up and running correctly first before altering your transformer, this will allow you to look at the initial schema of the data returned. In our example so far we have: +The transformer initially returns the data exactly as it is retrieved from the data source. It is best to get the query working first, then adjust the transformer once you can see the returned schema. In this example so far: -1. Setup a REST data source, with our URL set to +1. Set up a REST data source with the URL set to: ``` https://api.openbrewerydb.org ``` -2. Created a query and set the path to *breweries* +2. Create a query and set the path to *breweries* 3. Ran the query to see the schema -The schema for this query appears as below: +The schema for this query should match the data returned by the API. - - -Using this information we can now write the transformer function that will be used. Initially we just want to write a function which will: +Use this information to write the transformer function. Initially, it should: 1. Work through the array of breweries that are returned by the API, in the format shown above 2. Extract the state and add it to a total count of states that have been seen 3. Return a new structure that contains only the state name and the count of breweries within -You can see the basic transformer we have written to do this below. - - +You can write the transformer to do this with a loop that counts the breweries per state and returns a `state` and `count` property. -Here we have taken the data, written a for loop that iterates through a fills up an object with counts for each state (using the state's name as the key into the object), and finally, we've mapped these totals to our output structure, an object with a state and count property. You can see from this that we can drastically change the format of the data; using JavaScript you can change the data in a multitude of ways. +Here, we take the data, loop through it, fill an object with counts for each state, and map the totals to the output structure. The output contains a `state` and `count` property. This shows how much you can change the shape of the returned data with JavaScript. -For the last part, we want to add data that simply isn't a part of the query, enriching the application logic that we've provided as part of the transformer. We are going to add a URL that points to an image of the states flag for each of the state entries, to do this we will create a URL dynamically to [http://flags.ox3.in/](http://flags.ox3.in/) - a repository of SVG flags. You can see the final function which does this below. +For the final part, add data that is not part of the query by building a URL for each state's flag. In this example, generate a URL dynamically from [http://flags.ox3.in/](http://flags.ox3.in/), a repository of SVG flags. - +This adds a map of state names to state codes, then uses the code to build the final URL. The results now include a `flag` property, which you can use in the design section with an image or card component. The example shows how this works with a data provider, repeater, and card component bound to the `state`, `count`, and `flag` properties. -This may look a little complicated, but all we have done is added a map of the state names to state codes, then at the end when we produce the final data we lookup the state name in the map and build a URL that has the code in it. You can see in our results section we now have a "flag" property, which can be used in the design section with something like an image or card component. We've thrown together a quick example of how this can all come together in your design, using only a data provider, repeater and card component bound to the "state", "count" and "flag" properties our transformer produced. - -![](https://files.readme.io/522188e-image_7.png "image (7).png") - -Hopefully, this has helped to demonstrate how transformers can be used to get the data you need for your application, happy coding! +This should show how transformers can shape the data you need for your application. ## Response -A query must always return an array as that is how Budibase handles data, it will always attempt to fit your data into a column/row type table structure. If you have an endpoint which returns a single object then the following conversion with occur: +A query must always return an array because that is how Budibase handles data. It fits the response into a column and row structure. If an endpoint returns a single object, it is converted like this: ```json { @@ -89,7 +77,7 @@ A query must always return an array as that is how Budibase handles data, it wil ] ``` -This functionality is important to understand when building transformers as if you return an array it will be broken up into individual rows. An example of this would be the use of the `Object.keys` or `Object.values` functions, breaking an object up into an array of keys/values. Below we can see an example of how Budibase would treat a transformer which returns the direct result of these functions: +This matters when building transformers because an array is broken up into individual rows. A common example is using `Object.keys` or `Object.values`, which produces an array of keys or values. Budibase treats those results like this: ```json // outputs [ "a", "b" ] @@ -102,8 +90,6 @@ return Object.keys({ "a": 1, "b": 2 }) ] ``` -If we were to take the above example and add it to a table within Budibase it would appear as seen below. - -![](https://files.readme.io/fadc6e2-image.png) +If you add the above example to a table in Budibase, each array element appears as a row. -If you instead would like to return all of these elements as an array you can do this, by wrapping the transformer response in an object, like `return { letters: Object.keys({ "a": 1, "b": 2 }) }` - however the query will still return an array, so that it can be used by a data provider + table/repeater. +If you want to return the values as an array, wrap the transformer response in an object, for example `return { letters: Object.keys({ "a": 1, "b": 2 }) }`. The query still returns an array so it can be used by a data provider, table, or repeater. From c9e9951e2e6d714ca7d05e821ae56c38a7ef27dd Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 15 Jul 2026 09:11:33 +0100 Subject: [PATCH 19/32] batched update --- docs/Data/data-sources/airtable.md | 26 ---- docs/Data/data-sources/arangodb.md | 46 ------- docs/Data/data-sources/mongodb.md | 124 +++-------------- docs/Data/data-sources/ms-sql-server.md | 123 ----------------- docs/Data/data-sources/mysql-mariadb.md | 168 ++---------------------- docs/Data/data-sources/oracle.md | 129 +----------------- 6 files changed, 29 insertions(+), 587 deletions(-) diff --git a/docs/Data/data-sources/airtable.md b/docs/Data/data-sources/airtable.md index 35251ea8d..df79325de 100644 --- a/docs/Data/data-sources/airtable.md +++ b/docs/Data/data-sources/airtable.md @@ -27,8 +27,6 @@ Airtable can be connected to Budibase through some simple configuration. This al To connect Airtable to Budibase, you need to add a new Data Source. Head over to the data section in the Budibase UI, and click the `Add source` button in the left navigation. -![](https://files.readme.io/d7da399-Screenshot_2023-06-27_at_12.10.36.png) - A dialog will open, allowing you to choose which data source you want to add. Choose Airtable, and click continue. You will be prompted to enter your API key and the base. You can get your API key from your Account page inside Airtable. To retrieve the `base` from Airtable, head over to the REST API page. This page should list all your bases for you. Click on the base you want to connect, and the `base ID` should be given to you. @@ -39,16 +37,12 @@ Enter the data into the configuration, and click `Save` to store the details of To query data from your Airtable base, click the `Add query` button below the Airtable configuration -![](https://files.readme.io/02704af-airtable-add-query.png "airtable-add-query.png") - First, enter a name for your query, this is purely cosmetical and has no impact on the inner workings. It will be displayed to you when you pick a data source in a [Data Provider](doc:data-provider) in the Budibase Design section. Choose the function you want to perform. There are detailed instructions on how to complete each function below. Then there are the specific fields. -![](https://files.readme.io/da9edcf-airtable-fields.png "airtable-fields.png") - The `Table` field accepts both the table name and the table ID. It is highly recommended to enter the ID as shown above. You can retrieve the ID for your table from the Airtable REST API page. The `View` field accepts the name of the view you've created in your base. The default is `Grid view` (yes, including a space). @@ -102,20 +96,12 @@ Bindings in Queries allow you to insert data when using the query. You can use H Let's take a look at an example where we pass the ID from a binding into the query. Our binding looks like this. -![](https://files.readme.io/6af491a-mongodb-binding.png "airtable-binding.png") - Then, adjusting our query, we add the `id` using handlebars directly into the string -![](https://files.readme.io/7902140-airtable-binding.png "airtable-binding.png") - Now, wherever you use the created query as a data source in a [Data Provider](doc:data-provider), you can configure the bindings directly from there, using the gearwheel behind the provider selection -![](https://files.readme.io/b7a426f-airtable-query-selector.png "airtable-query-selector.png") - This will then open up the configuration modal, where you can bind the value, for example using a [Form](doc:forms) input. -![](https://files.readme.io/d6e9ca3-mongodb-query-binding.png "airtable-query-binding.png") - ## Retrieving relational data You can have relationships between Airtables, however there is no joining functionality. Instead you must make two REST calls. @@ -128,28 +114,16 @@ In this example there are many classes with many students. 1. Within Airtable, add a RecordID column to your Students table. This will allow us to filter for the students that attend a particular class. -![](https://files.readme.io/d1bd779-Screenshot_2022-07-15_at_13.43.39.png) - 2. Also within Airtable, link your Classes table to your Students table. -![](https://files.readme.io/aa1ae3f-Screenshot_2022-07-15_at_13.48.22.png) - 3. Add a read query for the class table. -![](https://files.readme.io/4772010-Screenshot_2022-07-15_at_13.51.12.png) - 4. Add a read query for the students table. -![](https://files.readme.io/7e47bb9-Screenshot_2022-07-15_at_13.52.40.png) - 5. In the Design section, add a [Repeater Block](https://docs.budibase.com/docs/blocks#repeater-block) for the Classes query, and a [Table Block](https://docs.budibase.com/docs/blocks#table-block) nested underneath for the Students query. You can add the class title for each of the student tables, and configure the columns to avoid adding the id strings. 6. Add a filter to the students table block as follows: -![](https://files.readme.io/31285cf-Screenshot_2022-07-15_at_14.04.46.png) - 7. The final result should appear as follows: -![](https://files.readme.io/1558128-Screenshot_2022-07-15_at_14.07.33.png) -
diff --git a/docs/Data/data-sources/arangodb.md b/docs/Data/data-sources/arangodb.md index d179b8be1..da52b2f74 100644 --- a/docs/Data/data-sources/arangodb.md +++ b/docs/Data/data-sources/arangodb.md @@ -24,16 +24,8 @@ The only prerequisites for this guide are that you need a Budibase instance, an The first step is to create your ArangoDB datasource. When in the Data tab in the Budibase builder, click the *Add source* button in the top left corner. A modal will appear allowing you to select what type of datasource you want. Select *ArangoDB* and then click *Continue*. -Select the ArangoDB datasource - Select the ArangoDB datasource - - The next step is to add the relevant connection info so that Budibase can connect to your ArangoDB instance. By default the Username will be *root* and the Database Name is \_*system*. -ArangoDB connection info - ArangoDB connection info - - If you don't have a Collection yet, go to the URL of your ArangoDB instance - by default this is [localhost:8529](http://localhost:8529/) if you're running it locally - and then sign in to add a new collection. Once your connection details have been entered, click *Save and continue to query* to save those and test the connection. @@ -48,10 +40,6 @@ Create queries are very simple in the Budibase ArangoDB integration. They run an Simply enter the document object into the Fields field. If you want to use Bindings, you can set them up above with a Binding name and a default value. Then in your query, place the binding name where you want it to be used as shown below. We'll see the full power of bindings later in this guide. -Adding a simple document to an ArangoDB collection - Adding a simple document to an ArangoDB collection - - Once you're happy with your query, click *Run Query* to test it. If you are using Bindings the default value for them will be used. This type of query returns the newly created document as a response. You can use a JavaScript function in the [Transformer field](https://docs.budibase.com/docs/transformers) to modify this result, but most of the time the default `return data` will be sufficient. When you're finished working on the query, click *Save Query*. ## Read @@ -71,10 +59,6 @@ for bag in beans Using AQL you can add a lot more logic to limit the query or change the structure of the data coming out. In my case here, I'm filtering the results, limiting the count to 10 and sorting them by name. -Additional AQL filtering for our query - Additional AQL filtering for our query - - You can also query the database to get a single object where `{{id}}` is a binding like this: ```Text AQL @@ -93,32 +77,18 @@ To tie this all together, let's build a full CRUD app in Budibase using ArangoDB We'll start by updating our [Create](#create) query we made above. I'm going to replace the rest of the hardcoded values in the JSON object to use bindings. -Using bindings to create a new document with form values - Using bindings to create a new document with form values - - Now that we have those bindings in place, we can go to the Design tab to make use of them. I'm going to start by adding a Blank screen with the URL `/bag/new` where we will create a form for adding a new document to our collection. In my screen I'll add a Form component with a [Field group](doc:field-groups) and a [Button](doc:button). When setting up the form use your Create query as the Schema so that inside the field group we have the relevant fields for each column in the document. -Form component setup - Form component setup - - To make the form fully functional, add an On Click Action to your button to execute the query. In the Execute Query action settings, add the field values from the form for each binding. -Execute Query configuration - Execute Query configuration - - Now whenever you fill in the fields and click the Create button, our Create query will run with the specified values and add a new document to our collection. ## Listing documents For listing documents we can use the Table block and our simple [Read](#read) query. All you need to do is create a new screen, add a Table block, and choose the query. The table will immediately be populated with data from your collection. -![](https://files.readme.io/93a3027-SCR-20230217-ot6.png) - Once you have this table in place, you can configure the columns however you like. You can easily add a button that will link to the New document screen we built above. You can also route to the Edit document screen that we're building below. ## Updating documents @@ -153,18 +123,10 @@ When creating our new edit screen, we need to pass in the document's key as a [U Our edit screen will be set up in a very similar way to our create screen shown above. The main difference is we will use a Repeater block to provide the existing form values as defaults for the field components. We will use the first query we made as the data source for this Repeater block, and use `beans/{{ URL.key }}` as the id binding for that. This query will only provide one document from the collection, but to be extra safe we can also filter the Repeater block by the URL param key and limit it to 1 result. -The edit screen, with form fields populated by the Repeater block - The edit screen, with form fields populated by the Repeater block - - You will need to configure the Form and Field Group similarly to the ones on the create page, but add the values from the Repeater block as default values for each field. The Form Type should be Update in this case and because we are using custom queries in ArangoDB, we need to use a Custom schema where we define each field variable manually. The last thing to do when making an edit screen is to hook up the On Click action for the Save button to execute the Update query we made above. In the Execute Query settings we can pass in the form field values to be used in the query bindings, like so: -Our save button's On Click configuration - Our save button's On Click configuration - - ## Deleting documents The last type of query we need to create for a fully functioning CRUD app is one that will delete a document from our collection. This is another query that needs to be set as a Read function so that we can make use of AQL. This time we are using `key` as our binding and will use that to identify the document we want to delete from our collection. @@ -175,14 +137,6 @@ remove "{{key}}" in beans Now that we have our query, all we need to do is add a button to our edit screen that will execute this query, passing in the key from our URL parameter for the binding. -Executing the delete query on a button click - Executing the delete query on a button click - - -The final edit screen complete with delete button - The final edit screen complete with delete button - - > 👍 Nice work > > We've successfully built a full CRUD app using Budibase and ArangoDB! diff --git a/docs/Data/data-sources/mongodb.md b/docs/Data/data-sources/mongodb.md index 6d48fffac..cc6054967 100644 --- a/docs/Data/data-sources/mongodb.md +++ b/docs/Data/data-sources/mongodb.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -MongoDB is a modern NoSQL database, that can be connected to Budibase with a few clicks. +MongoDB is a modern NoSQL database that can be connected to Budibase with a few clicks. Before we get started, make sure you've got the following: @@ -34,16 +34,8 @@ Now that you have everything you need to hook up your MongoDB installation to Bu To connect your MongoDB Data Source, head over to the data section in the Budibase builder UI. Then, click the `Add source` button in the left-hand settings panel to add a new data source. -Press the `+` icon to add a data source - Press the `+` icon to add a data source - - You will be presented a dialog, in which you choose `MongoDB`. Then you will be presented with the connection configuration. -{673} - A standard connectionstring when connecting to MongoDB Atlas - - Paste your ConnectionString, and enter the database name which you want to connect with, and click `Save and continue to query`. Pressing this button will save the ConnectionString into your Budibase installation. @@ -58,12 +50,10 @@ Now that you have added the connection to your database, you can start querying The first step is to click the 'Add query' button, which is located on the data source page you just added. If you're not on this page, click on the MongoDB connection in the list of data sources on the left. -![](https://files.readme.io/29d5e4b-queries.png "queries.png") +Choose the query name, collection, function, and access level first. Then use the action type to define which MongoDB operation Budibase should run. ### Query configuration -![](https://files.readme.io/d478411-query-configuration.png "query-configuration.png") - Configuring your query is essential in making sure it runs correctly. In the table below you'll find what each field means. | Field | Description | @@ -84,12 +74,10 @@ You have the option to insert one or many documents into a collection. When inserting a single document, provide a payload within the query box. -![](https://files.readme.io/cd3e4b3-Screenshot_2022-06-17_at_11.50.46.png "Screenshot 2022-06-17 at 11.50.46.png") - In this case, an ObjectId is automatically generated for the new document.\ -If you want to specify an ObjectId, you can do that as follows: +If you want to specify an ObjectId, you can do that as follows: -![](https://files.readme.io/2a5b095-Screenshot_2022-06-17_at_11.54.46.png "Screenshot 2022-06-17 at 11.54.46.png") +If you are inserting multiple documents, provide an array of objects instead of a single object. > 🚧 Document ID > @@ -97,18 +85,12 @@ If you want to specify an ObjectId, you can do that as follows: When inserting many, you must provide an array of objects. -![](https://files.readme.io/1139ebd-Screenshot_2022-06-17_at_12.03.59.png "Screenshot 2022-06-17 at 12.03.59.png") - ### Read query The most basic query you can do is a *find* with no query body.\ This will return all data available within the specified collection. -![](https://files.readme.io/b80361e-Screenshot_2022-06-17_at_11.44.02.png "Screenshot 2022-06-17 at 11.44.02.png") - -A filter object can be added to the query box. For example, get all documents in the collection where age is greater than 40: - -![](https://files.readme.io/18cecf7-Screenshot_2022-06-17_at_11.43.33.png "Screenshot 2022-06-17 at 11.43.33.png") +A filter object can be added to the query box. For example, return only documents where age is greater than 40. A full list of query operators can be found here: [https://www.mongodb.com/docs/manual/reference/operator/query/](https://www.mongodb.com/docs/manual/reference/operator/query/) @@ -116,13 +98,11 @@ A full list of query operators can be found here: [https://www.mongodb.com/docs/ When performing an update you must provide two objects: -1. **uired]** F** Filter - find the documents to change. -2. **uired]** U** Update - instructions for the modifications to make. -3. **ional]** O** Options - additional update parameters (more [here](https://www.mongodb.com/docs/v4.4/reference/method/db.collection.updateOne/)) +1. **Required** Filter - find the documents to change. +2. **Required** Update - instructions for the modifications to make. +3. **Optional** Options - additional update parameters (more [here](https://www.mongodb.com/docs/v4.4/reference/method/db.collection.updateOne/)) -For example, set the *retired* property to true for all documents that have an age over 65: - -![](https://files.readme.io/f5d94e4-Screenshot_2022-06-17_at_12.23.37.png "Screenshot 2022-06-17 at 12.23.37.png") +For example, set the *retired* property to true for all documents that have an age over 65. If *updateOne* was used instead, then only the first filter match would have been updated. @@ -133,9 +113,7 @@ A full list of update operators can be found here: [https://www.mongodb.com/docs To delete ALL records from a collection, run a query with no filter and the *deleteMany* action type set.\ **Careful!** -Otherwise, you can add a filter to delete all matching records: - -![](https://files.readme.io/b172b92-Screenshot_2022-06-17_at_17.13.47.png "Screenshot 2022-06-17 at 17.13.47.png") +Otherwise, you can add a filter to delete all matching records. If *deleteOne* was used instead, then only the first filter match would have been deleted. @@ -151,19 +129,11 @@ Bindings in Queries allow you to insert data when using the query. You can use H Let's take a look at an example where we pass the ID from a binding into the query. Our binding looks like this. -![](https://files.readme.io/f13b018-Screenshot_2022-06-17_at_12.51.35.png "Screenshot 2022-06-17 at 12.51.35.png") - Then, adjusting our query, we add the `id` using handlebars directly into the string -![](https://files.readme.io/2830edf-Screenshot_2022-06-17_at_12.47.08.png "Screenshot 2022-06-17 at 12.47.08.png") - -Now, wherever you use the created query as a data source in a [Data Provider](doc:data-provider), you can configure the bindings directly from there, using the gearwheel behind the provider selection - -![](https://files.readme.io/c136975-configure-binding.png "configure-binding.png") - -This will then open up the configuration modal, where you can bind the value, for example using a [Form](doc:forms) input. +Now, wherever you use the created query as a data source in a [Data Provider](doc:data-provider), you can configure the bindings directly from there using the gearwheel behind the provider selection. -![](https://files.readme.io/d6e9ca3-mongodb-query-binding.png "mongodb-query-binding.png") +This will then open up the configuration modal, where you can bind the value, for example using a [Form](doc:forms) input. ### Transformer @@ -179,19 +149,15 @@ The `transformer` box accepts JavaScript, and is ran within a function. This mea Now that you have configured the entire query correctly, it's time to save the query. You can't save the query without running it first so we know it actually is working. -So the first thing you want to do now, is click the `Run Query` button - -![](https://files.readme.io/b2b5724-mongo-run-query.png "mongo-run-query.png") +So the first thing you want to do now is click the `Run Query` button. As soon as you click the button, the query will be executed. When the query is successful, the result will be displayed below. There you can inspect the result, configure the schema and preview it in a table. -![](https://files.readme.io/70ff61e-mongo-runquery-result.png "mongo-runquery-result.png") - ### Configuring schema Configuring the schema is important for Budibase, as it allows the interface to understand what kind of data it is dealing with. In order for you to configure the data, click the `Schema` Tab, which is next to the `JSON` tab in the results section. You should then be presented with a page like this: -![](https://files.readme.io/2edbd43-mongo-results-schema.png "mongo-results-schema.png") +Use this view to confirm the shape of the data before you save the query. ## Aggregations @@ -201,15 +167,13 @@ This is done through *pipelines* which contain a number of *stages*. More from t To use aggregations within Budibase, select the **Aggregate** function. -![](https://files.readme.io/db42f82-Screenshot_2022-11-11_at_10.34.04.png) - There are two modes in which you can interact with aggregations: JSON and Pipeline. ### Json This is the default mode. Simply enter an array of stages to be processed. -![](https://files.readme.io/95a2d7d-Screenshot_2022-11-11_at_10.42.11.png) +Use this when you already know the pipeline and want to paste it directly. ### Pipeline @@ -217,8 +181,6 @@ Whilst the JSON mode can do everything you need, you may find the GUI mode makes Add as many stages as you like with the `+` button, delete stages with the trashcan icon, and use the arrows to swap stages. -![](https://files.readme.io/0efef57-Screenshot_2022-11-11_at_10.47.35.png) - A benefit of using the Pipeline mode is that it provides the available aggregation stages in a dropdown, and selecting a stage will fill out a template of relevant properties, which can be easily altered. *** @@ -237,35 +199,11 @@ A benefit of using the Pipeline mode is that it provides the available aggregati In MongoDB it is common to use nested documents instead of relationships. For example, this **transactions** collection returns an array of transaction meta data, with nested transaction data: - - -Looking at the `Schema` tab, we can see a property called *transactions* of type *Array*: - -Array of transactions - Array of transactions - - -When displaying nested array query data, Budibase will automatically generate the schema for the nested objects. +Budibase will generate schema for the nested objects automatically once the query returns the data. To make use of the nested data, first add a Repeater [Block](doc:blocks) to your screen for the query. -Selecting the query - Selecting the query - - -Next nest a [Table block](doc:table-block) under the repeater block. The nested data source can be selected under the *JSON Arrays* section: - - - -Alternatively you can nest another **Repeater block**, which would give you access to the nested data row [bindings](doc:introduction-to-bindings): - - - -The data types are determined automatically based on the primitive types provided by the Mongo query: - -Example nested transaction data in Mongo Atlas - Example nested transaction data in Mongo Atlas - +Next nest a [Table block](doc:table-block) under the repeater block. Select the nested array from the *JSON Arrays* section of the table block.
@@ -275,40 +213,16 @@ In the previous example we had a nested array of objects. Sometimes you will hav In this tutorial you will see how to display a list of product tags underneath each account. Here is the result of the Mongo query: - - -Account schema with products array - Account schema with products array - +The pattern is the same: use one repeater for the parent records, a second repeater for the nested `products` array, and a Tag component inside that repeater. To begin create your screen and add a **Repeater block**. Select the *Read accounts* query. - - -Next add a [Headline](https://docs.budibase.com/docs/displaying-text#headline) and display the *account\_id* with the following Binding: `Account ID: {{ Accounts Repeater Block.Read accounts.account_id }}` - -Now we'll nest a second **Repeater block**, this time for the associated account products. Under the *Fields* section of the *Data* setting, select the *products* field: - -Selecting the related account products - Selecting the related account products - - Under the second repeater block, nest a **Tag** component. Your final Component Tree should look roughly like so: -Final component tree - Final component tree - - In the Settings Panel, set the *Text* property of the tag to the products value: `{{ Products Repeater Block.products.value }}` -Select the 'Value' binding from the products repeater - Select the 'Value' binding from the products repeater - - Use [Conditional UI](doc:conditions) to give the tags a custom colour based on the product: - - #### Result - +The final screen shows each account with its related product tags styled by value. diff --git a/docs/Data/data-sources/ms-sql-server.md b/docs/Data/data-sources/ms-sql-server.md index 89c528df3..7ecc04be2 100644 --- a/docs/Data/data-sources/ms-sql-server.md +++ b/docs/Data/data-sources/ms-sql-server.md @@ -20,101 +20,14 @@ next: After clicking on the SQL Server datasource you will be prompted to enter connection details: - - -## Advanced authorisation - -If you are using an MS SQL Server protected via Azure Active Directory, you can setup the `Advance auth` field to `Active Directory`, providing the required secrets. - - - -The Azure documentation can be found [here](https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/azure-ad-authentication-sql-server-setup-tutorial?view=sql-server-ver16). - -
- -*** - -
- -# Tutorial: Building a Bike Store app - -In this tutorial we will look at building a Budibase app from scratch using an existing Microsoft SQL Server database as our foundation. Our data is split between two schemas. - -One schema is called **Production** which contains our products, details and stocks. This data will be available to the public for customer use. - -The second schema is called **Sales** which contains internal data to be seen and managed by employees only. - -The full dataset can be found on [sqlservertutorial.net](https://www.sqlservertutorial.net/sql-server-sample-database/). - -## Setting up the datasources - -Given you have an MS SQL Server instance running, with the dataset committed, we can begin pulling that data into Budibase. - -First create an app - no sample data needed. - -![](https://files.readme.io/ef353f8-create_app.png) - -As we have two schemas, we will want to create two [Datasources](doc:data-sources); one for each schema. - -Click `Add source` and select `MS SQL Server`. Fill out the connection details and press `Save and fetch tables`. - -![](https://files.readme.io/ec7639b-create-ds-sales.png) - -Repeat the same process, but change the *Schema* to **production**. - -By default the datasource names will be *SQL Server* and *SQL Server-2*. It is best to rename these to match the corresponding schemas. - -For example, select the datasource for the **production** tables, change the name under configuration, and click `Save`. Do the same for **sales**. - -![](https://files.readme.io/1fa4ca6-rename-ds-prod.png) - -Your final *Sources* tree should look as follows: - -![](https://files.readme.io/0672e31-Screenshot_2022-12-19_at_15.27.11.png) - -## Define existing relationships - -Now that we have pulled in our tables, we need to inform Budibase how the tables relate to each other. - -* One Brand -> Many Products -* One Category -> Many Products -* One Store -> Many Staff -* One Store -> Many Orders -* One Staff -> Many Orders -* One Customer -> Many Orders - -To get started, click on the `brands` table. Next click on the `Define existing relationship` button along the top of the table. - -![](https://files.readme.io/282c97d-Screenshot_2022-12-19_at_15.53.58.png) - -This will pop up a dialog for you to select the `products` table as the *to table*, and select the *brand\_id* as the foreign key. - -![](https://files.readme.io/838d21f-define_relationship.png) - -Click `Save` and you will see the relationship links successfully added in both tables. - -Product links in the brands table - Product links in the brands table - - -Brand links in the products table - Brand links in the products table - - The same process can be followed for the other desired relationships mentioned. Alternatively you can [define relationships](https://docs.budibase.com/docs/sql-datasource#defining-relationships) from the datasource configuration page. ## Adding a public products catalogue screen In this tutorial we want to allow customers to browse the available products of the bike store. First we must give public users permissions to view the data. For each table under the **Production** datasource, click on `Manage access`. -![](https://files.readme.io/0d0bb56-Screenshot_2022-12-19_at_16.13.28.png) - This will display a modal for setting the read and write access levels. As we only want the public to be able to read the data, select the **Public** role for *Read* and click `Done`. -Anyone can read the products, but write require authorization - Anyone can read the products, but write require authorization - - > 🚧 Manage access for relationships > > When making data public, you must also give the related data public access.\ @@ -122,42 +35,22 @@ This will display a modal for setting the read and write access levels. As we on With the data permissions now set, we can add our screen into the [Design](doc:working-with-data) section. Click on the **Design** tab, and select the `/home` screen. Under access, select **Public** so that anyone can view the [Screen](doc:screens). -Public screen access - Public screen access - - Next click on `Add component` and add a [Cards block](https://docs.budibase.com/docs/blocks#cards-block). Select `products` as the datasource, and fill out the cards title, subtitle and description. Use the Binding from the dropdowns to pull data from the SQL datasource. -Selecting the product name as the card title - Selecting the product name as the card title - - Bindings also allow you to combine static text with dynamic data pulled from your SQL table. For example, we can prefix the price with a dollar sign using the following handlebars expression: ``` ${{ Products Cards block.products.list_price }} ``` -![](https://files.readme.io/fef6581-Screenshot_2022-12-19_at_16.29.21.png) - You can tick *paginate* and adjust the *limit* setting to determine how many products should be displayed per page. Of course given a catalogue of products, users would like to be able to filter. You can easily add a *Search column* via the dropdown in the cards block. -Adding search columns - Adding search columns - - For example, you may want to allow users to search by product name, brand name, or model year. -![](https://files.readme.io/7531e12-Screenshot_2022-12-19_at_17.25.11.png) - It would also be nice to add in some tags for the brand and category of the product. To do this let's [eject the block](https://docs.budibase.com/docs/blocks#ejecting-blocks). This will give us a more granular component tree like so: -Ejected cards block - Ejected cards block - - With access to the [Repeater](doc:repeater), we can now add a couple of [Tag](doc:tag) components below the *Spectrumcard*; one each for the brand and category. Use the following binding for the tag text: `{{ Repeater.products.brands.0.primaryDisplay }}` @@ -166,14 +59,10 @@ To explain, *brands* is the name of the relationship field. The `.0` is required Using [Containers](doc:container) and a bit of styling, you can create something like this: -![](https://files.readme.io/6dce82d-Screenshot_2022-12-19_at_17.29.15.png) - Finally click the `Preview` button in the top-right corner of the screen to test the app so far. Select `View as public user` to make sure unauthenticated users can view the data. -![](https://files.readme.io/d51c1c2-Screenshot_2023-02-03_at_11.57.14.png) - ## Managing sales data Whilst we want the public to be able to view the available products, the sales data should be managed by authenticated users. @@ -182,26 +71,14 @@ After setting up your relationships, as outlined earlier in the tutorial, go to This will prompt you to select the table to create the [Autogenerated screen](https://docs.budibase.com/docs/table-block#autogenerated-screen) for. Select the `orders` table and `Confirm`. -![](https://files.readme.io/214415d-7dc103f-Screenshot_2022-12-19_at_17.44.01.png) - Next you will be prompted to select an access level. By default **Basic** will be selected, which requires an authenticated user of the app. Click `Done`. This will add full CRUD functionality for the `orders` table. If you want to customise this screen, look at the [Table block](doc:table-block) page for more info. -Basic logged in user can view and edit orders - Basic logged in user can view and edit orders - - Whilst public users will be denied access to the *Orders* screen, it would be better to not show them the [Navigation](doc:navigation) link so as to avoid confusion. Click on the navigation panel, and click `Configure links`. Next beside `/orders` select a *Minimum role* - in this case **Basic**. Click `Save`. -![](https://files.readme.io/11c6448-Screenshot_2022-12-19_at_18.04.07.png) - This will ensure that public users do not see the *Owners* link. -Unauthenticated user only sees the Home link - Unauthenticated user only sees the Home link - - Auto-generated screens can be created for the other **sales** tables, but different [access levels](https://docs.budibase.com/docs/user-roles#app-specific-roles) could be used. diff --git a/docs/Data/data-sources/mysql-mariadb.md b/docs/Data/data-sources/mysql-mariadb.md index e9beb317d..5cf980b16 100644 --- a/docs/Data/data-sources/mysql-mariadb.md +++ b/docs/Data/data-sources/mysql-mariadb.md @@ -38,56 +38,8 @@ When you have a MySQL or MariaDB Server instance running, with the sample databa First create a new Workspace. We will set up our MySQL datasource and app here. - - -Once the new workspace has been created, click `Add source` and select `MySQL`, even if you are using MariaDB, or any other storage engine. - -![](https://files.readme.io/d3074a0-Screenshot_2023-01-12_at_14.36.26.png) - -Click `Save and fetch tables` to finish. - -
- -## SSL - -You have the option to provide an SSL which prompts you with two additional fields `key` and `value`. The ssl `key` in the connection options takes a string. There are a lot of different options that can be used here, the 3 main ones are listed below. - -* `ca:` The certificate(s) to trust instead of the ones Node.js is configured to trust. This refers to the value of the certificate(s) and not a filename of the certificate(s). -* `cert:` The client certificate to use in the SSL handshake. -* `ciphers:` The ciphers to use to use in the SSL handshake instead of the default ones for Node.js. - -Additional information on other keys or more information on the 3 listed above can be found [here](https://github.com/mysqljs/mysql#ssl-options). - -The `value` is the actual content of the SSL certificate files, and the paths provided in the MySQL configuration are pointers to these files. `/path/to/private-key.pem` - -## Define existing relationships - -Now that we have pulled in our tables, we need to inform Budibase how the tables relate to each other. - -* One Employee -> Many Titles (Historical) -* One Employee -> Many Salaries (Historical) -* Many Departments -> Many Employees / Managers - -To define these relationships, click on the MySQL datasource in the datasource list and scroll down to and click `Define relationship`. - -![](https://files.readme.io/cb4d4db-Screenshot_2023-01-12_at_14.47.32.png) - -For the one employee to many titles and salaries, define a relationship like so: - -One employee -> Many titles (matching on emp_no) - One employee -> Many titles (matching on emp\_no) - - For the relationship between **departments** and **employees**, there are joining tables, e.g. **dept\_emp**. Usually we would setup a [many-to-many relationship](https://docs.budibase.com/docs/sql-datasource#many-to-many) using the joining table as the *Through* table. Unfortunately in this case, the joining tables do not meet the requirements outlined by Budibase: -dept_emp is not a suitable Budibase joining table - dept\_emp is not a suitable Budibase joining table - - -from_date and to_date are invalid - from\_date and to\_date are invalid - - Luckily, this is an easy fix. Within MySQL Workbench, or through an alter SQL statement, make the **from\_date** and **to\_date** fields *nullable* for both joining tables. ```sql @@ -96,48 +48,24 @@ CHANGE COLUMN `from_date` `from_date` DATE NULL , CHANGE COLUMN `to_date` `to_date` DATE NULL ; ``` -dept_emp is now a suitable joining table - dept\_emp is now a suitable joining table - - Adding the Many -> Many relationships for **dept\_emp** should now work. > 📘 > > Make sure to re-fetch the tables to pull down the new schema information! -Many Departments -> Many Employees - Many Departments -> Many Employees - - An additional Many -> Many relationship cannot be added for two tables that already have a Many -> Many relationship established, but for this tutorial we do not need the **dept\_manager** table. Because the Many -> Many relationship between **departments** and **employees** will pull down a huge amount of information, we will also create a Custom SQL query called *Get Departments Only* to simply get the departments without any employee data when needed. -Simple select statement with no relationship data - Simple select statement with no relationship data - - -In the end your relationships table should look something like so: - -![](https://files.readme.io/a1cedaf-Screenshot_2023-01-24_at_14.37.53.png) - -By default the display name for the relationships will be the ID, but this isn't very readable: +When you're done, the relationships list should include the links for titles, salaries, and departments. - - -To improve upon this, we can [select a display column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column) for each table. This will be the column that appears in the relationship pills. As an example, for the **employees** table, open the menu on the **first\_name** column and select `Use as table display column`. - -Setting the first_name to be the display column - Setting the first\_name to be the display column - +By default the display name for the relationships will be the ID. Set the employee table display column so relationship values show a name instead. The employee relationship in the related tables, such as **titles**, is now more human readable. You can also use [Formula](doc:formula) columns to combine the first and last names of the employee into a single display column. Create a new formula column in the employees table called 'full\_name' with the following binding expression: `{{ first_name }} {{ last_name }}`. Set this column as the table display column. -![](https://files.readme.io/9e0a2e4-Screenshot_2023-01-16_at_11.15.34.png) -
## Org chart screen @@ -150,20 +78,6 @@ On the home screen, click `Add component` and select the *Row Explorer Block*. F Next in the *Cards* section, set the *Title* to match the **dept\_name**, and remove the *Subtitle* and *Description*. -Selecting the department name as the card title - Selecting the department name as the card title - - -List of clickable department names
-
- - List of clickable department names - - #### (Optional) Adding icons for each department To add a little bit of flavour to the row explorer, we can provide an *Image URL* for each department. One way to do this would be to host the images in a public repository and name the files to match the department names. Another approach is to create a column in your table to store a URL icon path, which is what we'll do in this example. @@ -186,11 +100,7 @@ UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/429955/customer- 4. In the Design section, click on the Row Explorer block and set the Image URL to the **icon\_url** field. -Selecting an image url - Selecting an image url - - -5. The image icons are not in the correct aspect ratio or a consistent size, but we can use the following [Global styling](https://docs.budibase.com/docs/custom-css#global-styling) to format the background image as needed: +5. The image icons are not in the correct aspect ratio or a consistent size, but you can use the following [Global styling](https://docs.budibase.com/docs/custom-css#global-styling) to format the background image as needed: ```html ``` -6. We also do not need the search, so we should [Eject](https://docs.budibase.com/docs/blocks#ejecting-blocks) the block and delete the form. Your builder should appear like so: - -![](https://files.readme.io/df7f486-Screenshot_2023-01-18_at_14.00.54.png) +6. We also do not need the search, so we should [Eject](https://docs.budibase.com/docs/blocks#ejecting-blocks) the block and delete the form. After that, only the department cards should remain. ### Step 2 - Adding the manager and employee cards @@ -211,16 +119,12 @@ After ejecting the row explorer block, we need to change the Data provider sourc In addition, the auto-generated click action of the `Spectrumcard` will need to be updated. Click `Define actions` and change the state value to the *dept\_no* from the query: -![](https://files.readme.io/cb0670d-Screenshot_2023-01-24_at_15.23.23.png) - -At the moment upon previewing the app, a basic form is shown on click of each department row. Instead we want to display a card for the department managerial team and their employees. +When you preview the app, clicking a department should update the selected department state. Instead of the default form, we want to display a card for the department managerial team and their employees. First delete the [Form block](doc:form-block) and button components from the container. Next we want to make sure the clicked department name is available in the explorer panel. To do this, we will push the clicked row department name into [App state](doc:app-state). Click on the `Spectrumcard` component and within the Settings Panel click `Define actions`. Then click `Add Action` -> `Update State` and set a variable called *DepartmentName* as follows: -![](https://files.readme.io/f44299b-Screenshot_2023-01-18_at_14.12.22.png) - Be sure to click the `Save` button! Whilst we could use multiple nested repeaters to pull in all of the department detail we want to display, it is much more efficient to use a [Custom SQL query](doc:custom-queries). Use the following SQL: @@ -235,21 +139,15 @@ WHERE d.dept_name = {{ dept_name }} AND (e.emp_no, t.from_date) in (select t.emp Also add a binding for the **dept\_name**, and give the query the name *Get Managers by Department Name*. Make sure to save! -![](https://files.readme.io/25ac3f3-Screenshot_2023-01-24_at_14.23.08.png) - Back to the Design section, add a [Cards Block](https://docs.budibase.com/docs/blocks#cards-block) for the managers using the SQL query datasource just added, passing in the binding: `{{ State.DepartmentName }}`. This will replace the form block we removed. -![](https://files.readme.io/6bb10dd-Screenshot_2023-01-24_at_14.25.46.png) - Within the *Cards* section set the *Title* to `{{ Managers.Get Managers by Department Name.first_name }} {{ Managers.Get Managers by Department Name.last_name }}`. For the *Description*, we want to display the managers current (most recent) job title: `{{ Managers.Get Managers by Department Name.title }}` With the card block setup, it is also worth adding a headline component to indicate which department has been selected. Above the cards block, add the headline component with the title `{{ State.DepartmentName }}`. Add some styling such as margin bottom and *Extra Large* size. -A preview of the app should show the following so far: - -![](https://files.readme.io/e3155f6-tabs_bug.gif) +At this point the selected department heading and manager card should be visible.
@@ -261,24 +159,12 @@ To get started, click `Add screen` and select `Autogenerated screens`. Tick the Next we want to be able to pass through the **emp\_no** and **dept\_name** from the home screen. To support this, configure the screen route as follows: -Employees screen with two variables - Employees screen with two variables - - -Use the name URL variable in the *Title* of the table block. - -Access the department name from the URL - Access the department name from the URL - +Use the route variable in the *Title* of the table block so the current department is visible. With so many records, search will be very important. Under *Search Fields* select some searchable fields. -![](https://files.readme.io/230109c-Screenshot_2023-01-19_at_10.07.57.png) - Now let's make use of the `{{ URL.id }}` binding to filter our employees by department. `Define filters` of the table block. The **dept\_no** will be available via the **dept\_emp** relationship, and we can match that against the ID in the URL as follows: -![](https://files.readme.io/c494ff9-Screenshot_2023-01-24_at_15.16.04.png) - Also set the *Scroll Limit* of the table block to 50. We will also want to `Configure columns`. Click on `Add all columns` and then press the `x` beside the **departments** column. We don't want to display the relationship because it will be the same for all rows. @@ -289,11 +175,9 @@ The employee screen is ready to go, but we still need to link it to the home scr Add a [Link](doc:link) component underneath the *Managers* card block. Add some margin top for some space. Give the URL the following binding: `/employees/{{ State.cAF3fs8fNJ }}/{{ State.DepartmentName }}`. The ID state will be different in your case. -![](https://files.readme.io/6e346f7-linking.gif) -
-##  Salary history +## Salary history The **salaries** table holds a historic record of each employees salary at a particular time. This time series can be displayed in a chart. @@ -301,54 +185,18 @@ Eject the Table block in the *employees* screen. Within the newly exposed *Details side panel*, select the *Details form block* and deselect **departments** and **salaries** from the *Fields* dropdown. We already know the department from the table heading, and we will be displaying the salaries in a chart instead of the [Multi-select picker](doc:multi-select-picker). -![](https://files.readme.io/63f7e05-Screenshot_2023-02-07_at_14.07.32.png) - We also want to make sure that we pass the correct ID through to state when clicking on a row. Click on the Table underneath the Data provider, and click `Define actions` under the *On Row Click* section of the Settings Panel. By default you will see the value binding of `{{ Clicked row._id }}` for the **Update State** action. Replace this with `{{ Clicked row.emp_no }}` as we want to use the actual primary key and not the URL-safe encoded link. -![](https://files.readme.io/a71a0f8-Screenshot_2023-03-14_at_08.34.49.png) - ### Adding the chart Under the *Details form block* add a [Chart block](https://docs.budibase.com/docs/blocks#chart-block). Choose a *Chart Type* of 'Line' and the **salaries** table as the datasource. Set the title to 'Salary History'. -Salaries Line Chart block - Salaries Line Chart block - - Next `Define filters` to add a filter on the employee number as follows: -![](https://files.readme.io/cd47442-Screenshot_2023-03-14_at_08.36.10.png) - > 📘 > > The State ID will only be set when a row is clicked, thus the chart display in the builder may display differently than the previewed/published app. Finally select the **from\_date** column as the *Label Col.* and the **salary** column as the *Data Col.*. A *Stepline* curve is the ideal way to display this data. - - - - - - - - - - - - - - - - - -
- Config - - Result -
- - - -
diff --git a/docs/Data/data-sources/oracle.md b/docs/Data/data-sources/oracle.md index 850b04f01..0f96d476a 100644 --- a/docs/Data/data-sources/oracle.md +++ b/docs/Data/data-sources/oracle.md @@ -24,55 +24,20 @@ To get started, follow the instructions from the [Database Star sample database] You may also find this video tutorial helpful for getting started: [How to Set Up the Oracle HR Schema](https://www.youtube.com/watch?v=x8C8w4JM3AU\&ab_channel=DatabaseStar). +Budibase supports Oracle `12.1+` in Thin mode and `11.2+` in Thick mode. + ## Adding the datasource With your Oracle instance running, and the sample database installed, we can begin pulling that data into Budibase. First create an app - no sample data needed. -![](https://files.readme.io/e745f7b-oracle-create-your-app.png) - Once the new app has been created, click `Add source` and select `Oracle`. - - -Click `Continue` and then fill out the connection config with the host, service name and user of your Oracle instance. - -![](https://files.readme.io/129f53b-Screenshot_2023-03-10_at_10.25.26.png) - -Click `Save and fetch tables` to finish. - -
- -## Defining relationships - -With our tables fetched, we can now [define relationships](https://docs.budibase.com/docs/sql-datasource#defining-relationships) within Budibase. - -Click the `Define relationship` button below the **Table** section to get started, and setup the following relationships: - -* One REGION -> Many COUNTRIES -* One COUNTRY -> Many LOCATIONS -* One LOCATION -> Many DEPARTMENTS -* One DEPARTMENT -> Many EMPLOYEES - -Example relationship: One Country -> Many Locations - Example relationship: One Country -> Many Locations - - Once finished you should see a list of your defined relationships: -![](https://files.readme.io/4c0801f-Screenshot_2023-03-10_at_10.40.41.png) - It is also worth changing the [display column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column) on some of the tables so that the links are more human readable. For example edit the **REGION\_NAME** column of the **REGIONS** table and toggle on `Use as table display column`. -Setting the region name as the display column - Setting the region name as the display column - - -Linked region in the countries table is now human readable - Linked region in the countries table is now human readable - -
## Region map screen @@ -89,8 +54,6 @@ height: 100%; Next add three [Containers](doc:container). Within each container add a [Headline](https://docs.budibase.com/docs/displaying-text#headline) for each of the Regions: *Americas*, *Europe*, *Middle East and Africa*, and *Asia*. Add margin and adjust the container layouts as desired. -![](https://files.readme.io/fc68bd8-Screenshot_2023-03-29_at_09.49.42.png) -
## Country screen @@ -99,20 +62,10 @@ With our region map setup, we can add a country screen that will list the countr Click `Add screen` and select `List view`. -Adding an auto-generated screen - Adding an auto-generated screen - - Click `Continue`, select the **COUNTRIES** table, and then `Confirm`. -![](https://files.readme.io/ceceb7e-Screenshot_2023-03-27_at_14.28.55.png) - You will now see your new screen with a pre-populated countries [Table block](doc:table-block). Click `Configure columns` in the Settings Panel, `Add all columns`, and then click the `X` to remove the ID columns and the *REGIONS*. -Configuring table columns - Configuring table columns - - You can see the locations are showing an ID field value, which isn't ideal. We can improve this by changing the [display column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column). Navigate to the **LOCATIONS** in the **Data** section and set the *City* column to the display column. We can further improve the user experience by adding country flag images to each row, and allow users to search the columns. @@ -123,10 +76,6 @@ Untick the setting `Show button above table`. All the countries have already bee Adding searchable fields is straightforward. Within the settings panel, select the *COUNTRY\_NAME* and *LOCATIONS.CITY* options under the **Search Fields** property. -Selecting search fields - Selecting search fields - - The search fields will allow users to performa a "Starts with" search to find countries by name or city. ### Row flag icons @@ -151,16 +100,10 @@ if (country === "israel") { return `https://images.mapsofworld.com/${country}/${country}-flag.gif` ``` -![](https://files.readme.io/a16da66-Screenshot_2023-03-28_at_15.46.26.png) - ### Filter out countries with no locations We don't want to display countries if they have no departments. Click on the [Data provider](doc:data-provider) and `Define filters`. Add another filter to check if the locations relationship if empty. -Don't retrieve locations with no city - Don't retrieve locations with no city - -
## Linking the region to the country screen @@ -169,36 +112,18 @@ While the countries screen is setup, we still need to filter the countries by re First click on the *Screens* icon button on the left hand panel. In the *Settings Panel* on the right, edit the route to include a [URL variable](doc:url-parameters) for the **region\_name**. -Adding a region id to the countries screen - Adding a region name to the countries screen - - Next in the components view, click on the [Data provider](doc:data-provider) and `Define filters`. Click `Add filter`, selecting *REGION\_ID* equals binding: `{{ URL.region_name }}`. -Adding a filter on the Region ID - Adding a filter on the Region ID - - Next navigate to the `/home` screen. For each of the headline containers, click `Define actions` for the *On Click* property. Add the **Navigate To** action, and select the countries screen. Then replace `:region_id` with the particular ID (1-4) for the selected region. -Navigate to the Region ID - Navigate to the country screen for Region 2 (Americas) - - ### Adding the region name to the country screen Above the 'COUNTRIES' heading, add a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block) component, and nest the headline under it. Select the **REGIONS** table as the data source, and `Define filters`. Match the region ID against the ID passed in the URL. We can use the *default* handlebars helper to provide a title while in the builder. -Filter on the Region ID from the URL, or default to 1 - Filter on the Region ID from the URL, or default to 1 - - For the heading value, select the *REGION\_NAME* binding from the dropdown: -![](https://files.readme.io/d48887e-Screenshot_2023-03-29_at_10.48.01.png) -
## Displaying a list of departments @@ -209,8 +134,6 @@ In the `/countries/:region_id` screen, delete the **Details form block**. The co Now in the empty **Details side panel**, add a Repeater block, and nest a Headline component. The Repeater block should have **COUNTRIES** set as the data source, with a filter on the **\_id** column against the *State ID*. This state binding represents the ID of the clicked row. -![](https://files.readme.io/b1facbe-Screenshot_2023-03-29_at_10.59.23.png) - > 🚧 Filtering on '\_id' > > The **\_id** field represents a URL-safe encoded id string.\ @@ -218,46 +141,22 @@ Now in the empty **Details side panel**, add a Repeater block, and nest a Headli The headline value should bind to the *COUNTRY\_NAME* of the repeater block: -Selecting the country name from the repeater block - Selecting the country name from the repeater block - - Below the country name headline, add a [Divider](doc:divider) as well as another Repeater block. This will be for the **LOCATIONS** pulled from the relationship of the **COUNTRIES** datasource. -Selecting locations from the countries relationship - Selecting locations from the countries relationship - - Now within the Locations Repeater block, nest a [Cards block](https://docs.budibase.com/docs/blocks#cards-block) for the **DEPARTMENTS** relationship: -Selecting departments from the locations relationship - Selecting departments from the locations relationship - - The *Title* of the Cards block should bind to the \_City\_of the location, which can be selected from the drop-down. Scroll further down the right hand settings panel to get to the *Cards* section. Remove the *Subtitle* and *Description*, but add the following binding for the individual card *Title*: `{{ Departments Cards block.DEPARTMENTS.DEPARTMENT_NAME }}`. This can be selected from the dropdown. -Final Details side panel component tree - Final Details side panel component tree - - ### Hiding locations that have no departments Currently if a location has no departments, we will see the *No rows found* message. -No rows found because Stretford has no departments - No rows found because Stretford has no departments - - Ideally we should not display Stretford at all in this case. Click on the *Departments Cards block* and click on `Configure conditions`. Add a [Condition](doc:conditions) to hide the component if **LOCATIONS.DEPARTMENTS** is empty. -![](https://files.readme.io/4d4bf12-Screenshot_2023-03-29_at_12.43.43.png) - #### Result -![](https://files.readme.io/c4592c1-departments.gif) -
## Employees screen @@ -270,10 +169,6 @@ You can also eject the table block so that you can deselect some of the employee Back to the `/countries` screen, click on the *Departments Cards block*. Find the setting called `Link card title` and tick the checkbox. Under *Link screen* select the `/employees/:department_id` screen. There is no need to replace the **:department\_id** in this instance, as Budibase knows to replace this with the **\_id** of the repeater. -Linking the card title to the employees screen - Linking the card title to the employees screen - -
## Removing navigation links @@ -282,10 +177,6 @@ As both the employees screen and the countries screen require an ID in the URL, Click the [Configure links](https://docs.budibase.com/docs/navigation#configure-links) button and click the `X` to remove the link for employees and countries, and click `Save`. -Only display the home screen link - Only display the home screen link - -
## Managing departments @@ -294,24 +185,8 @@ Currently the departments listed for a location are read-only. It may be the cas Create a new auto-generated List view screen for the **DEPARTMENTS** table, but in this case select *Admin* access level. -Only Admin users can view this autogenerated screen - Only Admin users can view this autogenerated screen - - You will also want to make sure that the navigation link for the department screens only displays for admin users. Click on the [Navigation](doc:navigation) icon on the left hand pane, and `Configure links`. Beside the `/departments` link, click the dropdown and select *Admin*, then click `Save`. -The departments link will be visible to admin users only - default is basic - The departments link will be visible to admin users only - default is basic - - To verify the permissions, click `Preview` in the upper right hand corner of the **Design** view. You can toggle the user permissions in the blue bar along the top to test. - -Verifying that admin users can see the Departments link - Verifying that admin users can see the Departments link - - -Verifying that power users (and below) cannot view Departments - Verifying that power users (and below) cannot view Departments - From 1c72fca151340c8471b3ab4eba76c6a5511fb428 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 15 Jul 2026 10:26:37 +0100 Subject: [PATCH 20/32] more batched updates --- docs/Apps/app-state/index.md | 78 +++++-------------- .../app-state/state-explorer-interface.md | 59 ++++---------- .../introduction-to-apps/command-palette.md | 31 +++----- docs/Apps/progressive-web-apps.md | 43 ++++------ docs/Automation/automation-actions/looping.md | 24 +++--- docs/Automation/automation-actions/n8n.md | 74 +++++------------- .../automation-actions/query-rows.md | 64 ++++----------- docs/Automation/trigger/email-listener.md | 40 +++++----- docs/Automation/trigger/row-actions.md | 48 ++++-------- .../Automation/trigger/row-trigger-filters.md | 40 ++-------- docs/Automation/trigger/row-triggers.md | 22 ++---- 11 files changed, 153 insertions(+), 370 deletions(-) diff --git a/docs/Apps/app-state/index.md b/docs/Apps/app-state/index.md index 1048de67a..51dc705b7 100644 --- a/docs/Apps/app-state/index.md +++ b/docs/Apps/app-state/index.md @@ -14,77 +14,37 @@ next: slug: searchfilter-data title: Adding filtering --- -App state is a generic store of values that can be used to easily pass values around and persist them between navigation and page reloading. +App state stores values that can be read and updated anywhere in your app. -Unlike other Binding values, App state values can be set and used anywhere in your application. To set an app state value, you can use an action called `Update state` in the actions drawer. There are two types: Setting and Deleting. Set a key as the unique identifier; this is used when referencing the state value elsewhere in your app. You can select an already existing one or create one by typing in a name. After this, you can enter any value into the value input field. In addition to static values, you can also use Binding values here. +Use it when you need to carry data between components, screens, or navigation events. -![](https://files.readme.io/09f8b06-setting_state.png "setting_state.png") +## Set a value -## App state tutorial +Use the `Update state` action to create or change a state value. -The example below shows a simple way to use app state within a Budibase app. The overview includes creating a select input that will save the field value to state. This state value will then be used to show and hide components based on the selected value. +Each state entry has: -1. Add a [Form](doc:form) component\ - ![](https://files.readme.io/4d784154d9a9a0d6de9d89d32eb368589623ce06e0e1223b6c6aa2ccce459e72-Screenshot_2025-08-20_at_11.01.43.png) -2. Add a [Options picker](doc:options-picker) component, then change the `Options source` from schema to custom. -3. Click the `Define Options` button and add your options for this demo the options used are: Tables, Blocks and Images.\ - ![](https://files.readme.io/44cececb6f6001686c24594c0ab25ed399fea614b277d58251a693129f9c9080-Screenshot_2025-08-20_at_11.04.35.png) -4. After this click the `On change` button, search for the `Update state` action. Add this and then configure your state settings to something similar to the below.\ - ![](https://files.readme.io/82beba62e5d2c18c5ae7520a26f5e7fa8d8dac3f6ffeb570dcc6001ffccf6ce1-Screenshot_2025-08-20_at_11.05.07.png) -5. After this build out your page however you want, add additional options to your select input if you choose to. -6. Setup conditionals for the various components throughout using the `Configure conditions` button within the conditions tab. +* A key, which is the name you reference elsewhere +* A value, which can be static or bound to another source - +## Use app state -9. Repeat step 8 for the other options you want to apply conditions to +Once a value exists, reference it through the `State` binding namespace. -**Short Demo** +Common uses include: - +* Passing the selected row into a form or side panel +* Storing a temporary selection while a user moves through a multi-step form +* Showing or hiding components based on a user choice -### App state screen generation +## Persist a value -For more context on app state, some components already include this feature. A good example is the [Auto generate screens](doc:screens#autogenerated-screen) feature, where you can quickly see app state in action by generating screens based on preexisting data. This feature is particularly useful for generating screens with side panels or forms. Once generated, you can view these side panels and forms, and observe how state is applied to the edit form types. Additionally, if you navigate to the [Table](doc:table) component and click the `ON ROW CLICK` button, you will see some pre-generated actions that demonstrate state handling. +Enable persistence when the value should survive reloads. Budibase stores persisted state in the user's browser. - +## Delete a value -What this is doing is getting the clicked rows `_id` and adding it to a [Form Block](doc:form-block) which is automatically set to update. This newly created state key is then added into the `Details form block Row ID` field which is what is use to save any updates made back to that specific row. +Delete a state value when it is no longer needed. This removes the stored value and clears any persisted copy. -![Showing state being passed into the Row ID](https://files.readme.io/ca96089-small-Screenshot_2023-05-04_at_09.50.54.png) +## Related guide -### App state examples - -There are a range of different ways app state can be used within Budibase. A few examples can be seen below. - -* **Multiple step forms**, you can use App state to save the `_id` of the row which you are currently creating. App state can then be used to both save your place in the form and to save information at different stages back to your database as you process through your multiple step form. -* **[Form Block](doc:form-block)** As talked in the **App state demo** you can use app state to pass specific rows `_id` into forms. Whether this be a form within a [Side Panel](doc:side-panel) component or a form on a different page, app state can be used in both cases. - -### App state Github discussions - -* [Bindings & app state](https://github.com/Budibase/budibase/discussions/10094) logging active persisted app states. -* [Collapsible panel + conditional UI](https://github.com/Budibase/budibase/discussions/5763) Slightly more complicated use of state with conditional UI. -* [Table Filter with a button](https://github.com/Budibase/budibase/discussions/10402) Trigging search with a button click instead of on change using state. - -*** - -## Persisting values - -If you wish for the values that the user has selected to persist you can select the Persist this value checkbox beneath the key/value fields. Doing so will save the value in the users browser using the localStorage API. (A gif below has been attached to showcase the difference between persisted state and regular state.) - - - -*** - -## Deleting values - -Deleting a value will delete it permanently and will also override values that are persisted. (Below is an example of deleting state.) - -![Deleting state example](https://files.readme.io/5d79ad7-small-Screenshot_2023-05-05_at_12.28.00.png) - -*** - -## Referencing state values - -Once you have created a value you are free to bind to it across your application. All values live under the **State** top-level Binding value and are visible in the bindings drawer. - -For example, To get the value in the 1st image you would enter `{{ State.isPersonal }}`. The pre generated example image using the [Table Block](doc:table-block) component you'd have to enter `{{ state.ID_bI8jAVBgC }}`. +* [State explorer interface](doc:state-explorer-interface) diff --git a/docs/Apps/app-state/state-explorer-interface.md b/docs/Apps/app-state/state-explorer-interface.md index fa09995de..d989a1a4a 100644 --- a/docs/Apps/app-state/state-explorer-interface.md +++ b/docs/Apps/app-state/state-explorer-interface.md @@ -13,58 +13,25 @@ metadata: next: description: '' --- -## Overview +The State Explorer shows where a state value is set and where it is used on the current screen. -The State Explorer Interface provides users with greater visibility and control over state variables used within a screen. It enables users to see: +Use it when you need to trace a state value through a screen without hunting through components manually. -* Which state variables are in use -* Where they are being used -* Which components they are attached to +## Open the State Explorer -Previously, there was no way to track which state variables were used or which components they were associated with. This feature addresses that gap, improving debugging and interface management. +1. Open the **State** tab beside **Components** and **Bindings** +2. Select a state variable from the dropdown +3. Enter a temporary value if you want to preview the screen with sample data -## Accessing the State Explorer +## Read the results -To open the State Explorer Interface: +The State Explorer separates usage into two groups: -1. Navigate to the State tab to the right of Components and Bindings. -2. Click on the tab to reveal the State Variables selection field. -3. The first state variable in the list is selected by default. -4. To view a different state variable, select it from the dropdown list. +* **Controlled by** lists components that update the state value +* **Updates** lists components that read the state value - -5. Below the **State variables** selection field, you will see the **Set Temporary Value for Design Preview field**. +Use these lists to find the exact component or binding that needs to change. -### Set Temporary Value for Design Preview +## Jump to a component -The Set Temporary Value for Design Preview field allows users to input a temporary value for preview purposes. This field can either be manually typed into or set using available internal Budibase bindings, providing flexibility when testing or designing interfaces. - - - -## Understanding State Usage - -When a state variable is selected, the State Explorer displays relevant information about its usage within the current screen. This information is categorised into two sections: - -### Controlled By - -This category lists state variables that are set/modified. These include: - -* Input fields updating state -* Button on clicks that trigger state changes -* Other interactive elements affecting state values - - - -### Updates - -This section shows where the state variables are being used. Examples include: - -* A Paragraph component displaying the state value -* A Form Block applying the state variable to the RowID setting -* Data provider and or table filters - - - -## Navigating to Components - -For each entry in the Controlled By and Updates sections, the associated component is listed as a clickable item. Clicking on a component will navigate directly to its Settings or Binding area, allowing users to see and modify how the state variable is used. \ No newline at end of file +Click any entry in the list to open the related component settings or binding. This is the fastest way to update a state variable that is used in multiple places. diff --git a/docs/Apps/introduction-to-apps/command-palette.md b/docs/Apps/introduction-to-apps/command-palette.md index 360312c9a..6215af6ee 100644 --- a/docs/Apps/introduction-to-apps/command-palette.md +++ b/docs/Apps/introduction-to-apps/command-palette.md @@ -10,9 +10,7 @@ metadata: next: description: '' --- -The budibase command palette allows you to quickly navigate through your datasources, screens, and automations, as well as publish your app and view the app preview. It is designed to streamline your workflow and improve overall productivity when working on your Budibase projects. - -![](https://files.readme.io/d03601b-image.png) +The Command Palette gives you quick access to common builder actions without using the mouse. > 📘 Accessing the command palette > @@ -20,27 +18,20 @@ The budibase command palette allows you to quickly navigate through your datasou ## Accessing the Command Palette -To open the Command Palette: - -Press Ctrl + K (or Cmd + K on OSX) while inside the Budibase Builder. - -The Command Palette will appear, allowing you to search for and access various elements and actions within your app. +Press `Ctrl + K` on Windows or `Cmd + K` on macOS while you are in the builder. ### Features -* Search: Start typing the name of the element or action you are looking for, and the Command Palette will display the relevant results. You can use the arrow keys to navigate through the search results and press Enter to select a result. -* Datasources: Quickly access your project's datasources, databases and APIs. -* Screens: Easily navigate to any screen within your app. -* Automations: Navigate directly to any automation in your app. -* Invite users: Open the user invite panel to directly assign access and even invite new users into your budibase installation. -* App Preview: Open the app preview to test and debug your app. -* Change builder theme: You can even change the theme of your builder directly from the app panel. -* Publish App: Publish your app directly from the Command Palette, making it accessible to end-users. +Use the palette to: -![](https://files.readme.io/250b64e-image.png) +* Search for screens, datasources, and automations +* Open the app preview +* Publish the app +* Open the invite users panel +* Switch builder theme -## Closing the Command Palette +Start typing to narrow the results, then use the arrow keys and `Enter` to select one. -To close the Command Palette without selecting an option, press Esc or click anywhere outside the Command Palette. +## Closing the Command Palette -The Command Palette simplifies navigation and improves your productivity. With quick access to datasources, screens, automations, app publishing, and app previews, you can focus more on building amazing apps and less on navigating and clicking through the platform. +Press `Esc` or click outside the palette to close it. diff --git a/docs/Apps/progressive-web-apps.md b/docs/Apps/progressive-web-apps.md index d0c4cfa93..8c3bbadae 100644 --- a/docs/Apps/progressive-web-apps.md +++ b/docs/Apps/progressive-web-apps.md @@ -12,7 +12,7 @@ metadata: next: description: '' --- -To turn your Budibase app into a Progressive Web App (PWA), open the app in the builder and head to Settings >> Progressive Web App. Here you can configure +Use Progressive Web App settings to let users install your app on their device. > 📘 > @@ -26,51 +26,38 @@ To turn your Budibase app into a Progressive Web App (PWA), open the app in the | Short Name | Used to specify a short name for your web application, which may be used when the full name is too long for the available space.(Not supported in Firefox) | | Description | Displayed in the modal which prompts the user to download the PWA | -## Appearance +Set these values to control how the app is named in the install prompt and on the user's device. -
+## Appearance ### App Icons -In order to provide the required icons for all required formats, we recommend using a tool like [PWA Builder](https://www.pwabuilder.com/imageGenerator) to generate a .zip file containing all the required sizes and formats. The example below - -An example modal when a user clicks to download a PWA - An example modal when a user clicks to download a PWA, featuring the App Name and Description settings - +Generate the icon set with a tool such as [PWA Builder](https://www.pwabuilder.com/imageGenerator). Use the resulting sizes and formats for the app icon field. ### Colors -The Theme color chosen will be used for the app's title-bar. The Background color will be used while the app is loading, though behaviour may differ on some devices. - - - -
- - +The theme color controls the app title bar. The background color applies while the app is loading. ### Display Mode -Only available on mobile devices, these setting impacts how the app is displayed. Broken down explainations for each option are below. +Display mode affects how the app opens on supported devices. #### Standalone -* What it does: Displays the PWA in an app-like window without browser UI (no URL bar or tabs). -* Where supported: All platforms (desktop and mobile). -* Best for: General-purpose PWAs mimicking native apps. -* Benefit: Clean, app-like experience with some access to browser tools (mostly on desktop). +* Displays the app without browser chrome +* Supported on desktop and mobile +* Best for general-purpose installed apps #### Fullscreen -* What it does: Hides all browser UI, status bar, and navigation controls, giving your PWA full screen real estate. -* Where supported: Only on Android (native support); use Fullscreen API on desktop/iPadOS as a fallback. -* Best for: Immersive apps like games, VR/AR experiences. -* Benefit: Maximises visual space and immersion. +* Hides browser UI and uses the full screen +* Best for immersive experiences +* Support varies by platform #### Minimal UI -* What it does: Shows basic browser navigation (e.g., back/reload buttons or a title bar), but hides full browser chrome. -* Where supported: Android and desktop. -* Best for: Apps that benefit from slight browser context (e.g., light tools or content viewers). -* Benefit: Balances app-like feel with minimal navigation support. +* Shows a small amount of browser UI +* Best for apps that still benefit from basic browser context +* Support varies by platform More extensive information on this can be found [here](https://web.dev/learn/pwa/app-design#display_modes). diff --git a/docs/Automation/automation-actions/looping.md b/docs/Automation/automation-actions/looping.md index daf9ba988..593756617 100644 --- a/docs/Automation/automation-actions/looping.md +++ b/docs/Automation/automation-actions/looping.md @@ -14,35 +14,33 @@ next: --- > 🚧 Iteration hard limit > -> Users who self-host can configure this by changing the `AUTOMATION_MAX_ITERATIONS`environment variable. +> Users who self-host can configure this by changing the `AUTOMATION_MAX_ITERATIONS` environment variable. > > * For docker-compose users, update docker-compose.yaml > app-service > environment. > * For Kubernetes users update values.yaml > `automationMaxIterations` - - -The Loop step allows you to **repeat a single or series of automation actions across multiple records**. For example, when an automation is triggered, send an email to my top 10 contacts, and then update their status field. +The Loop step repeats one or more automation actions for each item in a list. ## Settings ### Binding / Value -Binding / Value is the actual value that you want to loop over +Binding / Value is the list or array that you want to iterate over. ### Max loop iterations -Max Iterations is a soft limit that is set by the user that defines how many times that automation will run (this is superseded by a hard limit that we or the self-hosting user sets) -` { "items": [ { "success": true } ], "iterations": 1, "success": false, "status": "MAX_ITERATIONS_REACHED" }` +Max loop iterations sets a soft limit for the step. The platform hard limit still applies. + +If the loop reaches the limit, it stops and returns a `MAX_ITERATIONS_REACHED` status. ### Failure conditions -Failure Condition stops the loop whenever the currentItem equals the value provided in the failure condition, then loop is then broken at that particular point and the results up to then provided -`{ "items": [ { "success": true }, { "success": true } ], "iterations": 2, "success": false, "status": "FAILURE_CONDITION_MET" }` +Failure Condition stops the loop when the current item matches the value you provide. -This leads to how we provide the bindings for each step. A block that is being looped gets provided the following binding (in addition to any previous blocks): +If the condition is met, the loop stops early and returns a `FAILURE_CONDITION_MET` status. - +## Bindings -Any blocks after the loop block get provided with the entire output, such as: +Steps inside the loop get the current item plus any bindings from earlier steps. - +Steps after the loop get the full loop output. diff --git a/docs/Automation/automation-actions/n8n.md b/docs/Automation/automation-actions/n8n.md index 7273b5c39..424d65c54 100644 --- a/docs/Automation/automation-actions/n8n.md +++ b/docs/Automation/automation-actions/n8n.md @@ -14,67 +14,36 @@ next: Within **n8n** create a [Webhook trigger node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/). Optionally configure the *Authentication*, and select the desired *HTTP Method*. - +Copy the webhook URL. Use the *Test URL* while you are building the workflow, then switch to the *Production URL* when you are ready. -Click on the webhook URL to copy it to clipboard. You can start with the *Test URL* to make sure things are working as expected before using the *Production URL*. - - - -Click listen for test event just before you run the automation in Budibase. - -Connect additional nodes to your **n8n** webhook trigger as desired. +Add any additional nodes you need after the webhook trigger. ## Budibase DB node It is also possible to connect to the Budibase DB within your **n8n** workflow using the [budibase-db-n8n-node](https://github.com/melohagan/budibase-db-n8n-node). Read more on installation: [Install community nodes in the n8n app](https://docs.n8n.io/integrations/community-nodes/installation/gui-install/). - -Install the Budibase DB node - Install the Budibase DB node - - -Budibase DB node will then be available - Budibase DB node will then be available - +After installing the community node, n8n exposes a Budibase DB node that you can add to your workflow. ## Triggering an n8n workflow from Budibase -First, we will create our automation in Budibase. For this example, we will use an [On demand](doc:app-action) automation. - -With the webhook setup in **n8n**, and the URL copied, you can now add the `n8n` automation action step in your automation. - -Adding the n8n action step - Adding the n8n action step - - -Next enter the *Webhook URL* that you copied, and make sure the *Method* matches correctly. +Create or open a Budibase automation. For this example, use an [On demand](doc:app-action) automation. -Triggering an n8n workflow from a Budibase automation - Triggering an n8n workflow from a Budibase automation - +Add the `n8n` automation action step, paste the webhook URL, and match the HTTP method to the n8n node. -After running a test of the automation in Budibase. You should see the output on N8N. - - +Run a test. If the webhook is configured correctly, the execution appears in the n8n workflow history. ### Authorization -The authorization field is optional, and represents the [Authorization HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization). - -Consider an **n8n** webhook with *Basic* authentication set as *user*: 'test', *password*: 'admin'. - - - -The automation action step will return with a `401` error if the *Authorization* field is not set: +The Authorization field maps to the [Authorization HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization). -Authorization needs to be set - Authorization needs to be set - +For Basic auth, provide the header in this format: -In the case of *Basic* auth you need to provide the header in the following format:`Basic BASE64_ENCODED(username:password)`, which would look result in something like this: +```text +Basic BASE64_ENCODED(username:password) +``` - +If the header is missing or malformed, the request returns `401`. > 🚧 Keep credentials safe > @@ -88,17 +57,10 @@ In the case of *Basic* auth you need to provide the header in the following form This is going to be a very simple example. -1. Add a query step before you n8n automation step. - - -2. For this example, we are going to limit the objects queried to 2 -3. Add a JavaScript step and return the query rows. This will format the array in a way that will be accepted by n8n. - - -4. Pass the query step output inside the n8n payload -5. Test and send - - -6. Output in n8n +1. Add a query step before the n8n action step +2. Limit the query result set if needed +3. Add a JavaScript step that returns the query rows in a payload shape n8n accepts +4. Pass the JavaScript output into the n8n payload +5. Test the automation - +The output should appear in the n8n execution history with the payload you sent from Budibase. diff --git a/docs/Automation/automation-actions/query-rows.md b/docs/Automation/automation-actions/query-rows.md index 7ccb091cf..67398e3a6 100644 --- a/docs/Automation/automation-actions/query-rows.md +++ b/docs/Automation/automation-actions/query-rows.md @@ -10,63 +10,31 @@ metadata: next: description: '' --- -The query rows action allows you to pull data from a table, with several filtering and sorting options available. +Use the Query Rows action when an automation needs a filtered result set from a table. -Query rows action - Query rows action - +## Configure the table -
+Choose the table first. Then set optional sort column, sort order, and limit values. -### Table +Budibase applies a maximum result limit: -The first dropdown requires that you select a table. +| Internal DB | SQL DB | +| :-- | :-- | +| 1000 rows | 5000 rows | -If you forget to choose a table, the error output of the automation will inform you. +## Add filters -Make sure to select a table for your Query Rows action! - Make sure to select a table for your Query Rows action! - +Click `Define filters` to restrict the rows returned. Filters can use either static values or [Bindings](doc:data-in-automations). -With a table selected, you can select an optional **Sort Column** and **Sort Order**. If these fields are left blank, then the rows will be returned in no particular order. +Use the **When filter empty** setting to decide what happens if a binding resolves to an empty value: -You can also choose to add an optional **Limit** to the number of rows returned, otherwise the default maximum limit will be used. +* Return all rows +* Return no rows -| Internal DB | SQL DB | -| :-------------------------------- | :-------------------------------- | -| Maximum of **1000** rows returned | Maximum of **5000** rows returned | +If you plan to loop over the result set and then update or delete those rows, make sure blank bindings do not return an unexpected set of records. -
+## Use the output -### Filtering +The output is available as `{{ steps.X.rows }}` where `X` is the Query Rows step number. -You may provide filters when querying table rows by clicking the `Define filters` button. Filters can be against static values, or against [Bindings](doc:data-in-automations). - -Filtering rows - Filtering rows (static value and binding examples) - - -The final setting is labelled **When filter empty**. This determines what data is returned if a Binding value is used in a filter, but is empty. - -For example, in the screenshot above we filter on the `{{ trigger.fields.Name }}` binding. If that binding was empty, then you have the choice of returning: - -* All table rows -* No table rows - -> 🚧 Update/Delete rows -> -> If you are looping over the output of a **Query Rows** action to perform updates or deletes in the next step, it is important that you consider what happens if your binding is blank. - -
- -### Using the query rows output - -You can access the output of a **Query Rows** action through the Binding: `{{ steps.X.rows }}`, where 'X' is the step number of your action. - -For example you would use `{{ steps.1.rows }}` for the following action: - -Step 1: Query Rows - Step 1: Query Rows - - -This binding is particularly useful in automation [Looping](doc:looping), where you want to perform an action for each row retrieved. +For example, `{{ steps.1.rows }}` returns the rows from the first Query Rows action. This is commonly used with [Looping](doc:looping). diff --git a/docs/Automation/trigger/email-listener.md b/docs/Automation/trigger/email-listener.md index 97fcb5644..6b6781301 100644 --- a/docs/Automation/trigger/email-listener.md +++ b/docs/Automation/trigger/email-listener.md @@ -7,25 +7,29 @@ metadata: description: kba_5hdtu robots: index --- -The Email Received automation triggers whenever a new email arrives in a mailbox that you've connected to. It connects to your IMAP server (Gmail, Outlook, Microsoft 365, or any IMAP-compatible provider), checks for new messages on a short polling interval, and fires when an email matches your conditions. When it runs, the trigger exposes the message’s subject, sender, recipients, date, plain-text, and HTML body so you can use them in later steps. +The Email Received trigger runs when Budibase finds a new message in a connected mailbox. It polls an IMAP server, checks for unread messages, and exposes the email subject, sender, recipients, date, plain-text body, and HTML body for later steps. -If your flow also needs to send or reply to emails, set up SMTP first. The IMAP trigger doesn’t require SMTP to receive messages, but you’ll need SMTP for outbound mail. For a quick setup guide, follow the steps on the Email (SMTP) setup page here. +If you also need to send email, configure SMTP separately. Receiving messages only requires IMAP. ## Setup -To configure the trigger, create a new **Email received** type automation. Click on the initial step and enter your IMAP host and port, enable SSL/TLS, and provide the mailbox username and password +To configure the trigger: - +1. Create a new **Email received** automation +2. Open the trigger step +3. Enter the IMAP host and port +4. Enable SSL/TLS if required +5. Add the mailbox username and password -Showing the various configuration settings to get the email listener setup +Use the mailbox settings to point Budibase at the folder you want to monitor. In most cases you only need the host, port, security settings, username, and password. -The Email received trigger listens to the mailbox you set up within the initial step of the automation. When a new email arrives, Budibase detects it, converts the message into a payload (subject, from/to, date, body text/HTML), and starts your automation. You can then map those fields in downstream steps (e.g., create a record with From/To/Body). Budibase tracks each email’s UID, so the same message won’t trigger twice. +When a new email arrives, Budibase converts it into a payload and starts the automation. The same message will not trigger twice. ## Microsoft 365 / Azure Entra ID -If your mailbox is hosted in Exchange Online, the Microsoft guide on enabling IMAP access is relevant for the mailbox-level settings, but Budibase also needs an OAuth2 connection and Exchange Online app/service-principal setup. +If your mailbox is hosted in Exchange Online, you also need OAuth2 and mailbox-level IMAP access. -Budibase's IMAP trigger uses the OAuth2 client credentials flow for machine-to-machine access. In practice, that means: +Budibase's IMAP trigger uses the OAuth2 client credentials flow for machine-to-machine access. Configure it as follows: 1. Create an OAuth2 connection in Budibase under **Workspace Settings > Connections > APIs**. 2. Set the token endpoint to your Entra tenant, for example `https://login.microsoftonline.com//oauth2/v2.0/token`. @@ -33,7 +37,7 @@ Budibase's IMAP trigger uses the OAuth2 client credentials flow for machine-to-m 4. Set the scope to `https://outlook.office365.com/.default`. 5. In the **Email received** trigger, choose **OAuth2** as the authentication method and select the Budibase OAuth2 connection. -For the Exchange Online side, the mailbox must allow IMAP and the app must be granted access to the mailbox. A working setup looks like this: +The mailbox must allow IMAP and the app must have access to it. A working setup looks like this: ```powershell Connect-ExchangeOnline -UserPrincipalName redacted@bongotown.onmicrosoft.com -Device @@ -71,22 +75,16 @@ If IMAP does not appear in the app registration's API permissions, add the Excha } ``` -The Graph `User.Read` entry above is included from the working tenant setup that was shared with us. Budibase's IMAP trigger does not require Microsoft Graph for mail polling itself; the important part is the Exchange Online IMAP permission and mailbox access. +The Graph `User.Read` entry above comes from the working tenant setup that was shared with us. Budibase does not need Microsoft Graph for polling itself. The important part is Exchange Online IMAP access plus mailbox permission. -`your-graph-scope-id` should be replaced with the scope ID for the Graph permission you grant, and `your-exchange-online-role-id` should be replaced with the Exchange Online role ID from your tenant setup or the value your engineer provides. +Replace `your-graph-scope-id` and `your-exchange-online-role-id` with the values from your tenant. -The Microsoft article is mainly useful for the IMAP mailbox setting itself: Microsoft Learn. +The Microsoft article is mainly useful for the mailbox IMAP setting itself: Microsoft Learn. ## Example -This is an example of how you can use Budibase's email automation trigger to populate a table with the contents of an email. This is useful when testing this feature, as you can see what is being output from the automation +Use the trigger outputs to map the message subject, sender, and body into a table. - +When an email is received, trigger a create row action and map `_body`, `_from`, and `_subject` into the target table. If the subject is empty, you can still create the row from the sender and body fields. -When an email is received, it triggers the _create row_ action, which we have set up to populate our 'emailz' table based on three fields: _body_, _from_, and _subject_. These have been selected from the Email's trigger outputs - - - -Now, each time an email is received, Budibase runs the automation and creates a new row in 'Emailz' with the sender’s email address in _from_ and the message content in _body_. There may not always be a subject, but if there is, it will be in _subject_ - - \ No newline at end of file +Each time an email is received, Budibase runs the automation and creates a new row with the sender, body, and subject values. diff --git a/docs/Automation/trigger/row-actions.md b/docs/Automation/trigger/row-actions.md index 073ee89ac..099101070 100644 --- a/docs/Automation/trigger/row-actions.md +++ b/docs/Automation/trigger/row-actions.md @@ -12,55 +12,39 @@ metadata: next: description: '' --- -A Row Action is configured against the table but can be enabled or disabled per view. This allows you to control which users can trigger specific workflow stages. +Row actions let you trigger a workflow from a table row. -Using row actions allows you to securely ensure that only specific users with the correct permissions can progress row data through a pipeline +Configure the action on the table, then enable it per view to control who can run it. ## Setup -Below are the steps on how you can setup your first row action. - 1. Go to the data and select the table/view you wish to create a row action on 2. Click the **Row actions** button beside **Access** above your table - - + This opens the row action controls for the selected table or view. 3. A context menu will appear, providing you with some information about row actions 4. Click the **Create row action** button -5. You will be prompted with a modal. Type a relevant name for the row action e.g. accept, deny, assign etc - - +5. Type a name for the row action, such as `accept`, `deny`, or `assign` 6. Click the **Create** button -7. You will now be redirected to the row action automation. You can begin building out your workflow for this row action here - - -8. Returning to your table, you can see how many row actions have been created for a table. You can also create views with relevant access roles. This will carry over to your row actions. If a certain user doesn't have the correct permissions, they won't have access to the row action. These can be managed on a view-per-view basis by toggling them on and off. - - -9. After toggling these on, you should see a new dropdown button on the table's right-hand side. - - -10. Clicking on the dropdown button on the far right will display all available row actions. You can then click one of the row actions to trigger the corresponding workflow. - - +7. Build the automation that should run for this row action +8. Return to the table and enable the action for the views and roles that should see it +9. Users will then see a dropdown on the table row with the available actions ## Design -A new action with the same name has been added to trigger these row actions. You can learn more about configuring this action [here](doc:data-actions#row-action). +Row actions are also available as a design-time action. See [Row action](doc:data-actions#row-action) for configuration details. -From the design perspective, there are two ways to quickly add row actions to your components. +There are two common ways to add them to a screen: -The first is with a [table](doc:table) component. Start by adding a table component to your design area. Select the table component, scroll to the bottom of its settings, and click `Add button`. This will let you choose either a custom button or a row action. The button title will match the name of your row action. +1. Add a [table](doc:table) component and use `Add button` in the settings panel. +2. Choose a custom button or a row action. +3. The button label matches the row action name. - +The button appears in the table and can be made collapsible if you have several actions. -When selected, a new button will appear in the table. You can review the button's settings to see how it’s configured. There is also an option to make the button collapsible, which is helpful when you have numerous buttons attached to the table, as they will be grouped into a dropdown menu. - -Once everything is set up, users can use these buttons to trigger your row action automation, allowing users to process your workflows. +You can use the button to trigger the row action automation directly from the table. ### Form block -A [form block](doc:form-block) can also generate buttons with row actions. The setup here is even easier than the table, as it will auto-generate the button based on your selected schema. Ensure you use an update form type, as row actions are meant to progress existing data through a workflow. - - +A [form block](doc:form-block) can also generate row action buttons automatically. Use an update form type so the action works on existing data rather than creating new rows. -You can also add a [Row action](doc:data-actions#row-action) to any component that allows [actions](doc:actions) to be applied. \ No newline at end of file +You can add a [Row action](doc:data-actions#row-action) to any component that supports [actions](doc:actions). diff --git a/docs/Automation/trigger/row-trigger-filters.md b/docs/Automation/trigger/row-trigger-filters.md index bd8d30fb3..2e1e4f334 100644 --- a/docs/Automation/trigger/row-trigger-filters.md +++ b/docs/Automation/trigger/row-trigger-filters.md @@ -10,42 +10,18 @@ metadata: next: description: '' --- -# Row Triggers with Filters +Row trigger filters let you limit when a row created or row updated automation runs. -## Overview +## Use filters -Row triggers allow you to automate actions based on changes in your database. With the addition of filters, you can now create more specific triggers that only fire when certain conditions are met. +Add a filter when the automation should only run for rows that match a specific condition, such as an `Approved` flag or a particular status value. -## Types of Row Triggers +## Row created -1. **Row Created**: Triggers when a new row is added to the database. -2. **Row Updated**: Triggers when an existing row is modified. +For row created triggers, the filter is checked against the new row. If the row matches, the automation runs. -## Adding Filters to Triggers +## Row updated -Both "Row Created" and "Row Updated" triggers now support filters. Filters allow you to specify conditions that must be met for the trigger to fire. +For row updated triggers, the automation only runs when the row changes into a matching state. -### Example filter - - - -This filter would cause the trigger to fire only when the Approved column of the affected row equals "true". - -## Special Behavior for Row Updated Trigger - -The Row Updated trigger has a special behavior when filters are applied: - -By default, the trigger will only fire when a row transitions from not meeting the filter criteria to meeting the filter criteria. - -### Example - -Consider a filter: `Status = Approved` - -* The trigger will fire when a row's status changes from "Requested" to "Approved". -* The trigger will not fire if a row's status is already "Approved" and some other field (like "Due Date") changes. - -This behavior ensures that the trigger only fires when the specific condition you're interested in is met, rather than on any update to a row that already meets the condition. - -## Row Created Trigger Behavior - -For the Row Created trigger, the filter is applied to the newly created row. If the new row meets the filter criteria, the trigger will fire. \ No newline at end of file +For example, if the filter is `Status = Approved`, the trigger runs when a row changes from `Requested` to `Approved`. It does not run again on later edits if the row is already approved. diff --git a/docs/Automation/trigger/row-triggers.md b/docs/Automation/trigger/row-triggers.md index eb8bfa1c7..52bafed68 100644 --- a/docs/Automation/trigger/row-triggers.md +++ b/docs/Automation/trigger/row-triggers.md @@ -12,28 +12,20 @@ metadata: next: description: '' --- -## Row created +Row triggers let you run an automation when a row is created, deleted, or updated. -This trigger type allows users to create automations based on newly created rows. When a row is created, the entire row’s object will be passed to the automation and referenced through trigger Bindings. Various steps can be added to manipulate the data, such as updating information in another table or sending the data to a [REST API](doc:external-data-connector) endpoint. +## Row created - +Use this trigger when a new record should start a workflow. The trigger passes the full row object into the automation, so later steps can create related records, send notifications, or sync the new data to another system. ## Row deleted -This trigger works similarly to created rows. It will pass in a row’s object whenever a row is deleted. This can then be used to do other operations e.g. removing it from an API or deleting a related row elsewhere within Budibase. - - +Use this trigger when the workflow should react to a delete. Common uses include cleaning up related records, revoking access, or logging the change elsewhere. ## Row updated -Like the other two triggers listed above, this automation will run whenever a row within the chosen table is updated. - - - -It will provide both the old row's object (before the change). Additionally you also have access to the current values these are displayed as Bindings the names will reflect the columns of your table. - - +Use this trigger when a workflow should react to edits on an existing row. The trigger exposes both the previous row values and the updated row values, so you can compare fields and branch the automation based on what changed. -With the addition of the oldRow object, you can now perform more complex operations, such as testing if a specific value has changed and then continuing or ending the automation based on that condition. +## Typical outputs -This trigger can also be used similarly to the creation and deletion triggers, such as updating additional related records or posting updates to an API or query. +The row payload is available as trigger bindings. For updates, the automation also receives the old row object, which is useful when you only want to continue if a specific field changed. From 986487f7626cf9a257279231060c1968ed0bb153 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 15 Jul 2026 11:10:52 +0100 Subject: [PATCH 21/32] large batch update --- docs/Apps/actions/application-actions.md | 69 ++-- docs/Apps/actions/data-actions.md | 149 ++------ docs/Apps/blocks/form-block.md | 120 +----- docs/Apps/blocks/index.md | 157 ++------ docs/Apps/blocks/more-blocks.md | 66 +--- docs/Apps/blocks/multi-step-form-block.md | 104 +---- docs/Apps/blocks/table-block.md | 76 +--- docs/Apps/chart/area-chart.md | 194 ++-------- docs/Apps/chart/bar-chart.md | 185 ++------- docs/Apps/chart/index.md | 64 ++-- docs/Apps/components/accordion.md | 62 +-- docs/Apps/components/card.md | 83 ++-- docs/Apps/components/container.md | 360 ++---------------- docs/Apps/components/index.md | 12 +- docs/Apps/components/tag.md | 49 +-- docs/Apps/forms/field-groups.md | 42 +- docs/Apps/forms/form-bindings.md | 158 +------- docs/Apps/forms/form-steps.md | 125 +----- docs/Apps/forms/form-validation.md | 49 +-- docs/Apps/forms/index.md | 35 +- docs/Apps/forms/save-static-value.md | 13 +- docs/Apps/pickers/date-picker.md | 53 +-- docs/Apps/pickers/index.md | 40 +- docs/Apps/pickers/option-picker.md | 185 ++------- .../adding-a-search-field.md | 103 +---- .../working-with-data/adding-search-copy.md | 98 +---- docs/Apps/working-with-data/data-provider.md | 105 ++--- docs/Apps/working-with-data/fetching-data.md | 25 +- docs/Apps/working-with-data/index.md | 29 +- docs/Apps/working-with-data/repeater.md | 52 +-- .../working-with-data/searchfilter-data.md | 55 +-- .../working-with-data/single-row-provider.md | 47 +-- 32 files changed, 604 insertions(+), 2360 deletions(-) diff --git a/docs/Apps/actions/application-actions.md b/docs/Apps/actions/application-actions.md index 671405d6e..8301cfdbc 100644 --- a/docs/Apps/actions/application-actions.md +++ b/docs/Apps/actions/application-actions.md @@ -1,8 +1,6 @@ --- title: Application actions -excerpt: >- - These actions can be anything from notifications, to triggering automations or - navigating between screens. +excerpt: Actions for navigation, notifications, modals, and automations. deprecated: false hidden: false metadata: @@ -16,69 +14,58 @@ next: slug: form-actions title: Form actions --- -## Navigate To - -Use this action if you want to go to another web page or app screen.\ -For example: [Navigation on row button click](doc:url-parameters) - -When the *Destination* is set to 'URL', you have the option to open the link in a new tab. - -![](https://files.readme.io/8f018e8-new_tab.png) +Use application actions when a user interaction should change screens, open UI, show feedback, or trigger automation. -Alternatively, if the *Destination* is set to 'Screen', then you can select a screen to navigate to from the dropdown. The screen can optionally be opened in the current tab, or in a [modal](https://docs.budibase.com/docs/screens#modal-screen). +## Navigate To -You can learn more about using URL parameters with the `Navigate To` action [here](https://docs.budibase.com/docs/url-parameters). +Use this action to open a URL or another screen. -![](https://files.readme.io/a455654-open_modal.png) +If the destination is a URL, you can open it in a new tab. -## Trigger Automations +If the destination is a screen, you can open it in the current tab or in a modal. -Often there are times where you would like to trigger a automation after a user has performed an action. There are a range of different [Automations](doc:custom-automations). You are able reference any created automations by clicking the `Use an existing automation` radio button and then selecting an existing previously created automations to use and run. +## Trigger automations - +Use this action to run an existing automation. -Lastly, creating fields within the automation itself allows data/bindings to be sent to it, this can then be used in your automation to perform whatever task you require. An example of this would be passing an `_id` of a row to the automation to then update the row's state e.g. from `Pending` to `In progress`. +Pass values into the automation with fields on the action. - +This is useful when a user action should kick off a background process. ## Logout -If you want to log a user out, you can use this action. It has redirect functionality built in meaning you can redirect to whatever url you desire. - -## Close Screen Modal - -If the current screen has been opened as a [Modal](https://docs.budibase.com/docs/screens#modal-screen), then close it. Additionally, you can navigate to a new screen or open a different screen modal afterwords also using this action. +Use this action to sign the current user out and optionally redirect them. -## Close Modal +## Close screen modal -This action takes no settings, and will close any modal component open on screen. +Use this action to close the current screen modal. -## Open Modal +You can also navigate to another screen after closing. -Opens a modal component on a screen - different to a "Navigate to" action with "Open screen in modal", which opens an entire screen in a modal, this action opens a modal component that is already on the current screen. See [modal component]() +## Close modal -## Show Notification +Use this action to close the currently open modal component. -This allows you to show a popup notification, of which there are four different types; `Success`, `Warning`, `Error` and `Info`. Changing the type will change the styling of the popup for example: success will be have a green background where as error will have a red background. Additionally you can make use of the bindings to output more informative messages. E.g. `Hi {{ Current User.email }} welcome to Budibase.` +## Open modal - +Use this action to open a modal component that already exists on the current screen. -### Logic within notifications +## Show notification -It is possible to use some logic with the notification - if the result of the logic running is falsy, no message will show. This can be used in conjunction with a "Continue if/Stop If" step to show the user some feedback explaining why the action has stopped. +Use this action to show a success, warning, error, or info message. -## Prompt User +You can include bindings in the message text. -This action adds an additional step before other actions are run. The title, message, and button text can all be customised. It provides a prompt to the user, and won't run any other action after it unless they click the confirm button. This is very useful for a longer chain of actions, as it provides context and gives the option to cancel the process before it starts +## Prompt user -![](https://files.readme.io/8499167ec5c02eb383158fb8bf283960a3e4426483ae9edb667a76707e8179df-image.png) +Use this action to confirm a user decision before continuing a chain of actions. -
+If the user cancels, later actions do not run. -## Open Side Panel +## Open side panel -Provides a list of all side panels within a current screen, selecting one will open that side panel whenever the action is hit. +Use this action to open one of the screen's side panels. -## Close Side Panel +## Close side panel -Closes the currently open side panel. +Use this action to close the currently open side panel. diff --git a/docs/Apps/actions/data-actions.md b/docs/Apps/actions/data-actions.md index ffbd701a6..a631b95bf 100644 --- a/docs/Apps/actions/data-actions.md +++ b/docs/Apps/actions/data-actions.md @@ -1,6 +1,6 @@ --- title: Data actions -excerpt: These are data based actions; CRUD and other data manipulations. +excerpt: Actions for saving, updating, exporting, and fetching data. deprecated: false hidden: false metadata: @@ -14,153 +14,68 @@ next: slug: application-actions title: Application actions --- -## Save Row +Use data actions when user input should create, update, delete, export, or refresh data. -Saving a row can mean two things: updating or adding a new row. Depending on what you want to do you will have to structure this action differently. +## Save row -If you're adding, updating or viewing any row the easiest way is to add a [Form Block](doc:form-block) component. Here you can choose to create, update or read, depending on your selection you will be prompted with additional fields. For update and read you will have to pass in the `Row ID` into the row field, this is what will be use to update the specific record back to your chosen data source. In this instance you don't have to worry about the `Save Row` action as it already preconfigured for you. (You can [eject blocks](https://docs.budibase.com/docs/blocks#ejecting-blocks) if you want to see a good example of how the `Save row` action is configured). However, if you did go down the regular [Form](doc:form) route your save row action would look something to the below. +Use this action to create or update a row. - +If you are using a form block, the save action is already configured for you. -Updating a row can be done in a number of different ways. If you have a structure containing a [Data provider](https://docs.budibase.com/docs/data-provider) and a [Repeater](https://docs.budibase.com/docs/repeater), selecting the repeater as your Datasource will make it so you can correctly get the values from the specific row. To change a field you then take advantage of the add column button that is at the bottom. Click it, select the field you want to change, and type in the value you want to change it to (or use a binding). A descriptive image of this is shown below: +For custom forms, add the columns you want to update and bind the values into the action. - +When updating a row directly, provide the row `_id`. -If you are not using a repeater, an alternative way to update a row is to add the **\_id** column and provide a value that matches an existing id.\ -For example, you could be passing a task id in the URL: +## Duplicate row - +Use this action to copy a row into another table with matching columns. -## Duplicate Row +If the action is triggered from a row button, the row context can supply the source row automatically. -This action allows you to clone a row into any table with shared column names.\ -If you are performing this action from a row button click, then no **\_id** needs to be provided. +## Delete row -Alternatively, your button could be nested within a [Repeater](https://docs.budibase.com/docs/repeater). The below example shows how this would be setup with a repeater. - - - -## Delete Row - -This action is used to delete rows from your data source. It's used much in the same way that you would when updating a row. The main difference being you don't have to select a data source. You only have to select the table and pass the correct `Row ID` binding. For this example we will pass the `Row ID` via a [URL variable](doc:url-parameters), then the `Row ID` will be passed into the delete on click action used to delete the record from the [Budibase DB](doc:budibasedb). - - +Use this action to delete a row by table and row ID. ## Fetch row -This action allows you to fetch a table row from any table within your app. This action works the same `Delete Row` where you have select a table and reference the `Row ID`. - -![Fetched row action example.](https://files.readme.io/35152f1-Screenshot_2023-05-18_at_11.07.01.png) - -This can be used alongside other actions a good example of this is with [App state](doc:app-state). You can fetch the row then create a state to hold all the data related to the row fetched. This can then be used to as the basis to bind to different components within your app. - -Below there is a simple demo showing this in action. This is a very simple demo and its only outputting the entire fetch object to a paragraph component. You can break this up into multiple components and output different parts of the object if you so choose. - - - -## Execute Query - -The `Execute Query` action requires separate configuration as the queries need to be setup before they can be used by this action within your apps. There are many ways to use this action. For instances, you can use it to send the query results to a [REST API](doc:rest), retrieve results from a query created using an [External data source](doc:data-sources), and so on. - -In the example below we will be focusing on using this with a REST datasource. This example won't be too in-depth and shall only show a basic get REST query. This will also be used in a similar fashion to `Fetch rows` action, where we will storing it as state to display the object. - - - -For anything more advance have a read through the [REST API](doc:rest) docs. It will show you how to import and configure everything necessary to perform a more advanced action. - - - -## Refresh Data Provider - -This is mainly used for [External datasources](doc:data-sources) for example the [REST API](doc:rest) as it requires the recalling of queries in order to refresh [Data providers](doc:data-provider) after other actions have been performed. A good example for this is when you update a user record within a [Form](doc:form) inside a [Side panel](doc:side-panel). Once updated you would want to chain the `Refresh Data Provider` action afterwards to refresh the changes made without having to refresh the page to see these changes. Another example of this might be for the [Candlestick Chart](https://docs.budibase.com/docs/candlestick-chart) where new data is available over time, and it may be useful to refresh at the click of a button. - -## Update State - -Allows you to set a state value, or delete the key entirely. When entering an identifying *Key* you can select an existing one from the dropdown, or simply manually type into the text box to create a new key. - - - -Your state variable can then be accessed, anywhere in your app, via the state Binding, in this case: `{{ State.employee_id }}`. - -See [App state](doc:app-state) for further reading and examples. - -## Upload File To S3 - -To be used with the [S3 File Upload](doc:s3-file-upload) component. - -## Export Data - -This action is used to export selected rows within a table to either a CSV or JSON file. To set this up quickly add a [Table](https://docs.budibase.com/docs/table) component to a screen, and set it to display the Employees table from the sample BudibaseDB data. Add a button component underneath, and add an On Click action "Export Data". - - - -Once this has been done, it should export the rows selected and output it as the selected export. - - - -![Downloaded CSV due to the result of the export data action.](https://files.readme.io/bb41e11-Screenshot_2023-05-19_at_07.57.15.png) - -#### Configure delimiter - -The default delimiter (separator) for CSV exports is a comma `,` . It is however possible to change this to one of a preset list of options. This feature does not apply to JSON file exports. - -Using the tab key delimiter - Using the tab key delimiter - - -#### Configure export columns - -By default *all* table columns will be included in the export, however you can use a subset and provide custom labels. - -Click the *Export columns* button and add the specific columns you want to export. You can also drag-and-drop the columns to rearrange the column order in the export. +Use this action to read a single row and pass it into state or another component. -Only include these three columns in the data export - Only include these three columns in the data export - +## Execute query -Exported CSV file - Exported CSV file - +Use this action to run a saved query. -## Clear Row Selection +This is common for REST queries and external datasources. -Deselects any selected rows of the chosen table. +## Refresh data provider - +Use this action to reload a data provider after another action changes data. - +## Update state -Can also be useful in combination with the **Open Side Panel** action. +Use this action to set or clear an app state value. -## Download File +## Upload file to S3 -Initiates the download of a specified file or files. +Use this action with the [S3 File Upload](doc:s3-file-upload) component. -### Download from Attachment +## Export data -![](https://files.readme.io/44a00e9-image.png) +Use this action to export selected table rows as CSV or JSON. -Specify the table and column from which the file(s) will be downloaded - only columns that have the type `Single Attachment` or `Multi Attachment` will appear in the `Column` dropdown. +You can choose the delimiter for CSV exports and limit the exported columns. -Downloading from Multi Attachment columns will result in a `.zip` file containing all items being downloaded with a filename comprising of the name of the [Display Column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column) followed by the name of the Multi Attachment Column. +## Clear row selection -### Download from URL +Use this action to deselect any currently selected table rows. -![](https://files.readme.io/73c0df1-image.png) +## Download file -Specify the URL of the file to be downloaded. If `File name` is left blank the file downloaded will be named "undefined" and appended with the file extension. +Use this action to download a file from an attachment column or a URL. ## Row action -With V3, a new automation called [Row Actions](doc:row-actions) was introduced. This allows for a data action that triggers specific automations. The Row Actions action includes four configurable settings: +Use this action to trigger a row action automation. -1. **Table or View** - 1. Specify the table or view where the row action has been created -2. **Row ID** - 1. Provide the Row ID that the row action will use. -3. **Row Action** - 1. Select the specific row action you want to trigger -4. **Require Confirmation** - 1. This is a checkbox option. A modal will appear when selected, requiring user confirmation to trigger the row action automation. Additional fields will be displayed, enabling you to customize elements of the modal, such as the title, body text, and button labels. +You must provide the table or view, row ID, and row action to run. - \ No newline at end of file +Enable confirmation if users should confirm before the automation starts. diff --git a/docs/Apps/blocks/form-block.md b/docs/Apps/blocks/form-block.md index cb393a895..6d91ccf8e 100644 --- a/docs/Apps/blocks/form-block.md +++ b/docs/Apps/blocks/form-block.md @@ -10,121 +10,37 @@ metadata: next: description: '' --- -Form blocks combine all the necessary components to build a comprehensive and flexible form. +Use the Form block to create a form quickly from a table, view, or relationship schema. -There are three key types. +## Types -| Type | Fields | Save button | -| :----- | :------------------------------------------------------------------------- | :--------------------------- | -| Create | Provides blank fields to be filled out. | Creates a new row. | -| Update | Provides pre-populated fields based on the record that matches the row ID. | Updates the existing record. | -| View | Provides pre-populated *read-only* fields based on the provided row ID. | N/A | +| Type | Behavior | +| :-- | :-- | +| Create | Starts with blank fields and creates a new row | +| Update | Loads row data and updates an existing row | +| View | Loads row data as read-only | -Next you can select a table which will provide the Datasource and Schema. This supports both the Budibase internal table, as well as the core SQL databases. +## Schema and row ID -If you want to use a [custom schema](https://docs.budibase.com/docs/forms#form-schema) then you will need to **Eject** the block. Alternatively you can build your own custom form using a Form *component*. This approach requires more work but is much more customisable. +Choose a schema to generate the fields automatically. -
+For `Update` and `View`, set the Row ID so the form knows which row to load. -## Detail form with Row ID - -> 👍 Auto-configured details side panel -> -> Manual setup is not required when creating an [autogenerated table block](https://docs.budibase.com/docs/table-block#autogenerated-screen).\ -> A [Details side panel](https://docs.budibase.com/docs/table-block#on-row-click) will already be included with the *Row ID* set to [App state](doc:app-state) of the [Clicked row](https://docs.budibase.com/docs/table#on-row-click). - -When selecting *Update* or *View* type, you will need to provide a *Row ID* so that the form block knows which row data to populate the fields with. - - - -### Example usage - -Add a [Block](doc:blocks), such as the **Cards block** for your data, and add a [Side panel](doc:side-panel) to your screen. - -In the Settings Panel of your **Cards block**, enter a *Title* Binding for your rows. - - - -Click on the *Click actions* button, and add an [Update state](https://docs.budibase.com/docs/data-actions#update-state) action to set a new key 'employee\_id' to `{{ Employees Cards Block.Employees._id }}`. - -Next click `Add Action`: **Open Side Panel**, and make sure to select your side panel from the dropdown. Then `Save` your actions. - - - -> 📘 What is '\_id'? -> -> The **\_id** field represents a unique row identifier, which will exist on all data tables, including the internal DB and SQL tables within Budibase. It is a URL-safe encoded string. - -Finally add a **Form block** component inside your **Side panel**. In the Settings Panel, set *Type* to 'Update'. - -Provide *Row ID* with the app state binding you created above, i.e. `{{ State.employee_id }}`. - - - -You should now be able to Preview your app to see the details side panel in action: - - - -
+If you need a custom schema, eject the block and build the form manually with a Form component. ## Fields -After you pick a table schema, you will be able to configure your fields using the right side panel. - -Form field configuration - Form field configuration - +Use the settings panel to: -Click on the cog to customise field placement, actions, validation, and much more. - -Configuring form fields - Configuring form fields - - -You can adapt the layout of form fields with the layout option on each column, this allows for single, two and three column layouts. - - - -In field configuration you have a variety of things which can be done, you can use the switch to decide which fields appear in the form. Easily adjust the order by dragging items and alter the text of labels. You can also disable a field to prevent interaction or set it to read-only, maintaining the styling without allowing changes to the field's value. - -> 👍 Toggle all fields -> -> If you only need to expose a couple of required fields, you can toggle the switch at the top to hide all fields, and then toggle on the few required ones. -> -> - -
+* Show or hide fields +* Reorder fields +* Change labels +* Set fields to read-only or disabled ## Buttons -Depending on the selected type, you will have the option to add or remove the form action buttons. For example, *Update* type will have the following buttons by default: - - - -Click the cog icon to edit the preset button [Actions](doc:actions). For example you may not want to perform navigation or show notifications after clicking the 'Save' button. - -You can also drag the left hand edge to re-arrange the order that the buttons appear: - - - -#### Position and size - -By default the buttons will appear at the bottom of your form. If you want to place them at the top, inline with your heading, then you will need to change the *Button position* to 'Top'. This can be done in the `Styles` tab. - -You can also enlarge the *Size* of your form, which will proportionally increase the field sizes, button sizes, and heading size. - -Large form with buttons at the top - Large form with buttons at the top - - -
+The block includes preset save buttons for the selected form type. Use the settings panel to edit the button actions or move the buttons to the top of the form. ## Ejecting -A form block can be ejected to expose it's constituent parts. When a *Create* type form is ejected, it will appear similar to the following: - - - -The *Update* type is similar, but will also include the [Data provider](https://docs.budibase.com/docs/data-provider) and [Repeater](https://docs.budibase.com/docs/repeater) necessary to provide the row detail. - - \ No newline at end of file +Eject the block when you need full control over the underlying form components and layout. diff --git a/docs/Apps/blocks/index.md b/docs/Apps/blocks/index.md index 5c1bfec8a..d0997ed13 100644 --- a/docs/Apps/blocks/index.md +++ b/docs/Apps/blocks/index.md @@ -1,6 +1,6 @@ --- title: Blocks -excerpt: Working with pre-built components in the Design Section +excerpt: Working with pre-built components in the Design section deprecated: false hidden: false metadata: @@ -20,148 +20,45 @@ next: slug: table title: Table --- -Blocks in the Budibase are pre-built components comprised of multiple [Components](doc:components) themselves. They perform a common functionality and take away the complexity of having to repeat yourself. +Blocks are pre-built component groups that package common patterns into a single component. -At the time of writing, there are seven types of blocks available. +Use them when you want to add a complete layout faster or keep a screen easier to manage. -
+## Add a block -## Adding a Block +1. Open the Design section +2. Select `Add component` +3. Choose a block from the `Blocks` category -To add a block to your application, head over to the *Design* section, then press `Add component`. The blocks can be found under the *Blocks* category. +## Configure a block -List of available blocks - List of available blocks - +Select the block to open its settings. -Once you choose one of the blocks you want to have, it will appear in the design window. +Most blocks include a `Data` setting, plus the settings from the components they contain. -
+### Empty states -## Configuring Blocks +Most blocks support a custom message when no rows are returned. -Configuration of blocks is done by clicking the block you just added to open the Settings Panel. +Use bindings in the message if you need dynamic text. -Table block - Form block - +## Common blocks -The most important selection you will have to make first is picking which data table you want to use. Click the *Data* dropdown to see the list of available Datasources. +* Cards block +* Repeater block +* Form block +* Multi-step form block +* Chart block +* Row explorer block -Other settings are composed of the different [Components](doc:components) that were encapsulated within the block. To learn about which components are used for each block, look at the respective section below. +## Eject a block -### Empty text +Eject a block when you need to edit the nested components directly. -Most blocks support a custom message when no data is found. This is most likely to occur when [filtering](doc:searchfilter-data) returns no results. For example: +You can usually eject a block from the settings panel or the component tree. -Custom no rows found text - Empty text setting - +## Related pages - - -You can also use Bindings in your message. - -## Types of blocks - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - - Description -
- Cards block - - The *Cards Block* merges three different components into one. In order, it uses [Data Provider](doc:data-provider), [Repeater](doc:repeater) and [Card](doc:card) components. - - All the configuration options relevant to all three components are available in the sidebar. Additionally, you can easily add search fields to allow users to filter your card blocks. -
- Repeater block - - The *Repeater Block* is a quick way to have both the [Data Provider](doc:data-provider) and the [Repeater](doc:repeater) component into one. -
- Form block - - The [Form Block](https://docs.budibase.com/docs/form-block) is a comprehensive component that makes building different types of forms much more convenient. -
- Multi-Step Form Block - - The Multi-Step Form Block allows large forms to be broken up into pages. -
- Chart block - - The *Chart Block* combines a [Data Provider](doc:data-provider) with a nested [Chart](doc:chart) that matches the type chosen from the *Chart Type* dropdown menu. -
- Row explorer block - - Allows you to view data in an alternative way. It combines a searchable and scrollable list of cards on the left hand side, whilst displaying a detail form on the right for the selected card. -
- -
- -## Ejecting blocks - -As mentioned, blocks combine various components for convenience. Whilst there are many settings, sometimes blocks wont provide the full flexibility you are after. In this case, you can *eject* the block. - -An ejected block will split a single block component into its constituent components. To eject a block, you can press the `Eject block` button in the settings panel, or select the option from the component tree. - -Eject block button in the settings panel - Eject block button in the settings panel - - -
- -Eject block from component tree - Eject block from component tree - - -
- -Ejected content - Ejected content - +* [Card](doc:card) +* [Repeater](doc:repeater) +* [Table](doc:table) diff --git a/docs/Apps/blocks/more-blocks.md b/docs/Apps/blocks/more-blocks.md index 91629efe9..1a5dd704d 100644 --- a/docs/Apps/blocks/more-blocks.md +++ b/docs/Apps/blocks/more-blocks.md @@ -10,62 +10,30 @@ metadata: next: description: '' --- -## Repeater Block +## Repeater block -A repeater block and be used to iterate over rows in a table. Components nested inside a Repeater block will be repeated for as many rows are returned by the table. The bindings drawer will also have access the schema of the data source. This can be useful for creating project dashboards. +Use a repeater block to render the same layout once for each row in a datasource. -### Repeater Block Example +It is useful for dashboards, card lists, and other custom row layouts. -Add a repeater block set to the data source of the Jobs table in the Budibase sample data. Inside the repeater block, add a Container with a nested Headline component and Paragraph component, displaying the Customer Name and Job Notes, respectively. +## Cards block -![](https://files.readme.io/288ef66f66ca6ea596b13564318b2aabe7d51b59ee92455a932afddf64906b44-image.png) +Use a cards block when you want to show a small set of fields for each row, usually with an image and short summary text. -This will display on the screen as a container-per row, with each container showing a different row from the Jobs table. With some styling applied to containers and some filtering based on dates we can very quickly produce a dashboard to show the status of jobs. +## Chart block -![Dashboard Screenshot](https://files.readme.io/a136c9593f7b2f8c790bfbcb39e2b8da93ddbc4a50b778a32f56284810a6f303-Screenshot_2024-08-28_at_13.52.36.png) +Use a chart block to combine a [Data provider](doc:data-provider) with a chart component. -
+Common chart types include: -## Cards Block +* Pie +* Donut +* Bar +* Line +* Area +* Histogram +* Candlestick -![Cards Block Example](https://files.readme.io/4433d02567d850469f525fe65917ebcdae58967336dfc59a524106df84a86b0e-Screenshot_2024-08-28_at_13.55.57.png) +## Row explorer block -Cards Blocks are a quick and easy way to display a few attributes, and an image. A great example of this would be a staff roster. By default, Cards Blocks have a Title, Subtitle, and Description, a well as an optional Image URL. This can be useful for "Meet the Team" style pages, or inventory/e-commerce applications. As with the Repeater Block, a Cards block will iterate over the rows of the data source, and bindings will be available in the bindings Drawer based on the schema of the data source. - -![Cards Block Configuration](https://files.readme.io/70108b9995e10d9dc0b9015c96d5ea5afd00f258e25e14eafef2c142040f7f8b-Screenshot_2024-08-28_at_14.02.31.png) - -## Chart Block - -| Type | Description | Requirements | -| :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------ | -| Pie | Circular graphic divided into "slices", where the greater the arc-length is proportional to the numerical value. | Label (text), Data (numerical) | -| Donut | Similar to the Pie Chart, a Donut Chart is a segmented ring, where segment-sizes are proportional to the numerical value. | Label (text), Data (numerical) | -| Bar | Presents categorical data with rectangular bars with heights or lengths proportional to the values that they represent. | Label (text), Data (numerical) | -| Line | Displays information as a series of data points connected by straight line segments | Label (text), Data (numerical) | -| Area | Similar to a line chart, an area chart also shades the area beneath the line. Multiple data lines can be chosen for display. The order in which data lines are chosen will determine which shaded area shows over others. | Label (text), Data (numerical) | -| Histogram | | Value (numerical) | -| Candlestick | Typically used to show share prices | Open price, High price, Low price, Close price (all numerical), and Date. | - -![An example Pie chart, using the BudibaseDB Sample Data (Label: Customer Name, Data: Quote Price)](https://files.readme.io/15c1d5a1b2f27e26ec96d406cc1d08022cf34eaeb749e5dcd24e42da9ca44700-Screenshot_2024-08-28_at_13.26.16.png) - -![An example Donut chart, using the BudibaseDB Sample Data (Label: Customer Name, Data: Quote Price)](https://files.readme.io/d2dda866bee4e5bcddd52a4df7233d6f3a09335ae025642324bab4bf74e16ff4-Screenshot_2024-08-28_at_13.26.27.png) - -![An example Bar chart, using the Budibase DB Sample Data (Label: Customer Name, Data: Quote Price & Updated Price)](https://files.readme.io/88555ebc9f6863cd9352a7cac07ffd094e52da67db16c2258daae0708e84daeb-Screenshot_2024-08-28_at_13.26.39.png) - -![An example Line chart using fabricated data in a BudibaseDB table](https://files.readme.io/763da104473283d093575b3d77e39fdb25f485053ea4ee2cec97bb2b2fb40508-Screenshot_2024-08-28_at_15.06.56.png) - -![An example Area chart using fabricated data in a BudibaseDB table](https://files.readme.io/2d15e101c4e333b992507838eb2f93ef551199b357930f7e1c2a21985311a756-Screenshot_2024-08-28_at_15.08.22.png) - -![An example Histogram chart, using the BudibaseDB sample data (Value: Quote Price, Bucket Count: 6)](https://files.readme.io/3dccdc776f0196eb46d78f11ccf120fbc315e7706621a10f1f38fc88ef1974f0-Screenshot_2024-08-28_at_13.26.49.png) - -![An example candlestick chart, using a REST API query to fetch data from alphavantage.co](https://files.readme.io/62bea66cbebc2e3a9abbba2c2284fe8c8b0477d3e3443a6628cd6bb243b7858e-Screenshot_2024-08-28_at_15.09.15.png) - -
- -## Row Explorer - -![](https://files.readme.io/7969eeb1ec694b730b0b9f1c0b0d5599b4f14fe5b22cdce43603710970a812f5-image.png) - -A row explorer block helps give a brief overview of all rows in a datasource, and then a closer look at one row at a time. Built into the block is a search-field, as well as an update-row form. - -![Row Explorer Example](https://files.readme.io/dc3ba3db8159ac17415d9008d67016adc5b7a19e202cb402753c362dcd3e5157-Screenshot_2024-08-28_at_15.33.43.png) \ No newline at end of file +Use a row explorer block to show a list of rows on one side and the selected row details on the other. diff --git a/docs/Apps/blocks/multi-step-form-block.md b/docs/Apps/blocks/multi-step-form-block.md index d57b2a1b0..5b4a53bc1 100644 --- a/docs/Apps/blocks/multi-step-form-block.md +++ b/docs/Apps/blocks/multi-step-form-block.md @@ -10,108 +10,38 @@ metadata: next: description: '' --- -When building a [Form](doc:forms) with many [Form steps](doc:form-steps) the Component Tree can get quite long and tricky to maintain. The multi-step form block aims to solve this problem by allowing you to manage your form steps within the Settings Panel. - -
+Use the Multi-step form block when you want to manage step-based forms in one component. ## General settings -When you initially create a multi-step form block, it will have a single step displaying all the form fields for the chosen *Data* source. Blocks support the internal Budibase DB tables, as well as [SQL](doc:sql-datasource) tables. - -Just like a [Form block](doc:form-block) you may change the form *Type* between 'Create', 'Update', and 'View' as needed. - -The selected data source and form type will be applied across all form steps in your multi-step form block. - -General settings - General settings - - -
+Choose the data source and form type once. These settings apply to every step in the block. -## Details +Supported form types: -The details section includes settings that will be applied on a per step basis. Initially there will be a single step, but you can click to `Add step` button to get started. +* Create +* Update +* View -Add a form step - Add a form step - +## Steps -Once another form step has been added, you will be able to navigate between the steps using arrow buttons. The `x` button will delete a form step, while the `+` icon will add another step immediately after the currently selected step. +Start with one step, then add more as needed. Use the step controls to move between steps, add steps, or delete steps. -Navigating between form steps - Navigating between form steps - +Step titles can use the current step binding: -#### Title and description - -By default the title of each step will be tied to current step Binding like so: - -``` +```text Step {{ Multi-step Form Block.Current Step }} ``` -This will conveniently label each step "Step 1", "Step 2", etc without needing manual input. With that said, you can easily replace this with your own step title. - -Similarly you can add a *Description* which will appear below the step title, however this is blank by default. - -Adding a description
-
- - Adding a description - - -Step title with description - Step title with description - - -#### Fields - -Form fields can be shown/hidden and further configured for each form step. For example you may want to show only 'contact information' fields in your first step, while showing only 'address details' fields in the second step. - -Read [configuring form fields](https://docs.budibase.com/docs/form-block#fields) for more information. - -#### Buttons - -When you add new steps in the multi-step form block, Budibase will intelligently configure the buttons you would likely want as follows: - - - - - - - +You can also add a description for each step. - - - +## Fields - - - +Show or hide fields per step so each step only contains the inputs it needs. - +## Buttons - - - -
- First step - - Middle step - - Last step -
- - - - - -
+Budibase adds the usual step navigation buttons automatically. The final step keeps the save action, while earlier steps use step navigation actions. -These buttons will use the [Change Form Step](https://docs.budibase.com/docs/form-actions#change-form-step) action to appropriately navigate between the different steps, and the 'Save' button will naturally save your form at the end. If you need custom actions, click on the cog icon beside a button. You may also add and remove buttons as needed. +## Initial step -Read [configuring form buttons](https://docs.budibase.com/docs/form-block#buttons) for more information. \ No newline at end of file +Set the initial step when you want the form to open on something other than step 1, such as when using persisted state. diff --git a/docs/Apps/blocks/table-block.md b/docs/Apps/blocks/table-block.md index 2f85c28d1..4723d9c72 100644 --- a/docs/Apps/blocks/table-block.md +++ b/docs/Apps/blocks/table-block.md @@ -1,6 +1,6 @@ --- title: Table Block (Deprecated) -excerpt: Quickly display and action your data +excerpt: Quickly display and act on your data deprecated: false hidden: true metadata: @@ -10,78 +10,28 @@ metadata: next: description: '' --- -The Table block effectively merges both the [Data Provider](doc:data-provider) and the [Table](doc:table) component into one. It also integrates [Searching and filtering data](doc:searchfilter-data). This helps you simplify the logic of the page, and not have to worry about configuring two different components. +The Table block combined a [Data provider](doc:data-provider) and a [Table](doc:table) component. -Furthermore, it allows you to add CRUD (Create, Read, Update and Delete) functionality to your table data; all in one component! It achieves this through the use of 'Create' and 'Edit Detail' [Side panels](doc:side-panel). +It also included search, filtering, and row actions in one block. -Many of the settings will be shared with the [Table](doc:table) component. The block specific settings are described on this page. - -> 👍 Table -> -> The new table documentation can be found [here](doc:table). +Use the current [Table](doc:table) documentation instead. ## Search fields -Select the fields you want users to be able to search on. For a [Text field](doc:text-field) the search will be a *starts with*. Other fields will search for an exact match. - -As noted under the setting, a maximum of five search fields can be used at any given time. - -Allow users to search on First Name and Start Date - Allow users to search on First Name and Start Date - - -![](https://files.readme.io/97a81b3-Screenshot_2022-12-12_at_12.10.29.png) - -If you add search fields, upon [Ejecting](https://docs.budibase.com/docs/blocks#ejecting-blocks) a [Form](doc:forms) component will be added like so: - -Ejected table block with search fields - Ejected table block with search fields - - -In addition, the added [Data provider](doc:data-provider) will include the necessary filters with the form field bindings. - -![](https://files.readme.io/064a55a-Screenshot_2022-12-12_at_12.21.20.png) - -## On row click - -This setting allows you to determine what happens when a table row is clicked. By default **Run actions** will be checked, however with *no actions set* nothing will happen. - -Run actions on row click - Run actions on row click - - -Click `Define actions` to get access to all of the available [Actions](doc:actions). - -The other option is **Show details side panel**. This will open a [Side panel](doc:side-panel) when a row is clicked, showing the row detail within a [Form block](doc:form-block). - -As noted under the option, table block side panels will not work with [REST queries](doc:rest-queries) or other [Custom queries](https://docs.budibase.com/docs/data-sources#custom-queries). - -## Show button - -You can add an action button to the top right of your table. To do so, check `Show button above table`. - -The table block will have no action button by default - The table block will have no action button by default - - -Once checked, you will be able to enter some text for the button, and similar to *on row click*, you can choose between running some actions or opening a side panel. +Search fields let users filter table rows by specific columns. -In this case however, the side panel will have a nested form block in *Create* mode, i.e. the fields will initially be blank and save a new row on submit, rather than update an existing row. +Text fields use a starts-with match. Other fields use an exact match. -Action button opens a new row side panel - Action button opens a new row side panel - +## Row click -Table block with Create row action button - Table block with Create row action button - +Use row click actions to run actions or open a side panel. -## Autogenerated screen +## Button actions -When creating an autogenerated screen, the table block is the only component that is added, with both side panel options selected. +You can add a button above the table to run actions or open a create side panel. -Ejecting an autogenerated screen table block will result in a component tree like so: +## Autogenerated screens -![](https://files.readme.io/52bf6d5-Screenshot_2022-12-12_at_14.40.39.png) +Autogenerated screens use the Table block by default. -Ejecting in this case is useful if you wanted to view and edit the side panel forms within the builder. \ No newline at end of file +If you eject the block, you can edit the nested components directly. diff --git a/docs/Apps/chart/area-chart.md b/docs/Apps/chart/area-chart.md index 48c7ff0da..93a4bbd2b 100644 --- a/docs/Apps/chart/area-chart.md +++ b/docs/Apps/chart/area-chart.md @@ -10,181 +10,41 @@ metadata: next: description: '' --- -The area chart is a mixture between the [Bar Chart](doc:bar-chart) and the [Line Chart](doc:line-chart). Allowing you to display multiple columns of data on top of each other, having the area coloured. +Use an area chart to compare one or more numeric series across the same labels. - +Area charts are useful when you want stacked or overlapping lines with filled areas. -Not only can you stack the different data like above, but you can also let them overlay. +## Setup -## Adding an Area Chart +1. Add a [Data provider](doc:data-provider) +2. Add an Area chart inside the provider +3. Select the provider in the chart settings +4. Choose a label column +5. Choose one or more numeric data columns -To add the area chart to your UI, you first need to wrap it in a [Data Provider](doc:data-provider). Then you can add the Area chart to your UI through `Chart > Area Chart`. +## Settings -![](https://files.readme.io/451ee80-Screenshot_2023-07-04_at_13.40.21.png) +Common settings include: -## Displaying data +* Provider +* Label column +* Data column(s) +* Format +* X-axis and Y-axis labels +* Width and height +* Colours +* Curve +* Data labels +* Animate +* Legend +* Stacked -After adding the Area chart to your UI, you can now select data. You should've already selected a data source through the [Data Provider](doc:data-provider), so now you can select the Data Provider in the Area chart. +## Use stacked values -In the chart on top of this page there are 4 columns selected, and they stack by default. To do this, just select the data provider, a label column, and select the 4 columns you want to display. +Enable `Stacked` when you want series to build on top of each other. - +Leave it off when you want the series to overlap. -And that is all you need to do to get an area chart set up. But of course, you customize much more in the Settings Panel. To read more about further customization, check the reference table below. +## Requirements -> 📘 Numeric data only -> -> Of course, line charts need to have a scale, so for the data column(s), you can only select [Numeric](doc:number) columns (eg; containing values that can be converted to numbers) - -## Settings panel - -The settings panel has quite a few customization options, allowing you to get the most out of your bar chart. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Setting - - Description -
- Provider - - The [Data Provider](doc:data-provider) as a parent of your chart -
- Label Column - - The Labels you want to display with your data. These are displayed on the X-axis -
- Data Column(s) - - The data you want to display as lines. This has to be [numeric](doc:number). Can be multiple -
- Format - - Will divide labels by thousand or million on the axis and adds a `K` or `M` to the axis respectively -
- Y-axis Label\ - X-axis label - - The labels you want to display next to the Y and X-axis. -
- Width\ - Height - - The size you want the chart to be, supports all CSS supported sizes -
- Colours - - Choose from one of the predefined colour-palettes -
- Curve - - The type of line you want to have. - - * \*Smooth\*\*: A curved line flowing with the data - * \*Straight\*\*: A line straight from point to point - * \*Stepline\*\*: A line which remains horizontal, and drops down completely for the next data point. See below the reference table for an example of all three. -
- Data Labels - - Will display the value on every point on the graph -
- Animate - - Will animate when the data changes or on startup. Data-change can happen through [Dynamic filter's](doc:dynamic-filter) for example. -
- Legend - - Will display, in the upper-right corner, the label for each of the data columns displayed on the chart -
- Stacked - - Check this setting to have the different data columns stacked, which means they won't overlay but be stacked on top of each other.\ - You can see the difference between stacked and not stacked below the reference table -
- -### Stacked vs non-stacked comparison - -{1958} - Not stacked (left) and Stacked (right) comparison - \ No newline at end of file +Area chart data columns must be numeric. diff --git a/docs/Apps/chart/bar-chart.md b/docs/Apps/chart/bar-chart.md index 380080eb7..a94ec1157 100644 --- a/docs/Apps/chart/bar-chart.md +++ b/docs/Apps/chart/bar-chart.md @@ -10,172 +10,41 @@ metadata: next: description: '' --- -The bar chart is a very basic, but powerful, method of displaying data in such a way it makes much more sense immediately, compared to simply browsing the data in tables. +Use a bar chart to compare numeric values across categories. -![](https://files.readme.io/4ff30c3-barcharts.png "barcharts.png") +## Setup -## Adding a Bar Chart +1. Add a [Data provider](doc:data-provider) +2. Add a Bar chart inside the provider +3. Select the provider in the chart settings +4. Choose a label column +5. Choose one or more numeric data columns -To add a bar chart to your UI, you need to connect it to your data source using a [Data Provider](doc:data-provider). After adding the `data provider`, add the `Chart > Bar Chart` component to it, and you'll be able to link up the data from your table. +## Settings -![](https://files.readme.io/15be8d6-Screenshot_2023-07-04_at_13.41.04.png) +Common settings include: -> 👍 Grouping data -> -> To group data inside a bar chart, use [Views](doc:views) on top of your data. This way, you can hook up your chart using the data provider linked to the view instead. +* Provider +* Label column +* Data column(s) +* Format +* X-axis and Y-axis labels +* Width and height +* Colours +* Stacked +* Horizontal +* Data labels +* Animate +* Legend -## Displaying data +## Use horizontal bars -Now that you have the data linked up to your bar chart, you can select which columns you want to display. For example, we have a table with cars and their mileage, and displaying this in a bar chart is only a few clicks. +Enable `Horizontal` when you want labels on the Y-axis and bars that run left to right. -![](https://files.readme.io/29a411c-mileage-barchart.png "mileage-barchart.png") +## Group data -To get this view, head over to the Settings Panel, and select the `License Plate` as the label column, and the mileage as the data column(s). And to get the bars horizontally, instead of vertical, check the `Horizontal` setting in the Settings Panel. And there you have it. +If you want grouped values, use a [View](doc:views) or other grouped datasource before connecting the chart. -This is just one of the many things you can do with the bar chart, explore all the features from the Settings Panel below. +## Requirements -> 📘 Numeric data only -> -> Of course, bars need to have a size, so for the data column(s), you can only select [Numeric](doc:number) columns (eg; containing values that can be converted to numbers) - -## Settings panel - -The settings panel for the bar chart has the following options. Generic styling settings are omitted from this overview. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Setting - - Description -
- Provider - - The [Data Provider](doc:data-provider) as a parent of your chart -
- Label Column - - The Labels you want to display with your data. These are on the X-axis in standard mode, or on the Y-axis on `Horizontal` mode -
- Data Column(s) - - The data you want to display with the labels. This has to be numeric. Can be multiple -
- Format - - Will divide by thousand or million on the axis and adds a `K` or `M` to the axis respectively -
- Y-axis Label\ - X-axis label - - The labels you want to display next to the Y and X-axis. -
- Width\ - Height - - The size you want the chart to be, supports all CSS supported sizes -
- Colours - - Choose from one of the predefined colour-palettes -
- Stacked - - Check this setting to have the different data columns stacked (aka, on the same line instead of each column as a separate bar) in the chart -
- Horizontal - - Displays the bars horizontally, rather than vertically, when checked. The labels will move to the Y-axis when this is checked -
- Data Labels - - Will display the value of the bar on top of the bar when checked -
- Animate - - Will animate when the data changes or on startup. Data-change can happen through [Dynamic filter's](doc:dynamic-filter) for example. -
- Legend - - Displays the label for each colour visible on the chart as a legend in the upper-right corner -
\ No newline at end of file +Bar chart data columns must be numeric. diff --git a/docs/Apps/chart/index.md b/docs/Apps/chart/index.md index 6d49088e7..139bd61c6 100644 --- a/docs/Apps/chart/index.md +++ b/docs/Apps/chart/index.md @@ -1,6 +1,6 @@ --- title: Charts -excerpt: Visualise your data +excerpt: Visualise your data. deprecated: false hidden: false metadata: @@ -10,56 +10,42 @@ metadata: next: description: '' --- -Whilst there are a variety of chart types, all charts have some common properties: +Use charts to present numeric data from a [Data provider](doc:data-provider). + +All charts share the same core settings: * Title * Provider -* Label Column -* Data Column(s) -* Width & Height +* Label column +* Data column(s) +* Width and height * Margin * Custom CSS * Conditions -## Providing data - -Charts allow you to visualise data from a [Data Provider](doc:data-provider), which can have datasources such as: - -* Budibase DB -* [REST Queries](doc:rest-queries) -* [Custom Queries](doc:custom-queries) - -## Displaying data - -The data displayed in your chart will be determined by the label and data columns. - -**Label Column** Provides the name of each categorical variable.\ -**Data Column(s)** Provides the value or range of values for each label. - -> 🚀 Data column type -> -> Data columns must be numeric (eg; containing values that can be converted to numbers) - -## Generating the chart schema - -For table datasources, the available options for the label and data columns will match the columns of the table. - -When using a **View** as a datasource, any **View Calculations** (such as Sum, Average, Minimum, or Maximum) you have configured will also be available as numeric data columns for your chart. - -Data from REST Queries on the other hand, will likely need to be transformed to be suitable for use in charts. +## Choose a source -In particular, your [Transformer](doc:transformers) and Schema should align with the following: +Charts can read from: -![](https://files.readme.io/673ca59-Screenshot_2022-04-26_at_15.58.08.png "Screenshot 2022-04-26 at 15.58.08.png") +* Budibase DB +* REST queries +* Custom queries -Naturally you would replace the strings and numbers with response data from your API. +## Use chart data -### Many data columns +The label column names each category. -Most chart types can make use of more than one value column. Thus, additional value fields would be needed in your schema. +The data column or columns provide the numeric values for each label. -For example, you may want to display the change in average temperature between seasons for each country: +REST queries and custom queries often need a transformer so the returned data matches the chart schema. -![](https://files.readme.io/1a25614-Screenshot_2022-04-26_at_16.48.50.png "Screenshot 2022-04-26 at 16.48.50.png") +## Common chart types - +* Area +* Bar +* Candlestick +* Gauge +* Histogram +* Line +* Pie +* Progress donut diff --git a/docs/Apps/components/accordion.md b/docs/Apps/components/accordion.md index 0e434adf9..3961c6dab 100644 --- a/docs/Apps/components/accordion.md +++ b/docs/Apps/components/accordion.md @@ -10,59 +10,35 @@ metadata: next: description: '' --- -The Accordion component is a collapsible container allowing users to toggle its body content's visibility. It is particularly useful for organising content in a space-efficient manner, such as FAQs, settings panels, or grouped information. +Use the Accordion component to hide and reveal grouped content. ## Features -* **Collapsible Sections**: Users can expand or collapse content panels to show or hide information. -* **Customisable Header**: The accordion heading can be customised with a label and styling options. -* **Dynamic Content**: Supports nested components or any child content within the expandable body. +* Collapsible sections +* Customisable header +* Nested child content ## Settings -| Setting | Description | -| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Label | A text string that serves as the heading for the accordion section. This label is always visible, whether the accordion is expanded or collapsed. | -| Bold | A boolean option that, when enabled, renders the label text in bold to emphasize the section heading. | -| Default State | Determines whether the accordion should be open or closed when the component is first rendered. This allows for tailored user experiences, especially in forms or detail views. | +| Setting | Description | +| :-- | :-- | +| Label | Heading text shown on the accordion | +| Bold | Render the label in bold | +| Default State | Choose whether the accordion starts open or closed | -## Component support +## Use it for -The Accordion component can render nested components within its body: +* FAQs +* Settings panels +* Grouped form sections +* Supporting content that should stay compact -* When the accordion is open, all child components are visible. -* When the accordion is closed, the child content is hidden from view. +## Structure -This makes the Accordion ideal for embedding forms, lists, media, or any reusable component inside a collapsible container. - -## FAQ example - -```Text CSV -Question,Answer -"What is your return policy?","We accept returns within 30 days of purchase. Items must be in original condition and accompanied by a receipt." -"How can I track my order?","After placing an order, you'll receive a tracking number via email once your package ships." -"Do you offer international shipping?","Yes, we ship to most countries worldwide. Shipping costs and delivery times vary depending on the destination." -"Can I change or cancel my order?","Orders can be changed or canceled within 2 hours of placing them. Please contact our support team immediately." -"Are your products eco-friendly?","We prioritize sustainability and use eco-friendly materials whenever possible. Check product pages for more details." -``` - -### Component tree - -In the component tree, the Accordion acts as a parent container for any content you want to show or hide. - -Typical structure: +The Accordion acts as the parent container for any content you want to show or hide. 1. Add `Accordion` to your screen -2. Nest content components inside the Accordion body (for example `Text`, `Form`, `Repeater`, or `Container`) -3. Optionally nest additional components inside those children for more complex layouts - -Example tree: - -- `Screen` -- `Accordion (FAQ: Shipping)` -- `Text` (question/intro) -- `Container` -- `Text` (answer) - -All nested child components remain in the tree at all times, but their visibility in the app is controlled by whether the Accordion is expanded or collapsed. +2. Nest content components inside the body +3. Add more nested components if the content needs further structure +When the Accordion is open, child components are visible. When it is closed, they are hidden. diff --git a/docs/Apps/components/card.md b/docs/Apps/components/card.md index 8df451022..99cbbaefa 100644 --- a/docs/Apps/components/card.md +++ b/docs/Apps/components/card.md @@ -18,79 +18,52 @@ next: slug: blocks title: Blocks --- -Use the Card component to display lists of data to your users. Cards can contain content, images, and actions, and are a great alternative to the table component; especially, if you want to present an image for each card. You can switch between vertical and horizontal variants of the card using the settings panel. - -Cards are highly flexible and have a lot of configuration options. We'll dive into those below - +Use the Card component to display records in a compact layout. > 📘 Cards Block > -> Want to quickly convert your data to a list of cards? Use the Cards [Block](doc:blocks) instead +> Use the Cards [Block](doc:blocks) if you want to render a data source as a card list. ## Layout -The card component has two different layout modes. Vertical and Horizontal. The vertical mode has every component aligned vertically, whereas the horizontal mode has the image left of the text elements. - -For example purposes, I've loaded a list of countries into the database, with flags as images connected to it. In vertical mode, cards render with the image above the text content - -### Vertical Mode - - -As you can see, there's 3 items per row. However, this is purely dependent on the screen size. When you change the width of your browser window this can easily change to 1 (narrow or mobile), or 4 (or more) when you make your window wider. - -The vertical mode is enabled by default, but in case horizontal mode is enabled, all you have to do is deselect "Horizontal" from the Settings Panel. - -The order of elements visible in a card is from top to bottom, Image, Title, Subtitle and Description. - -### Horizontal Mode - -To enable horizontal mode, you need to check `Horizontal` in the Settings Panel. +Cards support two layout modes: +* **Vertical** places the image above the text +* **Horizontal** places the image to the left of the text -When horizontal mode is enabled, the image moves to the left of the text content +Use `Horizontal` in the Settings Panel to switch layout modes. +## Card elements -As you can see, the image has shifted to the left of the text elements, where the text elements themselves have not changed. - -Quick settings checklist: -- `Horizontal`: toggles image-above-text (off) vs image-left-of-text (on). -- `Image URL`: controls the image displayed in the card. -- `Show button`: toggles the optional button in each card. -- `Click action`: defines the card click behavior. - -## Card Elements - -The card consists of several default elements, which are bindable through Handlebars or JavaScript functions. Read more about binding in our [Bindings](doc:bindings) documentation. All elements can be configured in the settings panel. - -| Element | Description | -| :---------- | :--------------------------------------------------------------------------------------------- | -| Title | The top-most text element inside a card, printed as the largest font and bold | -| Subtitle | Directly below the title | -| Description | Below the subtitle, in the smallest font. | -| Image | The image which can be displayed on top, or on the left of the card (depending on layout mode) | +| Element | Description | +| :-- | :-- | +| Title | Primary label | +| Subtitle | Secondary label below the title | +| Description | Supporting text below the subtitle | +| Image | Optional image shown above or beside the text | ## Button -Next to the default elements, there's an optional button element. You can enable the button by checking the `Button` in the settings panel - - -The button text can be configured through [Bindings](doc:bindings), or simply text as demonstrated above. The button will then be added to the card as displayed below - - -Right now the button doesn't do anything yet, when you click it, but that can be configured through the `Define Actions` button in the settings panel. +Cards can also show an optional button. Set the button label with text or a binding, then configure the click action from the settings panel. > 👍 Define Actions > -> To learn more about defining actions, read the [Actions](doc:actions) documentation +> See [Actions](doc:actions) for how to configure the button click. + +## Common use -## Tutorial +Cards work well for: -This tutorial is primarily going to focus on the card component itself as the `Card Block` variant has already been discussed above. This tutorial will be broken down into steps, going from a blank screen to multiple cards and related details shown. Lastly, this tutorial will be using the inbuilt [Budibase DB](doc:budibasedb) as well as the sample data which it provides. +* Search results +* Related records +* Profile summaries +* Dashboard summaries -1. Add a data provider component (In this case I'm going to use the Employees table). -2. Add a repeater component nested inside the data provider.\ -3. Add the card component nested inside the new repeater which you created.\ -4. Bind up all relevant information you wish to display within the card. From the title to the link, or even add a button with relevant actions you want to perform when clicked. For this example I was just show some basic information contained within the employee's table.\ +## Tutorial pattern -At this point, you should have a data-driven card layout with the desired fields and actions. +To build a card list from data: +1. Add a data provider +2. Add a repeater inside the data provider +3. Add a card inside the repeater +4. Bind the title, description, image, and button fields to the row data diff --git a/docs/Apps/components/container.md b/docs/Apps/components/container.md index 157ab4102..96a1d1204 100644 --- a/docs/Apps/components/container.md +++ b/docs/Apps/components/container.md @@ -10,348 +10,42 @@ metadata: next: description: '' --- -The container now has two different layouts. You can toggle between these two modes by switching between the icons of the layout setting. By default, the grid-based layout is selected. If you wish to use the old layout, you must click the first displayed icon. +Use the Container component to group content and control layout. +## Layout modes -## Grid-based +Containers support two layout modes: -This layout allows users to drag, resize, and place their components anywhere on the screen. It also allows you to resize components based on the view mode you have currently selected in the builder. This allows you to build [responsive screens](doc:designing-for-mobile) easily for mobile and tablet devices. +* **Grid** lets you place and resize components freely in the builder +* **Flexbox** arranges child components in rows or columns -To drag, hover over the component and click on its label. This will allow you to drag the component freely within the builder's design area. If you don't click on the label, you will just be able to resize the component. +Use grid when you want direct placement. Use flexbox when you want predictable responsive layout. -## Flexbox +## Flexbox settings -A Container is a `div` with pre-defined styles. They are the building blocks of your application and critical for responsive design. Containers are used to structure your application and layout other components/elements in a structured way. You can use [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) to layout the items within your container. +| Setting | Description | +| :-- | :-- | +| Layout | Switch between grid and flexbox | +| Name | Rename the container in the component tree | +| Direction | Set child components to row or column | +| Horizontal align | Align children on the main axis | +| Vertical align | Align children on the cross axis | +| Size | Control how the container grows or shrinks | +| Gap | Set spacing between children | +| Wrap | Wrap children onto multiple lines | +| On click | Run actions when the container is clicked | +## Background colour -> 📘 Learn Flexbox -> -> Budibase containers use flexbox to layout components. A great resource for learning flexbox is [flexbox froggy.](https://flexboxfroggy.com/) +Use the background color setting to separate sections or add emphasis. -## Container settings +You can also apply a gradient background. Use the `X` in the color picker to clear a selected color. -### Flexbox +## Common use -There are several general settings for the container component, most of which are shared with other components as well. +Containers are useful for: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Setting - - Description -
- Layout - - Switch between the flexbox and grid-base layouts. -
- Name - - Change the name of your component, and how it reads within the component tree. -
- Direction - - Change the direction of the components nested within your container. You can layout your components in a row (→) or a column (↓). -
- Horizontal align - - The horizontal. align setting is used to align the items on the main axis, the direction in which flex-direction has set the flow. The initial value is **left** which will line the items up at the start edge of the container, but you could also set the value to **right** to line them up at the end, or **center** to line them up in the center. - - You can also use the value **stretch** to take all the spare space between the items, and share it out evenly between the items so there will be an equal amount of space between each item. -
- Vertical align - - The vertical align property will align the items on the cross axis. The initial value is **top** which aligns the items along the top of the container (like they're handing from a roof), but you could also set the value to the **bottom** to align the items along the bottom (like they're standing on the floor), or **middle** to line them up in the center. - - You can also use the value to **stretch**, to stretch the items to fill the height of the container. -
- Size - - Where the **grow** option deals with adding space in the main axis, the **shrink** property controls how it is taken away. -
- Gap - - The **gap** property sets the gaps (gutters) between items stored within a container. You can select the different sizes of gaps you would like between your items. -
- Wrap - - Select the **wrap** to wrap your components onto multiple lines. This is critical when designing for mobile resolutions. - - With **nowrap**, the items are laid out in a single line which may cause the flex container to overflow. -
- On click - - By defining [actions](https://docs.budibase.com/docs/actions) within the `On Click` setting, the container will be treated like a button including the cursor change. Any click events of buttons or other containers within a container with *On Click* actions set will be ignored. -
- -Example setup: -- `Direction`: `row` -- `Horiz. align`: `center` -- `Vert. align`: `top` - -This places child components in a horizontal line, centered across the container, aligned to the top edge. - -### Container background colour - -You can also splash some color into your apps with containers! - - -To clear the selected color, click on the `X` in the bottom right of the panel. - -For additional flare, there are a range of gradients available. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Title - - Gradient -
- Warm Flame - - -
- Night Fade - - -
- Spring Warmth - - -
- Sunny Morning - - -
- Winter Neva - - -
- Tempting Azure - - -
- Heavy Rain - - -
- Deep Blue - - -
- Near Moon - - -
- Wild Apple - - -
- Plum Plate - - -
- Peach Kiss - - -
- Flamingo Sunrise - - -
- Bud Mist - - -
- Ballet Slipper - - -
- Black Noir - - -
- -You can also add background colors to your [Screens](doc:screens) - -
- -## Component layout - -When using containers to layout your components, the most important setting is *Direction* as this will determine the flow of components. - - - -If you need additional layout you can add additional containers. For example what if we wanted to group 'THREE' and 'FOUR' in column direction, but have an overall row layout for the screen. In this case we need to add a container and nest P3 and P4 like so: - - -Containers are a really flexible way to arrange your components in the **Design** section. You can nest any number of containers with different styles and layout options. - -You may, however be interested in [Using sections](doc:using-sections) or [Field groups](doc:field-groups) to get out-of-the-box layouts. +* Grouping related components +* Building responsive rows and columns +* Adding spacing and alignment +* Creating clickable layout areas diff --git a/docs/Apps/components/index.md b/docs/Apps/components/index.md index a02ee37fd..5df872662 100644 --- a/docs/Apps/components/index.md +++ b/docs/Apps/components/index.md @@ -10,22 +10,22 @@ metadata: next: description: '' --- -Components are the building blocks of Budibase apps. Use them to collect input, display data, and shape the layout of a screen. +Components are the building blocks of Budibase apps. Use them to collect input, display data, and shape screen layout. ## Add components -There are two common ways to add a component: +Add components in one of two ways: 1. Use the add component button in the builder. 2. Select a component type from the searchable component list. -When the component list is open, pressing `Enter` adds the highlighted component. +When the component list is open, press `Enter` to add the highlighted component. ## Delete components Select a component and press `Backspace` or `Delete`. -You can also open the component menu and choose the delete action. +You can also delete a component from its menu. ## Component tree @@ -61,7 +61,7 @@ Common shortcuts include: * `⌘ + C` to copy a component * `⌘ + V` to paste a component -Use `CTRL` instead of `⌘` on Windows. +Use `Ctrl` instead of `⌘` on Windows. ## Rename components @@ -77,7 +77,7 @@ Use names that describe the component’s purpose, not just its type. Once a component is on the screen, its settings appear in the right-hand panel. -Some components also expose additional controls in the canvas preview. Use these when you need to adjust layout or content without changing the underlying structure. +Some components also expose controls in the canvas preview. Use those when you need to adjust layout or content without changing the component tree. ## Related guides diff --git a/docs/Apps/components/tag.md b/docs/Apps/components/tag.md index f9b4a876e..bd7c3d393 100644 --- a/docs/Apps/components/tag.md +++ b/docs/Apps/components/tag.md @@ -10,23 +10,18 @@ metadata: next: description: '' --- -The `Tag` component can quickly display tags on a detail page or in other compact layouts. Use it for statuses, labels, categories, or related records. +Use the `Tag` component for short labels such as statuses, categories, and related values. -You can bind the tag text to row data, change its color, and optionally add a delete button configured with [Actions](doc:actions). +## Customise the tag +| Setting | Description | +| :-- | :-- | +| Size | Set the text size | +| Color | Set the tag color | +| Allow delete | Show an `X` delete control | +| On click delete | Configure what happens when the delete control is clicked | -## Customising the tag - -To customise the tag, you have several settings in the Settings Panel you can use. - -| Setting | Description | -| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Size | The size of text, choose between small, medium or large. | -| Color | Choose the color of the button, the text color will change accordingly. | -| Allow delete | Adds an `X` delete control to the tag. | -| On click delete | This setting appears when `Allow delete` is checked. Use it to configure what happens when the user clicks the `X`, using [Actions](doc:actions). | - -## Common usage +## Common use Tags work best when the value is short and repeatable. @@ -37,24 +32,14 @@ Common examples include: * Related items in a repeater * Filter chips in compact views -## Tutorial: Movie genre tags - -Use the Tag component to show related labels in a compact layout, such as tags on a card or detail view. - -To build the example: - -1. Create `Movies` and `Tags` tables. -2. Add a many-to-many relationship from `Tags` to `Movies`. -3. Build a cards view for `Movies`. -4. Eject the cards block and add a repeater for the related tags. -5. Add the Tag component inside the repeater and bind it to `{{ Tags Repeater block.Tags.Name }}`. -6. Use [Conditional UI](doc:conditions) to assign a color per tag name. +## Tutorial pattern -To remove tags: +Use a repeater when the tag values come from related data: -1. Enable `Allow delete`. -2. Add a `Save Row` action on `On click delete`. -3. Update the `Tags` relationship so the selected tag is removed. -4. Hide the tag when the relationship is empty. +1. Build the parent list or detail view +2. Add a repeater for the related items +3. Add the Tag component inside the repeater +4. Bind the text to the related field +5. Use [Conditional UI](doc:conditions) to vary the color when needed -If you need faster removal feedback, cache the removed tag in [App state](doc:app-state) before syncing the database update. +If you need delete support, enable `Allow delete` and wire the delete control to an action. diff --git a/docs/Apps/forms/field-groups.md b/docs/Apps/forms/field-groups.md index dd3de58be..b4389d84d 100644 --- a/docs/Apps/forms/field-groups.md +++ b/docs/Apps/forms/field-groups.md @@ -10,46 +10,28 @@ metadata: next: description: '' --- -`Field Groups` are components that group fields together within custom forms. They allow nested fields to be neatly aligned with each other, let you style your fields with consistent label positions, and offer us the ability to automatically update form schemas. +Field groups control how form fields are arranged inside a form. > 👍 Form block > -> The [Form block](doc:form-block) will also automatically include all form fields of the chosen schema by default, and allow you to choose and arrange the included fields. -> -> Form Blocks are a better option for most use cases, but we can still build our forms manually in more advanced cases, including using Form Blocks. - -## Updating fields automatically - -Field groups have a powerful function that can save you a lot of time when working on [Forms](doc:forms) - they let you reset them. This automatically populates forms with all the fields in your [Form schema](https://docs.budibase.com/docs/forms#form-schema). - -This means you can generate a full form in one click, or you can add in missing fields if you change your schema. Field Groups must be nested within a `Form` component for this to work. +> The [Form block](doc:form-block) can auto-generate fields for you. Use field groups when you need more control over layout. -When you select a field group component in the builder, you'll be able to press `Update form fields` in the Settings Panel to perform this function. +## Update form fields - +Use `Update form fields` to generate fields from the form schema or refresh them after the schema changes. -Auto-populated form fields - Auto-populated form fields - - -
+Field groups must be nested inside a `Form` component for this to work. ## Layout -In addition to auto-populating form fields, you can also use field groups to determine how the fields should be displayed. The default layout type is `One column`, but you can add multiple columns or `main and sidebar` layouts in a couple of clicks. - - - -Main with sidebar layout - Main with sidebar layout - - -
+Use field groups to control how fields are displayed. Available layouts include: -### Label alignment +* One column +* Multiple columns +* Main with sidebar -You can also choose whether labels are aligned to the *Left* or *Above* your fields. +## Label alignment - +Choose whether labels are aligned `Left` or `Above`. -It is worth noting that layout options are only available for labels that aligned *Above* the fields, as shown in the screenshots. +Layout options only apply when labels are aligned `Above`. diff --git a/docs/Apps/forms/form-bindings.md b/docs/Apps/forms/form-bindings.md index 14bc45e6c..0f836c4a9 100644 --- a/docs/Apps/forms/form-bindings.md +++ b/docs/Apps/forms/form-bindings.md @@ -10,152 +10,36 @@ metadata: next: description: '' --- -Forms are critical in a workspace, as they allow users to collect, edit, and submit data. +Use form bindings when field values need to come from dynamic data. -Bindings are not required for basic forms, but they are useful when you need dynamic labels, placeholders, or default values in the internal [Budibase DB](doc:budibasedb) and [SQL](doc:sql-datasource) tables. +Common uses include: -You may want to read the value of a form field when handling cases such as: +* Default values +* Dynamic labels and placeholders +* On change actions +* Conditional UI +* Filtering -* [On change event](https://docs.budibase.com/docs/actions#on-change) -* [Conditional UI](doc:conditions) -* [Filtering](https://docs.budibase.com/docs/searchfilter-data#filtering-data-from-the-front-end) +## Read values into a form -*** +Bind a field to query output, app state, or a repeater when you want the form to load existing data. -## Read Query: Setting default values +## Write values from a form -A default value binding is applied when the screen first loads. +Use form field bindings in create queries or save actions to pass submitted values into the database or API request. -Consider a [REST query](doc:rest-queries) that retrieves an employee record for a bound ID. We can add a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block) to a [Screen](doc:screens) to pull that employee data. +## On change -#### Step 1 - Setup the repeater block +Use `On change` when a field should update another field or trigger an action as soon as its value changes. -REST query to GET a single employee from rowId binding - REST query to GET a single employee from rowId binding - +Common uses include: -Selecting the GET query as the data source - Selecting the GET query as the data source - +* Calculating derived values +* Updating helper fields +* Showing or hiding controls based on the selected value -After selecting the GET query as the data source for the repeater block, click the cog icon and provide a binding value. +## Good practice -In this example, the repeater uses `{{ URL.id }}` from [URL variables](doc:url-parameters). You can also use [App state](https://docs.budibase.com/docs/app-state#app-state-in-blocks). - -Passing the rowId into the GET query - Passing the rowId into the GET query - - -#### Step 2 - Configure the form - -Add a [Form](doc:forms) and the fields you want to populate. Use a unique name in the *Field* setting, or select a field if you are using a [Create query](https://docs.budibase.com/docs/form-bindings#create-query-mapping-query-bindings-to-form-fields). - -For the *Default value* setting, click on the lightning bolt icon, and add the binding to pull out the specific field, for example *Address*: - - - -```Text Default value binding example -{{ Employee Repeater block.GET Employee Row.Address }} -``` - -Once the fields have the correct default values, you should see something like this: - - - -You may need to refresh the page. Default values only apply on load. - -*** - -## Create Query: Mapping query bindings to form fields - -If you are building a create form, you can use the bindings from a `Create` custom query as the schema for the form. The form fields populate in a [Field group](doc:field-groups) to match the query inputs. - -For example, consider a POST REST query: - -#### Step 1 - Add the REST query - -Add the binding fields and any default values. These are used in the POST body and as the form schema in Design. - -POST query bindings - POST query bindings - - -POST query body - POST query body - - -#### Step 2 - Add the form - -Add a form and select the create query as the schema. - -Selecting the form schema - Selecting the form schema - - -Add a field group, then click `Update form fields`. Budibase will populate the Component Tree with form fields that match your bindings. - -Auto-populating form fields via the field group - Auto-populating form fields via the field group - - -Add a submit [Button](doc:button) with an [Execute query action](https://docs.budibase.com/docs/data-actions#execute-query), then bind the query inputs to the form fields: - - - -> 👍 -> -> You can combine the read and create examples into a single form. - -*** - -## On Change event - -Use the *On Change* event when you want to run [Actions](doc:actions) after a field value changes. - -In the Settings Panel of each form field, click `Define action` beside *On change*. - -### Calculate age from DOB field - -1. Create a **Patients** table with a [Text](doc:text) field for the patient name and a [Date/Time](doc:datetime) field for the DOB. - - - -2. Add a **Side panel** [Autogenerated screen](https://docs.budibase.com/docs/screens#autogenerated-screen) for the **Patients** table. -3. Eject the form block, then add a disabled [Number field](https://docs.budibase.com/docs/text-inputs#number-field) called `Age`. - - - -4. Select the *DOB* field, then add an **Update Field Value** action for the `Age` field. -5. For the value, open the *JavaScript* tab and calculate the age from the DOB. - -![](https://files.readme.io/a52f4f6-small-Screenshot_2023-05-10_at_15.04.20.png) - -6. Provide the following JavaScript binding: - -```javascript Calculate Age from DOB -/** -* Source: https://stackoverflow.com/questions/10008050/get-age-from-birthdate -*/ -function getAge(dateString) { - var today = new Date(); - var birthDate = new Date(dateString); - var age = today.getFullYear() - birthDate.getFullYear(); - var m = today.getMonth() - birthDate.getMonth(); - if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { - age--; - } - return age; -} - -return getAge($("Field Value")); -``` - -Save the form after updating the binding. - -> 👍 `{{ Field Value }}` -> -> Gets the current field value. - -> ❗️ `{{ Details Form.Fields.DOB }}` -> -> Gets the previous value before *On change* runs. +* Keep binding names stable +* Use default values for loaded data +* Use `Configure validation` when user input must match a rule diff --git a/docs/Apps/forms/form-steps.md b/docs/Apps/forms/form-steps.md index 46c5a15ba..920d0ef25 100644 --- a/docs/Apps/forms/form-steps.md +++ b/docs/Apps/forms/form-steps.md @@ -10,124 +10,23 @@ metadata: next: description: '' --- +Use `Form Step` components when you want to split a form into multiple screens. + > 👍 Multi-step form block > -> If you're working with a single data table, the [Multi-step form block](doc:multi-step-form-block) is the quickest way to get started! - -The `Form Step` component allows us to create complex form structures, by only displaying certain fields at any given time. We can nest components within Form Steps, and control whether or not they appear using the `Change Form Step` button action. - -There are a few different options that can be selected within the action `Change Form Step`. - -* **Next Step** - Allows the user to move to the next form step. (Majority of the time this is attached to a button on click action) -* **Previous Step** - Allows the user to move to the previous form step. -* **First Step** - When used change the form step back to 1. -* **Specific Step** - Allows the user to jump between steps e.g. can go from step 1 to step 5. - - - -An example of where we might use `Form Step` components manually instead of a `Multi-Step Form Block` is creating a single form that allows us to save data to multiple tables, using distinct form steps. - -## Data - -Create two tables with a many-many relationship: - -* Employees -* Addresses - - - - - -## Building our form - -We’ll start by autogenerating a Form screen for our `Employees` table. By default, this contains a single `Form Block` component. - - - -This will form the basis of our first form step. We’ll make the following changes to our default form: - -* Update the `Title` to `Add an Employee`, -* Update the `Subtitle` to `Step 1/2`, -* Disable the `Addresses` field, -* Set the `Button Position` to `Top`. - - - -We’ll then hit `Eject Block` to expose the underlying components that make up our Form Block. - -
- - - -
- -This gives us the following component tree. - - - -We’re going to add a `Form Step` component, and nest the outer-most `Container` within our form inside of this. - - - -Note that `Form Step` components accept a single numerical argument, `Step`. By default, this is set to `1`. - -## Adding our second step - -To create our second form step, we’ll simply duplicate this existing one, making sure to rename it and update its `Step` value to `2`. - - - - - -We’ll then update our subheading to read `Step 2/2`. - - - -Next, we’ll replace the fields in our second step to match the schema of our `Addresses` table. - - - -As this is a relatively simple table, we can easily to this by manually adding `Text Field` components. For more complex schemas, you may wish to generate and eject a new form block before replacing the entire container. - -## Configuring buttons - -Lastly, we need to configure our two `Buttons` to reflect our desired user experience. Specifically: - -* The button in `Step 1` should increment the current form step. -* The button in `Step 2` should save the data from both steps to their respective tables. - -For the `Step 1` button, we’ll start by setting the `Text` to `Next` and the `Variant` to `Primary`. - - - -We’ll then replace all of its existing `On Click` actions with a single `Change Form Step` action, incrementing our form step. - - - -Our second button is closer to its intended functionality. - -Currently, this contains a sequence of actions to validate and save our form, before updating various UI elements. - - - -We’ll add a second `Save Row` action immediately after the existing one, choosing `Addresses` as our `Table`. - - - -We then need to manually define the values that we’ll pass to this action for each column. We’re setting our `Employees` value using `{{ Action 2.Saved row._id }}` - - - -We’ll then bind our remaining columns to the values in our form, in the format `{{ Form.Fields.Street }}`. +> If your form uses one table, the [Multi-step form block](doc:multi-step-form-block) is usually the faster option. - +## How it works -Now, when we preview our app and submit our form, related rows will be created on each of our tables. +`Form Step` components show one section of a form at a time. Use the `Change Form Step` action to move between steps. - +Common step actions: -## Initial form step +* `Next Step` +* `Previous Step` +* `First Step` +* `Specific Step` -You have the option to set the form step directly on the form component itself. This feature is especially valuable when you want to preserve the current form step using [persisted state](https://docs.budibase.com/docs/app-state#persisting-values). +## When to use it - +Use manual form steps when you need a single form to save data across multiple tables or when you need custom step-level control. diff --git a/docs/Apps/forms/form-validation.md b/docs/Apps/forms/form-validation.md index 334872be6..e32b1b46f 100644 --- a/docs/Apps/forms/form-validation.md +++ b/docs/Apps/forms/form-validation.md @@ -10,58 +10,37 @@ metadata: next: description: '' --- -Forms automatically validate their fields if a form schema has been assigned, showing validation error messages underneath any violating fields.\ -The validation rules are defined by the [Constraints](https://docs.budibase.com/docs/budibasedb#constraints) of the linked table. +Forms validate fields automatically when a schema is assigned. Validation rules come from the linked table constraints. ## Validate form action -Forms created within [Autogenerated screens](https://docs.budibase.com/docs/screens#autogenerated-screen) will automatically provide a 'Save' button with a *Validate Form* action. +Forms created in [Autogenerated screens](https://docs.budibase.com/docs/screens#autogenerated-screen) already include a `Validate Form` action on the Save button. -If you want to add the [Action](doc:actions) manually, simply select *Validate Form* from the action list.\ -Next choose the form you want to validate from the dropdown. In order for the form to appear within the options list, the button must be nested within the form in the component tree. +To add it manually, choose `Validate Form` from the action list and select the target form from the dropdown. The button must be nested inside the form. -This action will trigger the form validation, show any errors, and stop executing any further actions if the form is invalid.\ -The standard way to use this is for your first action to be validating the form, and the second action to be performing your task - for example saving a row. This ensures only valid forms will be submitted. - -| Name | Phone Number | -| :------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------ | -| ![](https://files.readme.io/4d4c58e3b4557d78242ca04d3faa7b2efc2659639408241848625522792cb4ed-image.png) | ![](https://files.readme.io/2fd283a983e34360f3cc0d8cc1d6f0dc3bdd49dfb5eb021b9bf31016d03b6fbe-image.png) | - -![](https://files.readme.io/76d807b-Screenshot_2022-06-23_at_18.02.01.png "Screenshot 2022-06-23 at 18.02.01.png") +Use this action first in a button action chain so invalid forms stop before any save or submit action runs. > 📘 Form steps > -> Validation is only triggered for the fields within the currently displayed form step +> Validation only applies to the currently displayed form step. ## Custom validation rules -There are a number of scenarios in which you would want to use custom validation rules: - -1. You are using a custom [Form Schema](https://docs.budibase.com/docs/forms#form-schema) -2. You want access to regex pattern matching -3. You want to use a Binding in your validation conditions -4. You want to display a custom violation message +Use custom validation when you need: -To add a custom rule, click on your form field. Then within the settings panel click *Configure validation*.\ -A panel will appear, from which you can add rules, enter constraint bindings, and enter custom validation messages. +1. A custom [Form Schema](https://docs.budibase.com/docs/forms#form-schema) +2. Regex pattern matching +3. A Binding in the validation condition +4. A custom violation message - +To add a custom rule, open the field settings and click `Configure validation`. ### Regex -One of many use cases for using regex would be to check for alphabetical characters only.\ -To do this, select *Must not match regex* with the value: `^[A-Za-z\s]+$` - - - - +Use regex rules when you need pattern-based validation, such as allowing only letters and spaces. ### Conditional validation rules -It is also possible to dynamically change validation rules through [Conditional UI](doc:conditions). - -Add a condition to a field, then select *Update setting* and *Validation* from the dropdowns.\ -You will then be able to click configure to add custom rules as shown above.\ -Finally, set a condition for applying that validation. When the condition is no longer met, then that validation rule will be removed from the field. +You can also change validation rules with [Conditional UI](doc:conditions). -![](https://files.readme.io/1e5b5a2-Screenshot_2022-06-23_at_19.06.29.png "Screenshot 2022-06-23 at 19.06.29.png") +Add a condition to the field, choose `Update setting`, then `Validation`, and define when the rule should apply. When the condition no longer matches, Budibase removes that validation rule. diff --git a/docs/Apps/forms/index.md b/docs/Apps/forms/index.md index 4951db92f..4badf8f67 100644 --- a/docs/Apps/forms/index.md +++ b/docs/Apps/forms/index.md @@ -10,30 +10,30 @@ metadata: next: description: '' --- -Forms are the primary building blocks of data-heavy applications. Use them to create and edit data with a consistent layout and theme. +Use forms to create and edit data with a consistent layout. Forms are built from three main component types: -1. **Form component** -2. **Field group component** -3. **Input components** +1. `Form` +2. `Field group` +3. Input components ## Form component -The Form component is the top-level container. All [Field groups](doc:field-groups) must be placed inside it. +The Form component is the top-level container. Place [Field groups](doc:field-groups) inside it. -You can also use fields independently of a form when you need simpler input controls, such as search fields. +Use a form when you want Budibase to handle submitted values, validation, and save actions together. ### Form schema -Forms have an optional **Schema** setting. The schema can be a table, view, relationship, or custom source. +A form can use a table, view, relationship, or custom source as its schema. Choosing a schema helps with: * Picking field names from a dropdown * Matching validation to the selected data type * Generating form components automatically -* Creating rows with the correct table schema +* Saving data with the expected table shape > 🚧 Schema from query > @@ -41,24 +41,17 @@ Choosing a schema helps with: ### Form type -A form can be in `Create` mode or `Update` mode. - -In `Create` mode, fields start blank unless they have a Default Value. - -In `Update` mode, fields are populated from the parent [Repeater](doc:repeater) data, unless the schema is custom. +* `Create` starts with blank fields unless a default value is set +* `Update` fills fields from the parent [Repeater](doc:repeater) or row binding ## Inputs -Each input component represents a single field. The field name comes from the schema or can be typed manually if no schema is set. - -### Custom Inputs / Fields - -You can add custom fields that are not part of the schema. Data Bindings always reflect the names of the fields in the form. +Each input represents a single field. The field name comes from the schema or can be typed manually if no schema is set. -### Help text setting +Use custom fields when the form needs values that are not part of the schema. Form bindings always reflect the field names in the form. -Use help text to give context or explain validation. If validation fails, the help text is replaced with the error message. +Help text gives users context or validation guidance. If validation fails, Budibase replaces the help text with the error message. ## Nesting non-form components -Forms can contain any components, not just fields. Use [Field groups](doc:field-groups) to manage layout. +Forms can contain other components as well. Use [Field groups](doc:field-groups) to manage layout. diff --git a/docs/Apps/forms/save-static-value.md b/docs/Apps/forms/save-static-value.md index 311386ae3..187964fa3 100644 --- a/docs/Apps/forms/save-static-value.md +++ b/docs/Apps/forms/save-static-value.md @@ -10,6 +10,15 @@ metadata: next: description: '' --- -It is common to save a static value when a user submits a form. For example, when an applicant applies for a job, you may want to save a value such as `Requires HR attention`. +Use a static value when a form submission should always save the same value to a column. -To do this, open the button in your form and add a **Save Row** action. Add the target column, then enter the static value. Every time the form is submitted, Budibase saves that value alongside the row. +For example, you might always save `Requires HR attention` when a job application is submitted. + +To do this: + +1. Open the form button +2. Add a `Save Row` action +3. Choose the target column +4. Enter the static value + +Budibase saves that value each time the form is submitted. diff --git a/docs/Apps/pickers/date-picker.md b/docs/Apps/pickers/date-picker.md index 2ce01b529..a7d2d42bf 100644 --- a/docs/Apps/pickers/date-picker.md +++ b/docs/Apps/pickers/date-picker.md @@ -10,49 +10,30 @@ metadata: next: description: '' --- -The Date Picker allows you to select a `Date`, `DateTime` or `Time`, depending on your settings. - -{1418} - Left: Date/time; Top-right: Date; Bottom-right: Time - - -As you can see above there's three flavours of the date and/or time pickers. +Use the Date Picker to select a `Date`, `DateTime`, or `Time` value. ## Add a date picker -The `Date Picker` needs to be a child of the [Form](doc:forms) component. - -To add the `Date Picker` component, click `Form > Date Picker`. - -![](https://files.readme.io/7a390a5-Screenshot_2023-07-04_at_12.15.43.png) - -After the Date Picker is added you can start to configure it. - -## Date, Date/Time or Time? - -To choose between the different types of pickers, you can use two checkboxes in the Settings Panel to get three different results. - -![](https://files.readme.io/13f6cc1-date-picker-checkboxes.png "date-picker-checkboxes.png") +1. Add a [Form](doc:forms) +2. Add a `Date Picker` inside the form +3. Set the picker type in the settings panel -To get the results, only check the box which are mentioned below. +## Picker types -* **Date/time**: ☑ Show Time -* **Date**: ☐ Show Time + ☐ Time Only -* **Time**: ☑ Time Only +Use the settings panel to choose one of these modes: -## Using the calendar +* Date and time +* Date only +* Time only -In addition to clicking the navigation arrows, users can use gestures to move between months: +## Common settings -* **Scroll**: On desktop, use a mouse wheel or trackpad to scroll over the calendar body to change months. -* **Swipe**: On touch devices, swipe horizontally across the calendar body to move to the next or previous month. +* Field +* Label +* Placeholder +* Default value +* Disabled -## Further configuration +## Calendar navigation -| Setting | Description | -| :------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Field | Connected field from the parent [Form](doc:forms) element, or custom by typing in a field name. | -| Label | The text visible to the user next to the `Date Picker` as a descriptor of the field | -| Placeholder | The text displayed in a lighter tint inside the `Date Picker`. Will only display when the picker has no value | -| Default Value | When a default value is provided, every time the form is opened this will be prefilled in the `Date Picker`. Entering this will also prevent the `Placeholder` from showing | -| Disabled | When checked, disables the field; The user cannot change the value. | \ No newline at end of file +Users can move between months by scrolling on desktop or swiping on touch devices. diff --git a/docs/Apps/pickers/index.md b/docs/Apps/pickers/index.md index c9fe0d4da..ba0894692 100644 --- a/docs/Apps/pickers/index.md +++ b/docs/Apps/pickers/index.md @@ -1,6 +1,6 @@ --- title: Pickers -excerpt: Selecting values from a range of options +excerpt: Selecting values from a range of options. deprecated: false hidden: false metadata: @@ -10,32 +10,22 @@ metadata: next: description: '' --- -All pickers are [Form](doc:forms) components that cover a range of data types. +Pickers are form components for choosing values. -In addition, each picker can perform an [Action](doc:actions) when an item is selected through the [On Change](https://docs.budibase.com/docs/form-actions#on-change) event. +They can also run an action when the value changes. -This page will summarise the five available pickers within Budibase. +## Picker types -## Options and Multi-select pickers +* Options picker +* Multi-select picker +* Relationship picker +* Date picker +* User field -There are three [available data sources](https://docs.budibase.com/docs/option-picker#displaying-options-in-the-options-picker) for dropdown lists in Budibase. +## Use each picker -The [Options Picker](doc:option-picker) only allows the user to select a single item, whereas the [Multi-select Picker](doc:multi-select-picker) allows a user to select many. - -## Relationship picker - -The [Relationship picker](doc:filter-by-relationships) should always be used to handle [Relationship](doc:relationships) fields. - -## Date picker - -The [Date Picker](doc:date-picker) allows a user to select a [Date/Time](https://docs.budibase.com/docs/datetime) from a pop-up calendar. - -## User Field - -A special field type that only works with the [User](doc:users-1) data type. If the *Allow multiple users* is selected, then it will automatically allow multiple selections, otherwise only one user can be chosen. - -It can also be optionally searched on the users email address. - -Adding a user field - Adding a user field - +* Use [Options picker](doc:option-picker) for single-value choices +* Use [Multi-select picker](doc:multi-select-picker) for multiple choices +* Use [Relationship picker](doc:filter-by-relationships) for relationship fields +* Use [Date picker](doc:date-picker) for dates and times +* Use the User field for selecting users diff --git a/docs/Apps/pickers/option-picker.md b/docs/Apps/pickers/option-picker.md index 2e30be655..f61cfea10 100644 --- a/docs/Apps/pickers/option-picker.md +++ b/docs/Apps/pickers/option-picker.md @@ -10,177 +10,44 @@ metadata: next: description: '' --- -The options picker component is a great tool to fill an Single Select data column or let your users select an item from a table of choice. It allows your users to pick a single option from a dropdown that is filled based on the connected data source, or through a custom schema to be used in other manners. +Use the Options Picker to let a user select a single value from a list. -![](https://files.readme.io/9118efb-options-picker.png "options-picker.png") +Add it inside a [Form](doc:forms). -## Adding an options picker +## Option sources -To add the options picker to your app, you first need to wrap it within a [Form](doc:forms) component. Once that is done you can add the `options picker` through `Form > Options Picker` +You can populate options from: -![](https://files.readme.io/702802c-Screenshot_2023-07-04_at_12.09.44.png) +* Schema +* Data provider +* Custom options -The options picker will now be added in an empty state to your UI. +## Use schema options -## Displaying options in the options picker +Use schema options when the values are stored on the form's table schema. -To display options in the option picker, you have a few routes to do this. Either you can let the options prefill based on the existing data or data-schema, or you can specify custom options so you can use the choice to do something else, for example, use in Automation, or transform it yourself before adding it to a table. Below is a quick table to highlight the purpose of each method. +This works best for static values that do not change often. - - - - +## Use a data provider - +Use a data provider when the options should come from another datasource. - - - +You need a provider, a label column, and a value column. - - - +## Use custom options - +Use custom options when you want to define the labels and values manually. - - - - - - - - - - - - - - - - - - - -
- Method - - Description - - Examples -
- Schema - - When you configure your data structure, you may configure an options field to have predefined, static options. Use this method, when the options are defined and unlikely to change. - - Low, medium, high +This is useful for public forms, API-driven values, and other custom workflows. - *1,2,3,4,5* +## Other settings - Cold, warm, hot -
- Data provider - - In some cases, you may want to populate your options picker with data from a field in your database, other than predefined options. So, when new data is entered in to your database, the Options picker is updated, dynamically. Use this method when the options are not predefined and likely to update. - - Categories - - Tags -
- Custom - - The custom method allows you to define options in the design section of the Budibase builder. It also allows you to assign a value to an option. Using the custom method, you can also: - - * populate values in the form, from an API request, or custom query. - * populate options in a form without giving the user write access to your database (good for public forms) - - Thor = correct,\ - Spiderman = incorrect,\ - Hulk = incorrect,\ - Iron man = incorrect -
- -### Using options from the parent form - -To use options straight from the table schema of your form, you need to make sure you have your wrapping form linked to a table. You can do this in the Settings Panel of the form, and picking the correct table in the `schema` option. - -Once this is done, you can return to the Settings Panel of the `Options Picker` and define your schema. For this, you only need to select the right field, or data column, in the `Field` option in the Settings Panel. - -You will then automatically see the options defined in the table schema reflect. - -Form set to Inventory (sample data) - Form set to Inventory (sample data) - - -
- -> 🚧 Supported Column Types -> -> When using a schema options source, the column must be of type 'Single Select' with the options provided. When using a data provider, options can be populated from Text rows. - -### Using a data provider - -Using a data provider is very similar to using the schema from the form, but in this case, it allows you to pick options from a data source that's different to what is configured in the form. - -To be able to select a data provider, you of course need to have the form wrapped inside a [Data Provider](doc:data-provider). - -First, select `Data Provider` as the `options source` in the Settings Panel. - -![](https://files.readme.io/6836a752cc25ad24c5805e341d48eee9cf7eb1ddc9b97a0e12a6216f1555513a-image.png) - -Next, there are 3 selections to be made in the Settings Panel. The actual data provider, the label column, and the value column. - -![](https://files.readme.io/dcd0eee41e44e4a7f30ab60ec8a55ca292f5e930454e135c102d7326064ee01c-image.png) - -The `Label` column is what is visible to the user to select from, and the `Value` column defines what is actually selected in the background. This can be an ID or an Single Select data-type column, for example. - -### Using custom options - -To use custom options, you need to select `Custom` as the options source in the Settings Panel. - -![](https://files.readme.io/396e8d79230cf646dea01d34a2d7edc8b753950c35bef875a24c361c9e695945-image.png) - -After selecting `Custom`, a new setting will appear in the Settings Panel, namely, `Define Options`. Clicking this will open up the bindings drawer where you can specify both label and value. - - - -Add as many options as you need, and fill both the `label` and the `value` field. The `label` field is intended as visual to your users, where the `value` field is intended for usage in your application, such as storing in a data-source, or through other means. - -## Adding autocomplete - -Autocomplete is a powerful feature which allows your user to type in the options picker to find the item they're looking for. This is especially useful when you have a long list of options to choose from. To enable this, you have to click the `Autocomplete` checkbox in the Settings Panel. - -This will transform the dropdown to have a search field. - -## Using radio buttons - -To use Radio buttons, all you have to do is select the `Radio Button` option through the `Type` setting in the Settings Panel. - -![](https://files.readme.io/6b21ae3f37c3610ddb938e4c6496a38e2e120c1f0dfd0f30c1d7f3fb4a204144-image.png) - -This will automatically transform the UI to use radio buttons instead of a dropdown. - -![](https://files.readme.io/1ff01481e62441e1424317cd4fd2fb70dfd6a655f7f9a9dc3a8767705d9e44f0-image.png) - -### Horizontal or vertical mode - -The image above illustrates the vertical mode of the radio buttons. You can also specify `horizontal` mode in the Settings Panel. - -![](https://files.readme.io/fae301b26c5996b566b84277f3d444320d3eab3ab25dd86f02b02f2bd79d0959-image.png) - -After selecting `horizontal`, your UI will look more compact, like below. - -![](https://files.readme.io/4b717241ed9b7eb3ff75ca4868e80a5e7c15fe75954e01a1d5b47a84f6b9fc5b-image.png) - -## Further settings - -There are more settings in the Settings Panel than have been discussed here. They're not complicated but might require explanation. You can find them in the reference table below. - -| Setting | Description | -| :------------------- | :---------------------------------------------------------------------------------------------- | -| Field | Connected field from the parent [Form](doc:forms) element, or custom by typing in a field name. | -| Name | The name of the field, displayed next to the options picker | -| Placeholder | The text displayed on the options panel when no option has been selected | -| Default value | A pre-selected value you can define using [Bindings](doc:bindings). | -| Disabled | Disables the field from editing | -| Configure Validation | Allows you to specify validation rules | +* Autocomplete +* Radio button type +* Horizontal layout +* Field +* Name +* Placeholder +* Default value +* Disabled +* Validation diff --git a/docs/Apps/working-with-data/adding-a-search-field.md b/docs/Apps/working-with-data/adding-a-search-field.md index 423f3b06c..213d76e09 100644 --- a/docs/Apps/working-with-data/adding-a-search-field.md +++ b/docs/Apps/working-with-data/adding-a-search-field.md @@ -10,100 +10,33 @@ metadata: next: description: '' --- -Most internal apps involve viewing and interacting with data. Adding search to your data display component, such as a [Table](doc:table) provides a better experience for the end-user. Using Budibase, there are three ways to achieve this: +Use search when users need to narrow table data quickly. -1. Using the Table itself -2. Using a form, table, and text input - the flexible way -3. Using a table and dynamic filter - the filter/search hybrid approach (also very easy) +There are three common patterns: -This guide will cover all three methods for adding search to a table. For each process, you will need data. In the tutorials, we will use the following CSV. If you have data, please continue to the tutorials below. If you don't have data, please download (File > Download) the following CSV and upload it to the [Budibase DB](doc:budibasedb). +1. Use the Table component's built-in search +2. Use a form field and filter bindings +3. Use a Data provider with a Dynamic filter - +## Built-in table search -**Right, let's do this 🏁** +Add the columns you want to search in the Table component. Text columns show a search input automatically. -*** +## Form field search -# 1. Using the table itself +Use a text input and bind it into a Data provider filter when you need a custom search experience. -Built into the [Table](doc:table) is a search field for every column you choose to display. +The common pattern is: -*Please note, that the searchable text field will appear only if the data type of the field you choose is text/string. If the field is stored as an option, a picker component will appear instead.* +1. Add a Table +2. Add a text input in a Form +3. Bind the input value into the Table filter +4. Return all rows when the input is empty - +## Dynamic filter search -*** +Use a Data provider plus a Dynamic filter when you want users to choose their own filter columns and values. -# 2. Using a form and text input (flexible way) +## Related guide -Here's a quick overview of what we're going to do: - -* Display data in a table -* Add a form and text field -* Connect the table's data to the search input - -## Display data in a table - -To get started, add a table component to your screen, and in the Settings Panel choose the data source to be the table you wish to display. to select your Datasource. You should now have a table with data. - - - -## Add a form and text field - -Add a new text field. Give the text field a name (this is how it will appear in bindings) and a label (this is what the user will see). You may also wish to add placeholder or help text. - -### Define filters - -Now in the settings menu of the Table Component, click to add a filter - - - - - -With these settings, when no nothing in in the search bar, all rows will be displayed. When something is in the search bar, all rows where the region is *like* (ie a partial or full match) will be returned. When Country or Item Type are an exact match, rows will be returned accordingly. When there are no rows that match, the table will show all rows available. - -An example using Customer Name to search the data. - An example using Customer Name to search the data. - - -##  Adding a search button (optional) - -After following these steps you will now have a reactive search field - i.e. whenever you press the enter key or click off the text field the search will trigger. - -You may instead prefer to only trigger the search on click of a button. A guide on doing that can be found in [this Github discussion](https://github.com/Budibase/budibase/discussions/10402#discussioncomment-5710657). - -*** - -# 3. Using a table and dynamic filter - the filter/search hybrid approach - -This approach does not provide a search input. But it is easy to set up and allows your users to filter/search their table data. We can add dynamic filtering to our data in 3 simple steps: - -1. Add a data provider and change the Data setting to match your data source - in our case *Sales*. -2. Add a dynamic filter component -3. Add a table component - -## Get Started - -1. Start by adding a Data Provider, and selecting the data source you wish to serve to the user. - - - -2. Next, add a Table component, and set it's Data source to be the Data Provider you added int the step above. It's important to use the Data Provider as the source here, instead of simply setting the table itself as your datasource. -3. - - Next, add a Dynamic Filter component and set it's Data source to also be the same Data Provider. Your component tree should look similar to this: - - -4. In the settings of the Dynamic Filter you can now give users the option to set filters based on allowed columns. - - - -As we can see in the example below a user can set their own filters to help them find and display specific rows that they are looking for. - - - -*** - -> 👍 Ask the community about search -> -> If you're running into any issues with adding search functionality to your data, [open a discussion](https://github.com/Budibase/budibase/discussions) within our community forum. +* [Adding filtering](doc:searchfilter-data) diff --git a/docs/Apps/working-with-data/adding-search-copy.md b/docs/Apps/working-with-data/adding-search-copy.md index 2b6e5de39..3619071a3 100644 --- a/docs/Apps/working-with-data/adding-search-copy.md +++ b/docs/Apps/working-with-data/adding-search-copy.md @@ -10,100 +10,4 @@ metadata: next: description: '' --- -Most internal apps involve viewing and interacting with data. Adding search to your data display component, such as a [Table](doc:table) provides a better experience for the end-user. Using Budibase, there are three ways to achieve this: - -1. Using the Table itself -2. Using a form, table, and text input - the flexible way -3. Using a table and dynamic filter - the filter/search hybrid approach (also very easy) - -This guide will cover all three methods for adding search to a table. For each process, you will need data. In the tutorials, we will use the following CSV. If you have data, please continue to the tutorials below. If you don't have data, please download (File > Download) the following CSV and upload it to the [Budibase DB](doc:budibasedb). - - - -**Right, let's do this 🏁** - -*** - -# 1. Using the table itself - -Built into the [Table](doc:table) is a search field for every column you choose to display. - -*Please note, that the searchable text field will appear only if the data type of the field you choose is text/string. If the field is stored as an option, a picker component will appear instead.* - - - -*** - -# 2. Using a form and text input (flexible way) - -Here's a quick overview of what we're going to do: - -* Display data in a table -* Add a form and text field -* Connect the table's data to the search input - -## Display data in a table - -To get started, add a table component to your screen, and in the Settings Panel choose the data source to be the table you wish to display. to select your Datasource. You should now have a table with data. - - - -## Add a form and text field - -Add a new text field. Give the text field a name (this is how it will appear in bindings) and a label (this is what the user will see). You may also wish to add placeholder or help text. - -### Define filters - -Now in the settings menu of the Table Component, click to add a filter - - - - - -With these settings, when no nothing in in the search bar, all rows will be displayed. When something is in the search bar, all rows where the region is *like* (ie a partial or full match) will be returned. When Country or Item Type are an exact match, rows will be returned accordingly. When there are no rows that match, the table will show all rows available. - -An example using Customer Name to search the data. - An example using Customer Name to search the data. - - -##  Adding a search button (optional) - -After following these steps you will now have a reactive search field - i.e. whenever you press the enter key or click off the text field the search will trigger. - -You may instead prefer to only trigger the search on click of a button. A guide on doing that can be found in [this Github discussion](https://github.com/Budibase/budibase/discussions/10402#discussioncomment-5710657). - -*** - -# 3. Using a table and dynamic filter - the filter/search hybrid approach - -This approach does not provide a search input. But it is easy to set up and allows your users to filter/search their table data. We can add dynamic filtering to our data in 3 simple steps: - -1. Add a data provider and change the Data setting to match your data source - in our case *Sales*. -2. Add a dynamic filter component -3. Add a table component - -## Get Started - -1. Start by adding a Data Provider, and selecting the data source you wish to serve to the user. - - - -2. Next, add a Table component, and set it's Data source to be the Data Provider you added int the step above. It's important to use the Data Provider as the source here, instead of simply setting the table itself as your datasource. -3. - - Next, add a Dynamic Filter component and set it's Data source to also be the same Data Provider. Your component tree should look similar to this: - - -4. In the settings of the Dynamic Filter you can now give users the option to set filters based on allowed columns. - - - -As we can see in the example below a user can set their own filters to help them find and display specific rows that they are looking for. - - - -*** - -> 👍 Ask the community about search -> -> If you're running into any issues with adding search functionality to your data, [open a discussion](https://github.com/Budibase/budibase/discussions) within our community forum. \ No newline at end of file +This page is the older v3 version of the search guide. Prefer [Adding search](doc:adding-a-search-field) for the current guidance. diff --git a/docs/Apps/working-with-data/data-provider.md b/docs/Apps/working-with-data/data-provider.md index 80d2ab739..6600b7a4b 100644 --- a/docs/Apps/working-with-data/data-provider.md +++ b/docs/Apps/working-with-data/data-provider.md @@ -14,97 +14,46 @@ next: slug: repeater title: Repeater --- -The data provider component is one of the most important components in Budibase. It exposes data to any components that expect data input on that particular screen. In previous versions of Budibase, only components nested inside Data Providers could access the data, but that is no longer the case. +Use the Data provider to make data available to components on a screen. -For example, all components under the *Data* section can be provided data. +Data providers can supply data to: -Add component: Data section - Add component: Data section - +* Tables +* Charts +* Repeaters +* Options pickers +* Other blocks that read from a data source -In addition, the following components can make use of data providers: +## Choose a source -* [Options pickers](https://docs.budibase.com/docs/option-picker#displaying-options-in-the-options-picker) -* [Blocks](https://docs.budibase.com/docs/blocks) -* [Charts](doc:chart) +Select a datasource from the `Data` dropdown. You can use: -All of these nested components can access the New Data Provider - All of these nested components can access the New Data Provider - +* Budibase DB tables +* SQL datasources +* Custom queries +* REST queries -Selecting a Data Provider - Selecting a Data Provider - +## Configure results -
+Use the Data provider to: -## Making use of your datasources - -A data provider can make all [Datasources](doc:data-sources) available for consumption within your apps. This includes, but is not limited to: - -* The internal [Budibase DB](doc:budibasedb) tables -* External [SQL Datasources](doc:sql-datasource) -* [Custom queries](https://docs.budibase.com/docs/custom-queries) -* [REST API](doc:rest) - -Once you have added your data provider you need to select which datasource you want to use. Simply click on the *Data* dropdown. - -Providing data from the ServiceLog table - Providing data from the Users table - - -> 🚧 Nested data provider -> -> Whilst you can nest data providers, you may find there to be some performance issues. -> -> It is worth considering if you could display the additional data in another [Screen](doc:screens) or [Modal](https://docs.budibase.com/docs/screens#modal-screen). - -
- -In addition to controlling which datasource that should be available to your child components, data providers also allow you to sort, limit, paginate and filter the data that will ultimately be presented in your app screen. - -
- -## Pagination and sorting - -To determine the sorting of the data rows provided, select a *Sort Column* and *Sort Order*. - - - -In this instance, the [Table](https://docs.budibase.com/docs/table) component can override the default sorting set by the data provider, however with other components the sorting will be static. - - - -You can also see that a **limit** of 5 has been set. This sets the maximum number of rows that can be presented per page. - -Limits, sorting and pagination are done through server side queries where possible for performance, e.g. if the datasource was PostgreSQL, or the Internal Budibase DB. It is worth noting however, that [Custom queries](https://docs.budibase.com/docs/custom-queries) and [REST queries](https://docs.budibase.com/docs/rest-queries) data provider settings are handled client side. As a result, in these cases, sorting will apply on a per page basis only. - -The type of sorting will be determined by the data type of the chosen column. For example text columns will be sorted alphabetically, whereas number columns will be sorted numerically. - -With pagination checked, this can be used by not only tables, but all components that are linked to that data provider. For example, a paginated data provider for a chart component will cause the chart to re-render with the new data as each page is cycled through. - -
+* Set sort column and sort order +* Limit the number of rows returned +* Paginate through results +* Add filters ## Filtering -To add filters to a data provider, click **Define filters**. - - - -This will bring up a drawer from which you can select *match all* or *match any* mode. - -You can then select the column you wish to filter on, alongside the operator. Click **Add filter** to filter on additional columns. - - - -Click [here](https://docs.budibase.com/docs/searchfilter-data) for more on filtering. In this example, we are using a form component with a single text field in it, as seen in the builder screenshots above. +Use `Define filters` to restrict the rows returned. -Similar to sorting, filtering will be performed server side for SQL datasource and the internal Budibase DB, however for custom queries the filtering will be client side. Thus when using custom queries, it is recommended that you provide any filters within the query. +Filtering supports: -
+* Static values +* Bindings +* Multiple filter groups -## When to use a repeater +If a filter uses a binding and the binding is empty, you can choose whether to return all rows or no rows. -If you want to build something a bit more custom than a table; maybe you want a container with some buttons that trigger an action or automation, then you will need the [Repeater](doc:repeater) component. Here's an example of a list of improvements suggested by staff that could help minimize risks and improve safety. +## Use with other components - \ No newline at end of file +Use a Data provider when multiple components need the same source data. If possible, reuse one provider instead of creating several similar queries. diff --git a/docs/Apps/working-with-data/fetching-data.md b/docs/Apps/working-with-data/fetching-data.md index d9f5a348b..717bb374f 100644 --- a/docs/Apps/working-with-data/fetching-data.md +++ b/docs/Apps/working-with-data/fetching-data.md @@ -10,20 +10,25 @@ metadata: next: description: '' --- -After adding a data provider and selecting a datasource, the next step is to add a component that allows you to display your data. In many cases you will use one of the following components: +After you add a Data provider, connect a component that can display the returned rows. + +Common display components include: * [Card](doc:card) -* [Chart](doc:chart) +* [Chart](doc:chart) * [Repeater](doc:repeater) -In the below example, a single Data Provider can supply information to the Sales Bar Chart, as well as a Repeater that displays a Container with a Text component *for every row the data provider returns*. +## Share one data source + +Use a single Data provider when multiple components need the same rows. This reduces duplicate queries and keeps the screen easier to maintain. + +## Common pattern - +1. Add a Data provider +2. Choose a datasource +3. Add a display component such as a Table, Chart, Card, or Repeater +4. Bind the display component to the provider -
+## Reuse data -> 🚧 Using Multiple Data Providers -> -> Data Providers can use other Data Providers as a source -> -> Each time a Data Provider is set to fetch information from a table or query, it creates extra network traffic on screen-load. If you're re-using data in multiple components on your screen, consider using a Data Provider to fetch the table without filters, and then any subsequent Data Providers can fetch from that first Data Provider and filter as needed, cutting down on the amount of queries to your database. \ No newline at end of file +If a screen needs the same data in several places, fetch it once and reuse the provider rather than building separate queries for each component. diff --git a/docs/Apps/working-with-data/index.md b/docs/Apps/working-with-data/index.md index 96e362f72..9eeb1fddb 100644 --- a/docs/Apps/working-with-data/index.md +++ b/docs/Apps/working-with-data/index.md @@ -10,22 +10,23 @@ metadata: next: description: '' --- -A [Data provider](doc:data-provider) fetches data and passes it to child components. Any component that displays data has a **Data** setting where you can choose the provider. +Use a [Data provider](doc:data-provider) to fetch rows and share them with child components. -Data providers control filtering, sorting, and pagination. This keeps the components presentational and makes it easier to reuse the same source across a screen. +Any component that displays data has a **Data** setting where you can choose the provider. -> 👍 Blocks -> -> For common data presentations, use [Blocks](doc:blocks). -> -> Blocks bundle a data provider with other components and reduce nesting in your Component Tree. +## What data providers do -## Fetching data +Data providers control: -After adding a data provider, open the Settings Panel and select a Datasource. +* Filtering +* Sorting +* Pagination -> 🚧 Using Multiple Data Providers -> -> Data providers can use other data providers as a source. -> -> Reusing a single unfiltered provider can reduce extra network traffic when multiple components need the same data. +This keeps display components focused on layout and makes it easier to reuse the same source across a screen. + +## Related pages + +* [Data provider](doc:data-provider) +* [Fetching data](doc:fetching-data) +* [Repeater](doc:repeater) +* [Single Row Provider](doc:single-row-provider) diff --git a/docs/Apps/working-with-data/repeater.md b/docs/Apps/working-with-data/repeater.md index 4b1991581..554fe4b4e 100644 --- a/docs/Apps/working-with-data/repeater.md +++ b/docs/Apps/working-with-data/repeater.md @@ -10,47 +10,37 @@ metadata: next: description: '' --- -The repeater component is used to loop over your data. Every child of your repeater will thus be repeated for every row in the data provider that you have selected. +Use the Repeater component to render the same content once for each row returned by a Data provider. -To get started with it, you must add it as a child of a [Data provider](doc:data-provider) and in the settings, select that data provider. You can then add your components and get started. An example structure can be seen below: +## Setup - - -
+1. Add a [Data provider](doc:data-provider) +2. Add a Repeater inside the Data provider +3. Select the Data provider as the Repeater source +4. Nest the components you want repeated ## Settings -A repeater acts like a container for each of your data rows. With this in mind, it shares many of the settings found in the [Container](https://docs.budibase.com/docs/container) component. - -![](https://files.readme.io/e896a6cece94c793310a08a258b4297932b53f44af26d1bcffe5dd1631c46366-image.png) - - - -There is also an option for choosing a message to display if no rows are present: - -
- -![](https://files.readme.io/fb8dfee-Screenshot_2022-10-07_at_17.57.18.png) - -
- -## Example: Edit screen +Repeater settings are similar to [Container](doc:container) settings. Use them to control layout, spacing, and visibility. -One important role of the Repeater component is to facilitate edit screens. Typically within an edit screen you want to fill out some form data for a single existing record. +Use the no-rows message when the data source returns an empty result set. -Let's explore this further. +## Common use -Edit screen component tree - Edit screen component tree - +Repeaters are useful when you need a custom row layout instead of a table. -1. The [Data provider](https://docs.budibase.com/docs/data-provider) has a filter that returns all rows that match the URL id.\ - See more on [URL variables](doc:url-parameters) +Common patterns include: - +* Cards +* Lists with buttons +* Detail panels +* Nested related data -2. As a data provider will always return an array of results, the Repeater is added to loop over the array - in this case one entry if filtered correctly. +## Edit screens -3. Finally the form is configured with the *Update* [form type](https://docs.budibase.com/docs/forms#form-type) so that the form fields are pre-populated with data from the Repeater. +Repeaters are often used on edit screens to load one row of data into a form. - \ No newline at end of file +1. Filter the Data provider by row ID or URL variable +2. Add a Repeater to unwrap the single returned row +3. Nest the form inside the Repeater +4. Set the form type to `Update` diff --git a/docs/Apps/working-with-data/searchfilter-data.md b/docs/Apps/working-with-data/searchfilter-data.md index 5f7460f08..6fa0f5846 100644 --- a/docs/Apps/working-with-data/searchfilter-data.md +++ b/docs/Apps/working-with-data/searchfilter-data.md @@ -10,58 +10,35 @@ metadata: next: description: '' --- -Below are the different methods of filtering within Budibase. +Use filtering when the screen should only show a subset of rows. ## Dynamic filtering -If you have a [Table](doc:table) component connected to a [Data provider](doc:data-provider) component, you can add dynamic filtering by simply adding the [Dynamic filter](doc:dynamic-filter) component. This should work as soon as you add it. - - +Use the Dynamic filter component with a Table and Data provider when you want users to build their own filters in the UI. ## Static filtering -Once you have linked a Datasource to a component, you can access the filter drawer by clicking the button beside the *Filtering* setting in the Settings Panel. - -The filter drawer is where you select the columns you want to filter on. For example, you may want to return sales records only where any of the sales reps made more than 60 sales, or all sales made in the first week of the month. - -It is also possible to filter on multiple columns, and even filter on the same column multiple times. - -## Filtering data from the front-end - -To let users filter data on the front end, add a [Data provider](doc:data-provider) and connect it to your source. - -Then add a [Form component](doc:form) with two Number fields: - -* `day_start` with the label `Day of month (start)` -* `day_end` with the label `Day of month (end)` - -In the data provider, open the filter drawer and add two expressions: - -* `day_of_month` is `more than or equal to` `day_start` -* `day_of_month` is `less than or equal to` `day_end` - -Users can now choose a start and end day to narrow the results. - -## Filtering options & Filter Groups +Use the Data provider filter drawer when the filter values are known ahead of time or controlled by bindings. -When filtering, there are a few settings that control how the filters are handled. +Common filter uses include: -#### Behaviour when combining Filter Groups +* Exact matches +* Partial text matches +* Range filters +* Multiple conditions across one or more columns -* **Show data which matches all filter groups**: all filters must match when returning records -* **Show data which matches any filter**: records are returned when they match any of the provided filter groups +## Front-end filters -#### Behaviour in Filter Groups themselves +Add form inputs and bind them into Data provider filters when users should control the filter values on the screen. -* **Show data when any of the following filters are matches**: Only one of the filters needs to match in order to return this record -* **Show data when all of the following filters are matches**: All of the filters in this group need to match in order to return this record +This is useful for search bars, range filters, and other interactive filtering controls. -
+## Filter groups -#### When filter empty +Filter groups let you decide whether rows must match all filters or any filter. -This setting is specific to filters that are using Bindings. It determines what data should be returned if the binding values are blank. +When a filter uses a binding and that binding is empty, choose whether to return all rows or no rows. -By default, if all filter binding values are empty, all rows are returned. If *Return no rows* is selected, empty bindings return no rows. This is useful when pairing a table with search fields because an empty search field shows all rows and a value narrows the list. +## Related guide -You can also filter using a [relationship picker](https://docs.budibase.com/docs/filter-by-relationships). +* [Adding search](doc:adding-a-search-field) diff --git a/docs/Apps/working-with-data/single-row-provider.md b/docs/Apps/working-with-data/single-row-provider.md index c5a03f24c..95ee9a056 100644 --- a/docs/Apps/working-with-data/single-row-provider.md +++ b/docs/Apps/working-with-data/single-row-provider.md @@ -1,45 +1,40 @@ --- title: Single Row Provider -excerpt: >- - Like a [Data Provider](https://docs.budibase.com/update/docs/data-provider), - only more targeted. +excerpt: Like a [Data provider](doc:data-provider), only more targeted. deprecated: false hidden: false metadata: description: kba_5hc76 robots: index --- -Using a Single Row Provider, it is possible to fetch all data from a single row in the specified table, when supplied with an `_id`. This can be useful to supplement the on-click actions of a [Table](https://docs.budibase.com/docs/table), or [Chart ](https://docs.budibase.com/docs/chart), for example. +Use a Single Row Provider to fetch one row from a datasource using an `_id`. -## Example +This is useful when a screen or modal needs the details for one selected record. -In a workspace which contains the Budibase DB sample data, create an app and add a blank screen. +## Setup -Add a Data Provider to your screen, and set it to fetch the Expenses table. +1. Add a [Data provider](doc:data-provider) +2. Set the provider to the table you want to read from +3. Add a Single Row Provider inside the screen or modal +4. Set the Single Row Provider datasource to the same table +5. Bind the Row ID to the selected row value or URL variable -Add a Pie Chart and nest it inside the Data Provider. Set the Label column to "Expense ID" and the Data Column to "Cost". Your Pie Chart should now populate. Hovering over each segment will show the cost. +## Display values -In the On-click segment [actions](https://docs.budibase.com/docs/actions) of the Pie Chart, add an "Update State" action, which sets the value `{{Clicked segment._id }}` on the key of "clicked_segment". Remember to Save your changes. +Add text or other display components inside the Single Row Provider. -Next, add a Modal, and set it to be a sibling of the Data Provider (not nested within). You can do this by dragging it around on the component tree. Inside the Modal, add a Single Row Provider, and set it's Datasource to be the same Expenses table as the Pie Chart, and set the Row ID to be `{{ State.clicked_segment }}` +Use the bindings drawer to access the columns from the returned row. -Inside the Single Row Provider, add a Text component, and open the bindings drawer using the lightning-bolt icon. Click into the "New Single Row Provider" option, and you'll see the column names from the expenses table. Using the binding for each of these will return the value in that column for the clicked segment. +## Common use -Here's some example text you could use: +Single Row Providers are commonly used for: -```markdown -###### ITEM ID: {{ [New Single Row Provider].Expenses.[Expense ID] }} +* Detail modals +* Edit forms +* Selected-row summaries +* Chart drilldowns -# {{ [New Single Row Provider].Expenses.Cost }} +## Related pages -{{ [New Single Row Provider].Expenses.Notes }} - -Expense Categories -{{ [New Single Row Provider].Expenses.[Expense Tags] }} -``` - -
- -Head back to the On-click actions of the Pie Chart and add another action, this time use the "Open Modal" action, and select your modal from the dropdown list. - -You can test this in Preview, or take a closer look in the builder by fetching a row ID from the table. To do this, view your Expenses table in the data section, and right click on a row to copy the row `_id`. Head back to your app and visit the "State" panel - select your state variable and paste in the row ID you copied. You should now be able to see actual values in the Text component of the Single Row Provider. \ No newline at end of file +* [Data provider](doc:data-provider) +* [Repeater](doc:repeater) From 04579abffd0034e04059120148bea403011d2919 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Wed, 15 Jul 2026 13:21:37 +0100 Subject: [PATCH 22/32] another large batched update --- docs/Apps/actions/chaining-actions.md | 169 ++------- docs/Apps/actions/form-actions.md | 61 ++-- docs/Apps/actions/index.md | 21 +- docs/Apps/app-scripts.md | 119 ++----- docs/Apps/chart/candlestick-chart.md | 163 ++------- docs/Apps/chart/gauge-chart.md | 34 +- docs/Apps/chart/histogram-chart.md | 23 +- docs/Apps/chart/line-chart.md | 178 ++-------- docs/Apps/chart/pie-donut-chart.md | 132 ++----- docs/Apps/chart/progress-donut-chart.md | 77 +---- docs/Apps/components/calendar.md | 326 ++---------------- docs/Apps/components/displaying-text.md | 98 +----- docs/Apps/components/image.md | 79 +---- docs/Apps/components/text-inputs.md | 145 ++------ docs/Apps/conditions.md | 59 ++-- docs/Apps/custom-css.md | 59 +--- .../design-guides/designing-for-mobile.md | 38 +- docs/Apps/design-guides/using-sections.md | 59 +--- docs/Apps/forms/form-steps.md | 16 +- .../introduction-to-apps/app-building-101.md | 245 ++++--------- docs/Apps/link-directly-to-budibase-app.md | 31 +- docs/Apps/pickers/date-picker-copy.md | 44 +-- docs/Apps/pickers/filter-by-relationships.md | 161 ++------- .../working-with-data/adding-search-copy.md | 4 +- .../passing-bindings-in-url-parameters.md | 96 ++---- .../scroll-to-form-field.md | 100 ++---- .../show-button-on-condition.md | 88 ++--- 27 files changed, 561 insertions(+), 2064 deletions(-) diff --git a/docs/Apps/actions/chaining-actions.md b/docs/Apps/actions/chaining-actions.md index 619074ab6..c0d5dc909 100644 --- a/docs/Apps/actions/chaining-actions.md +++ b/docs/Apps/actions/chaining-actions.md @@ -10,163 +10,44 @@ metadata: next: description: '' --- -Use chained actions when one action depends on the output of the previous one. Actions run synchronously, so if one fails, later actions do not run. +Use chained actions when later actions depend on the result of earlier ones. - +Actions run in order. If one fails, later actions do not run. -## Action referencing +## Access previous results -Accessing data from a previous action in a later one can be useful. +Some actions expose their output to later actions. -The following actions expose data after execution: +Common examples include: - - - - +* Save row +* Duplicate row +* Execute query +* Trigger automation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Action Name - - Data Binding - - Returns -
- Save Row - - \{\{ Action X.Saved Row }} - - Field value pairs (including auto-columns) - - * id: Unique row identifier -
- Duplicate Row - - \{\{ Action X.Duplicated Row }} - - Field value pairs (including auto-columns) - - * id: Unique row identifier -
- Execute Query - - \{\{ Action X.Query Result }} - - *First row example*\ - \{\{ Action X.Query Result.data.ne }} - - `{ data: [ _ ] }` - - * An object as determined by the query schema -
- Trigger Automation - - \{\{ Action X.Automation Result }} - - The response of a [Synchronous automation 🔒](doc:synchronous-automations) -
- -**Note** X is the action number. - -
- -*** +Use the action result binding from the previous step to read that output. ## Query result properties -In addition to the payload data of an execute query action result, you can also access: - -* Status code - *Number* -* Response time - *String including the time unit* -* Payload size - *String including the size unit* - -This can be useful with [Conditional UI](doc:conditions) for navigating to different screens on error or changing text color based on the status code. - -### Example - -1. Save the query result to [App state](doc:app-state). Use the **literal** keyword to ensure an object is saved, and not text. - - - -2. Reference the metadata properties with the following Bindings: - -```handlebars -### Status code: {{ State.QueryResult.code }} - -### Response time: {{ State.QueryResult.time }} - -### Payload size: {{ State.QueryResult.size }} -``` - -Response info returned after executing the query - Response info returned after executing the query - - -
- -*** - -## Tutorial: Creating and Linking two table entries in one form - -Use chained actions when one action depends on the output of the previous one. A common pattern is to create one row, then use its ID in a second row. - -#### Setup +Execute query actions also expose: -Create two tables: +* Status code +* Response time +* Payload size -* `guides` with `name`, `phone_number`, and `email` -* `tours` with `destination` and `date` +You can use these values in conditions or display them in the UI. -Add a relationship from `tours` to `guides`. +## Common pattern -#### Build the form +Use chained actions when you need to: -1. Add a form that creates a row in `tours`. -2. Add fields for `destination`, `date`, `TGname`, `TGphone`, and `TGemail`. -3. Add a button with a `Validate Form` action. +* Validate a form +* Save a row +* Reuse the saved row ID in another action +* Clear the form or navigate after the save completes -#### Chain the actions +## Related pages -1. Add a `Save Row` action for `tours`. -2. Add a second `Save Row` action for `guides`. -3. Use the row ID from the first action to link the new guide to the new tour. -4. Optionally add `Clear Form` or `Navigate To` after the saves complete. +* [Form actions](doc:form-actions) +* [Data actions](doc:data-actions) +* [Conditional UI](doc:conditions) diff --git a/docs/Apps/actions/form-actions.md b/docs/Apps/actions/form-actions.md index 41e1470f6..c8b36c4af 100644 --- a/docs/Apps/actions/form-actions.md +++ b/docs/Apps/actions/form-actions.md @@ -1,6 +1,6 @@ --- title: Form actions -excerpt: These actions specifically deal with form interaction. +excerpt: Actions for working with form values and steps. deprecated: false hidden: false metadata: @@ -14,60 +14,47 @@ next: slug: logic-actions title: Logic actions --- -## Update Field Value +Use form actions when an action needs to change a form field, move between steps, or validate a form. -This action will update the value of a form field with a literal value or Binding. +## Update field value -The *Reset to default value* type will change the value of the chosen field to its Default Value. +Use this action to set a form field to a literal value or binding. - +You can also reset a field to its default value. -## Scroll To Field +## Scroll to field -This action lets you scroll to any form field on the page. Attach it to components with on change, on click, or even on load buttons throughout your application. +Use this action to scroll a form field into view. -To set it up, select the form containing your item and choose the field to scroll to when the action occurs. In the example below, a form component is linked to a button click event, causing it to scroll to the specified form field. +This is useful for validation errors or long forms. - +## Validate form -## Validate Form +Use this action to validate a selected form. -Allows you to validate any form that you've selected from a list of available forms. +If validation fails, the form shows the relevant errors. - +## Change form step -More on [Form validation](https://docs.budibase.com/docs/form-validation). +Use this action with multi-step forms to move between steps. -## Change Form Step +Available step targets include: -This along with the [Form step](doc:form-steps#design) component can allow you to break up larger forms into steps, it provides you with the option to enhance a users experience if you so choose. +* Next step +* Previous step +* First step +* Specific step -This action lets you select the form you wish to change the current step of. It provides a few different options. +## Clear form -![](https://files.readme.io/fa04603-Screenshot_2023-05-19_at_13.21.14.png) +Use this action to clear the values from a selected form. -1. `Next step` this simply increments the step of the form by 1. -2. `Previous step` this will decrease the form step by 1. -3. `First step` this sets the form step to the initial step. -4. `Specific step` this adds a new option when selected, which allows you to type in a number that you want the step changed to.\ - ![](https://files.readme.io/8cc0bd4-Screenshot_2023-05-19_at_13.23.02.png) - -## Clear Form - -This clears whatever form's field values you've assigned to it, used here in conjunction with a "Prompt User" action. - - - -To view this quickly you can add a [Form block](doc:form-block) component eject the block and click the button component contained within. Afterwards, click the `Define actions` button on the far right of the screen within the settings area. From here you can see a list of pre generated actions one being the clear form action, clicking into this you will be able to see how its setup. Its extremely simple all thats required is selecting the form you wish to perform this action on. - - +This is commonly used after a submit or confirmation prompt. ## On change -Form fields have the ability to trigger an action *on change* of their value. - -Specifically, [Pickers](doc:pickers) will update on selection, whereas [Text input](https://docs.budibase.com/docs/text-inputs) fields will update on loss of focus. +Form fields can trigger actions when their value changes. - +Picker fields update when the selection changes. Text inputs update when focus leaves the field. -In addition, there is a convenient Binding `{{ Field Value }}` which represents the value of the trigger form field. \ No newline at end of file +Use the `{{ Field Value }}` binding to read the value that triggered the action. diff --git a/docs/Apps/actions/index.md b/docs/Apps/actions/index.md index 991b14b14..74f75ad89 100644 --- a/docs/Apps/actions/index.md +++ b/docs/Apps/actions/index.md @@ -10,20 +10,11 @@ metadata: next: description: '' --- -Budibase actions fall into four groups: data, application, form, and logic. +Budibase actions are grouped into data, application, form, and logic actions. -## Data actions +## Action groups -As the title implies, these actions revolve around data. They involve tasks like retrieving data from different sources (like REST APIs or external databases), refreshing data sources, or making changes to data (such as updating rows in a database). You can view this [here.](doc:data-actions) - -## Application actions - -These actions can happen at any time in your application. They include displaying notifications, opening side panels or pop-up windows, logging out users, and starting automations. See [Application actions](doc:application-actions). - -## Form actions - -Form actions manipulate different parts of a form. The main actions are `Update Field Value`, `Validate Form`, `Change Form Step`, and `Clear Form`. See [Form actions](doc:form-actions). - -## Logic actions - -Currently there is only one logic action: [Continue If / Stop if](https://docs.budibase.com/docs/chaining-actions#continue-if--stop-if). +* [Data actions](doc:data-actions) +* [Application actions](doc:application-actions) +* [Form actions](doc:form-actions) +* [Logic actions](doc:logic-actions) diff --git a/docs/Apps/app-scripts.md b/docs/Apps/app-scripts.md index 3dcbdfbe3..7d40872de 100644 --- a/docs/Apps/app-scripts.md +++ b/docs/Apps/app-scripts.md @@ -14,109 +14,44 @@ next: slug: custom-css title: Custom CSS --- -These scripts are injected into your app's server-side rendered HTML skeleton and take effect immediately. This allows them to override or manipulate any part of your app. +Use app scripts to add custom scripts, styles, and external references to your app. -## Unlocking app scripts +These scripts are injected into the app shell and apply across the app. -You must upgrade to an enterprise plan to unlock app script functionality. For more information, contact our [sales team here](https://budibase.com/contact/). +## Unlock app scripts -## Setup +App scripts require an enterprise plan. -You can configure app scripts in your app settings under a page titled "App Scripts." +## Add a script - +1. Open app settings +2. Go to `App Scripts` +3. Select `Add script` +4. Enter a name +5. Choose whether the script loads in the head or body +6. Add the HTML, script, or style content +7. Save the script -You can add a new script by clicking the "Add script" button in the top right of the table. The configuration of each script is broken down into 3 key elements; +## Script content -* The Name field is a descriptive title of what your script does -* The Location field is a options picker that will control whether this script is added to the head of the page or the body -* The HTML field is where you can add the content to the head or body of your app. You can include: - * JavaScript scripts - * CSS styles - * External style sheets - * Additional JavaScript references +You can add: -You can save your app script configurations once you've filled out the fields. +* JavaScript +* CSS +* External stylesheets +* External JavaScript references -To view your saved scripts, return to the "App Scripts" page. Click a row to open the form with pre-filled information. You can then save, cancel, or delete the script as needed. +## Use CSP whitelist domains - +Use the CSP whitelist when your scripts need to fetch resources from other domains at runtime. -## Domain Whitelisting for Content Security Policy (CSP) +You do not need to whitelist domains for scripts that are already loaded through App Scripts. -You can now specify external domains to be added to your app's [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP), enabling safe access to external resources or APIs. +## Common use cases -This configuration is available under the "App Scripts" page in a new section titled "CSP Whitelist Domains." +App scripts are commonly used for: -### Why is this needed? - -Browsers use CSP to control which resources a page can load. By default, only safe resources from your app’s domain are allowed. If your scripts fetch data or load additional resources from external domains, CSP may block them unless those domains are explicitly allowed. - -### When do I need to use this? - -You **only** need to add a domain to the CSP whitelist if: - -* A script or style you've added fetches additional resources (e.g., images, styles, JS) from other domains at runtime -* Your script makes AJAX/fetch requests to a different domain (e.g., calling an external API) - -You **do not need** to whitelist a domain if: - -* You're just loading an external script via the App Scripts feature. These scripts are automatically secured with a nonce. -* You're using self-hosted Budibase with CSP disabled. In that case, all domains are already allowed. - -### How to add domains - -On the “App Scripts” page: - -1. Scroll to the CSP whitelist section - - -2. Add one or more domains (e.g., [https://api.example.com](https://api.example.com)) -3. Save your changes - -Domains added here will be included in the default-src directive of your app’s CSP, allowing access to most types of external resources. - -## Examples - -### Changing font to inter - -* Add the relevant style sheets -* Then override the font with the below inline styling - -```Text HTML - - - - - -``` - - - -### Adding a chatbot - -This requires two scripts, - -* A script in the head that will link to the chatbot's JS file. - - ```Text HTML -