diff --git a/docs/AI/agent-building-101.md b/docs/AI/agent-building-101.md index fd787f141..b6df8f094 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,7 +72,7 @@ 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 @@ -91,7 +89,7 @@ Agents perform tasks through **Operations**. An Agent can have one or many opera By default, Budibase provides a structured instruction template to help you define your operation clearly. More information on this can be found [here](doc:agent-instructions-guide#recommended-template). -For now we will use the below instructions: +Use the following instructions for this guide: ```markdown instructions **Operation role** @@ -123,7 +121,7 @@ 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 @@ -147,7 +145,7 @@ 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. ### Adding Knowledge @@ -172,7 +170,7 @@ For more complex configurations, you can use the **Advanced setup** option withi Once these tools and knowledge sources are enabled, we need to guide the Agent on when to use them. -Here is our updated instruction prompt: +Use the following updated instruction prompt: ```markdown instructions **Operation role** @@ -226,7 +224,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: diff --git a/docs/Apps/actions/application-actions.md b/docs/Apps/actions/application-actions.md index 671405d6e..6029f525d 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,62 @@ next: slug: form-actions title: Form actions --- -## Navigate To +Use application actions when a user interaction should change screens, open UI, show feedback, or trigger automation. -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) +## Navigate To -When the *Destination* is set to 'URL', you have the option to open the link in a new tab. +Use this action to open a URL or another screen. -![](https://files.readme.io/8f018e8-new_tab.png) +If the destination is a URL, you can open it in a new tab. -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). +If the destination is a screen, you can open it in the current tab or in a modal. You can learn more about using URL parameters with the `Navigate To` action [here](https://docs.budibase.com/docs/url-parameters). -![](https://files.readme.io/a455654-open_modal.png) - -## Trigger Automations +## Trigger automations -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. +Use this action to run an existing automation. - +Pass values into the automation with fields on the action. -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`. - - +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 +Use this action to sign the current user out and optionally redirect them. -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. +## Close screen modal -## Close Modal +Use this action to close the current screen modal. -This action takes no settings, and will close any modal component open on screen. +You can also navigate to another screen after closing. -## Open Modal +## Close modal -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]() +Use this action to close the currently open modal component. -## Show Notification +## Open modal -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.` +Use this action to open a modal component that already exists on the current screen. - +## Show notification -### Logic within notifications +Use this action to show a success, warning, error, or info message. -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. +You can include bindings in the message text. -## Prompt User +It is also 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. -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/chaining-actions.md b/docs/Apps/actions/chaining-actions.md index bdc1fb278..b990b2aed 100644 --- a/docs/Apps/actions/chaining-actions.md +++ b/docs/Apps/actions/chaining-actions.md @@ -10,195 +10,44 @@ 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 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 new action 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 the following additional information: - -* 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. - -### 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 - -#### Schema - -* Bookings -* Leaders -* One Booking -> One Leader - -*** - -#### 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" +Execute query actions also expose: - -8. Repeat the previous step until your form has all of the following +* Status code - `{{ Action 1.Query result.code }}` +* Response time - `{{ Action 1.Query result.time }}` +* Payload size - `{{ Action 1.Query result.size }}` -| 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 | +You can use these values in conditions or display them in the UI. -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. +## Common pattern - +Use chained actions when you need to: -
-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. +* Validate a form +* Save a row +* Reuse the saved row ID in another action +* Clear the form or navigate after the save completes - -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 +## Related pages -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 +* [Form actions](doc:form-actions) +* [Data actions](doc:data-actions) +* [Conditional UI](doc:conditions) 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/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 b37ca8714..74f75ad89 100644 --- a/docs/Apps/actions/index.md +++ b/docs/Apps/actions/index.md @@ -10,30 +10,11 @@ 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 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 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) - -## 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). - -## 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 - -{` - -`} +* [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 - -`} \ No newline at end of file +NB: Custom Roles must be referenced by their ID, not their name. diff --git a/docs/Apps/custom-css.md b/docs/Apps/custom-css.md index 0883e687e..b2465bbdd 100644 --- a/docs/Apps/custom-css.md +++ b/docs/Apps/custom-css.md @@ -10,58 +10,31 @@ metadata: next: description: '' --- -All [Components](doc:components), including [Screens](doc:screens), have the option to add custom css. +Use custom CSS when you need to override the default styling of a component. -To do so, click on a component, and in the Settings Panel click on the *Styles* tab. Finally click on the *Edit custom CSS* button +## Add custom CSS to a component -![](https://files.readme.io/ea72d9a-Screenshot_2023-07-04_at_14.17.18.png) +1. Select the component +2. Open the `Styles` tab in the settings panel +3. Select `Edit custom CSS` +4. Enter inline CSS for the component -This will present a box in which you can enter CSS for the selected component.\ -For example: +Custom CSS here applies only to that component. -![](https://files.readme.io/82dd3a4-Screenshot_2023-07-04_at_14.21.30.png) +Selectors are not supported in this field. -> 🚧 Inline CSS -> -> Selectors cannot be used here, and you must enter inline CSS. +## Apply global styles -## Global styling +Use an [Embed](doc:embed) component when you need page-wide CSS selectors. -If you are determined to apply your own style to the entire screen, you can achieve this through an [Embed](doc:embed) component. +Add a ` -`} +Use synchronous automations when the caller needs data from the automation run. -Synchronous automations allow users to receive feedback from their automation, in the Design section or via 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. A synchronous automation returns data to the caller. > 📘 Licensing🔒 > -> The following features are available to: -> -> * **All installations** with a Premium or Enterprise license - -
- -## Creating a Synchronous Automation - -You can make an automation synchronous by adding a **Collect Data** step. - - - -A **Collect** step will simply return whatever binding or value is passed to 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). - -> 📘 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: -> -> - -
- -## Webhook - -When using 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: - -![](https://files.readme.io/3ca2a7a2d1761fa3b65d63ee7582ec98ba3a1556fe7f50015b371140a21b1230-image.png) - -![](https://files.readme.io/a4e4ece382d3fb981ba94430276c28fb45e7ae4526f2b7173a448de896c256ca-image.png) +> This feature is available on Premium and Enterprise plans. -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. +## Create a synchronous automation - +Add a `Collect Data` step to make an automation synchronous. -After publishing this automation, we can see the result in our POST request: +The `Collect Data` step returns the binding or value passed into it. -![](https://files.readme.io/65975b456d3b96f5cdf20fc35633eacb4edabb31412730ae1e7e9a092e50c7de-image.png) +The step must be the last step in the automation. -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.** +## Webhook use case -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. +Use a [Webhook](doc:webhook) trigger when an external service needs to call the automation and receive data back. -Making sure an array is returned - Making sure an array is returned - +The response can include the value returned by the `Collect Data` step. -And now the result: +If you need a number or array, use a JavaScript binding instead of a Handlebars value. -![](https://files.readme.io/4cab3fff50069a5acc354af46da7e301b12494862164440ea68dc90ac867740d-image.png) +## On demand use case -
+Use an [On demand](doc:app-action) trigger when a screen action needs to receive the automation result. -## On demand +Typical flow: -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. +1. Trigger the automation from a button +2. Store the result in app state +3. Bind the state value to a component -![](https://files.readme.io/210e91308bf6e0799e5f5c7b1d8a67f84ada077a4b5182e095777b26c8b44bba-image.png) +## Notes -Filter attached to the query rows step - 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. - -![](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. - -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). - -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. - -![](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. - -To display this we now simply to need bind the state to the Text component. - - - -We can now preview our app and click the [Button](doc:button) for which our actions are defined. - -![](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. - -Instead of displaying the result in a component, you could just as easily use the **Show Notification** action, or any other combination of actions. - -> 📘 Automation Result -> -> The automation result binding will only be available if your automation has a **Collect Data** step. \ No newline at end of file +* Synchronous automations can run for up to 120 seconds +* The automation result binding is only available when the automation includes `Collect Data` +* Use chaining actions to pass the result into later steps 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/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/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/index.md b/docs/Automation/trigger/index.md index 1d2b2e663..b7bf35d88 100644 --- a/docs/Automation/trigger/index.md +++ b/docs/Automation/trigger/index.md @@ -1,6 +1,6 @@ --- title: Triggers -excerpt: '' +excerpt: Start automations from events deprecated: false hidden: false metadata: @@ -10,24 +10,44 @@ 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 trigger. - +The trigger listens for an event and 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 types: -> 📘 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 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 respond to rows created, updated, or deleted through Budibase. + +Changes made directly in an external datasource do not fire Budibase row triggers. + +## Webhook triggers + +Use a webhook trigger when another application needs to start a Budibase automation. + +Use this 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 action, cron, or email triggers only when they fit the workflow + +If Budibase does not provide the trigger type you need, use a webhook-based integration. 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. 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/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/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/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/_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/budibasedb/attachments.md b/docs/Data/budibasedb/attachments.md index 3d4789eec..0dbc939d0 100644 --- a/docs/Data/budibasedb/attachments.md +++ b/docs/Data/budibasedb/attachments.md @@ -1,119 +1,49 @@ --- title: Attachments -excerpt: Learn more about how Budibase manages static files. +excerpt: Store uploaded files in Budibase DB deprecated: false hidden: false metadata: title: '' - description: kba_5hf5u + description: '' robots: index next: description: '' --- -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. - -### 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: - -## 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. - -### 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. - -### Attachment List - -Here, you can include multiple attachments of different types, such as CSV files, images, Word documents, and more. - -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. - -## 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. - -> 📘 -> -> 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. - -Your attachments will be displayed like any regular field - inside grids and tables, forms and more Budibase 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). - -## 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. - -### Creating the Countries table and columns - -Let's begin by creating a table to store data for our countries. - -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. - -* **Country Name**: Country names are just letters, so a [Text](doc:text) type is a good fit here. -* **Country Population**: We should use a [Number](doc:number) type for this. -* **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. - -{` - -`} - -## 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. - -Here are the files used in the video below 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! +Use an attachment column when a row needs to store uploaded files. -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: +Budibase supports: -![](https://files.readme.io/2aeb51f-countries.png "countries.png") +* Single attachments +* Attachment lists -*** +## Create an attachment column -## Manage access +1. Open the table +2. Click `Create column` +3. Choose `Attachment` or `Attachment List` +4. Save the column -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. +## Supported files -To fix this, click on the `Manage access` button. +Attachment columns can store common file types, including: -![](https://files.readme.io/520af17-Screenshot_2022-09-23_at_10.36.08.png) +* Images +* PDFs +* CSV files +* Word documents +* Audio files -Set the write access to **public** +The maximum file size is 20 MB per file. -![](https://files.readme.io/2cdaa92-Screenshot_2022-09-23_at_10.36.59.png) +## Use attachments in forms -**Note** this will allow anyone to upload a file to your app instance, so use with caution! +When a form targets the table that owns the attachment column, Budibase shows an upload control for that field. -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. +Use the matching table as the form schema so Budibase knows where to store the uploaded file. -> 👍 -> -> ![](https://files.readme.io/a2430f9-Screenshot_2022-09-23_at_11.10.13.png) +## Notes -> ❗ -> -> ![](https://files.readme.io/c4b0208-Screenshot_2022-09-23_at_11.10.35.png) \ No newline at end of file +* Attachments are stored in MinIO +* Public uploads require the table write access to allow the upload +* If the form schema does not match the target table, the upload cannot be saved diff --git a/docs/Data/budibasedb/barcodeqr.md b/docs/Data/budibasedb/barcodeqr.md index 4b03d5880..dde84e331 100644 --- a/docs/Data/budibasedb/barcodeqr.md +++ b/docs/Data/budibasedb/barcodeqr.md @@ -1,40 +1,38 @@ --- title: Barcode/QR -excerpt: This topic describes the barcode/qr data types, supported in Budibase +excerpt: Store barcode or QR values in Budibase DB deprecated: false hidden: false metadata: title: '' - description: kba_5ifb6 + description: '' robots: index next: description: '' --- -Barcodes and QR codes come in a huge range of formats, from simple product numbers to complex text patterns and URLs. - -To accommodate the wide variety of content the field can handle, the Barcode/QR column type is stored as text, or a string. - -Fields configured as Barcode/QR types in the database will appear as [Barcode/QR components](https://docs.budibase.com/docs/barcodeqr-field) in the builder. +Use a Barcode/QR column when a field should store text that is displayed as a barcode or QR code. -## Creating a Barcode/QR column +## Create a Barcode/QR column -The process for creating the column only takes a few seconds. +1. Open the table +2. Click `Create column` +3. Set the type to `Barcode/QR` +4. Save the column -1. First, navigate to your Datasource and click the `+` button along the top-right -2. Give the column a Name, e.g "ProductCode" -3. Select **Barcode/QR** from the **Type** -4. Click **Save Column** +## Use Barcode/QR columns -![](https://files.readme.io/59ea977-qr_column.png) +Barcode/QR columns are stored as text, so they can hold values such as: -## Convertible types +* Product codes +* URLs +* Reference strings -In Budibase, depending on the field type, you can update the type of a column to another +In the builder, these columns appear as Barcode/QR components. -In this instance, a Barcode/QR can be updated to any of the following and vice versa. +## Convert the column -* [Text](doc:text) -* [Options](https://docs.budibase.com/docs/text#options) -* [Long Form Text](https://docs.budibase.com/docs/text#long-form-text) +You can convert a Barcode/QR column to or from related text types such as: -This can be handy when you've been manually entering QR code and Barcode data for years as `Text` and you finally switch the field type to Barcode/QR! \ No newline at end of file +* Text +* Options +* Long Form Text diff --git a/docs/Data/budibasedb/boolean-truefalse.md b/docs/Data/budibasedb/boolean-truefalse.md index cba9c682d..c74bb5090 100644 --- a/docs/Data/budibasedb/boolean-truefalse.md +++ b/docs/Data/budibasedb/boolean-truefalse.md @@ -1,6 +1,6 @@ --- title: Boolean (True/False) -excerpt: '' +excerpt: Store yes/no values in Budibase DB deprecated: false hidden: false metadata: @@ -10,15 +10,22 @@ metadata: next: description: '' --- -True/False is a data type that has one of two possible values (usually denoted as true/false, yes/no, Boolean). Within your UI, this is usually displayed in the form of a checkbox. +Use a boolean column for values that only have two states, such as yes/no or true/false. -## Creating a Boolean column +## Create a boolean column -1. First, click the `+` button along the top-right -2. Give your column a name -3. Choose 'Boolean' as your data type -4. Click `Save Column` +1. Open the table +2. Click `Create column` +3. Enter a column name +4. Set the type to `Boolean` +5. Save the column -## Using the boolean data type +## Use boolean columns -In the Design section, you can pull in information from your true/false column, using the [Repeater](doc:repeater) component and [bindings](doc:introduction-to-bindings) +Boolean columns are commonly shown as: + +* Checkboxes +* Toggles +* Conditional display rules + +Use them when a value should only be on or off. diff --git a/docs/Data/budibasedb/datetime.md b/docs/Data/budibasedb/datetime.md index 7afee62e7..47f14f920 100644 --- a/docs/Data/budibasedb/datetime.md +++ b/docs/Data/budibasedb/datetime.md @@ -1,91 +1,50 @@ --- title: Date/Time -excerpt: '' +excerpt: Store date and time values in Budibase DB deprecated: false hidden: false metadata: title: '' - description: kba_5ifeq + description: '' robots: index next: description: '' --- -The date/time data type is important when using components or displaying information that relies on dates and times. - -The [Date picker](https://docs.budibase.com/docs/date-picker) component, for example, can utilize the date field. Dates within Budibase comply with ISO 8601 formatting, e.g. `2023-04-24T13:12:04.622Z`. Thankfully, the date picker makes data entry easier. - -## Creating a Date/Time column - -1. First, click the `+` button along the top-right -2. Give your column a name -3. Choose date/time as your data type -4. Enter some optional constraints -5. Click `Save Column` - -![](https://files.readme.io/1da53ba-Screenshot_2022-08-31_at_12.39.57.png) - -## Constraints - -You can provide an **earliest** and **latest** date within your date/time column. This allows you to enforce a constraint such that dates added must fall *before the latest* and *after the earliest* dates specified. - -As with all other fields you can make it **required**. - -These constraints can easily be edited after creation by hovering over the date field and clicking the three dots icon. - -### Ignore time zones - -When this option is checked, the values selected in date pickers will be saved exactly as they are represented into the target database. Regardless of the timezone the browser is in, you will always see the same exact timestamp when this option is selected. - -As an example, here is a snippet of a table where the browsers locale was changed to 3 different timezones and the time 12:00 was picked in each. You can see that the column "BB no timezone" (which has *Ignore time zones* enabled) will always show the same time, whereas the "BB normal" column (where the flag is toggled off) reflects the browser timezone changes. - -![](https://files.readme.io/1efd0f2-Screenshot_2022-08-31_at_13.03.11.png) - -It is possible, but not recommended, to change the *Ignore time zones* flag on tables that already have dates with timezones. Changing this flag does not change existing data, but it will change how your existing data is presented in the browser. - -By default this setting is toggled off. - -> 📘 -> -> This setting is also available for PostgreSQL and MySQL tables. - -## Working with dates - -As mentioned above, dates in Budibase are given as standard ISO 8601 date/time strings. You can make use of bindings to transform that date string into whatever you need to display. - -### Tutorial: Calculating the duration of an event - -Say we have a table *Events* with two date columns: *Start Time* and *End Time*. To calculate the duration of each event, we can create a Formula column and then use Bindings to calculate the difference between the two dates. - -It's not possible to perform mathematical operations on a date string, so the first step is to convert the date into milliseconds. The value is a count of how many milliseconds the date is before or after [the UNIX epoch in 1970](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#the_epoch_timestamps_and_invalid_date). We can do this using the **date helper** where bindings are available. The date helper takes the date value, the desired output format and an optional timezone as arguments. - -To format *Start Time* in milliseconds using the date helper, pass the Start Time value and 'x' as the date format. You can see the other available output formats in the [Day.js format documentation,](https://day.js.org/docs/en/display/format) which is what the date helper uses behind the scenes. Our Handlebars expression is `{{ date Start Time 'x' }}` and the output is **1685100000000**. +Use a date/time column when a field needs to store timestamps or dates. -The next step is to do the same for *End Time* and then using the **subtract helper**, subtract the ms value for *Start Time* from it. This will return the length of the event in milliseconds. Here's how it looks with the helpers chained up: +Budibase stores date/time values in ISO 8601 format. -`{{ subtract (date End Time 'x' ) ( date Start Time 'x' ) }}` +## Create a date/time column -Now we have the duration of the event in milliseconds, the final step is to convert this value into something more useful. We can use the **duration helper** which takes our time value and the unit to calculate a human readable duration. By default this helper uses the [Day.js Humanize Duration function.](https://day.js.org/docs/en/durations/humanize) +1. Open the table +2. Click `Create column` +3. Set the type to `Date/time` +4. Add any constraints you need +5. Save the column -Here's the final binding and the result: +## Common constraints -`{{ duration (subtract (date End Time 'x' ) ( date Start Time 'x' )) "milliseconds" }}` +Use constraints to limit the values users can save: -![](https://files.readme.io/0b7e610-image.png) +* Required +* Earliest date +* Latest date -Of course, you can also use JavaScript bindings for more complex time calculations. All of the helpers that make use of Day.js are also available there. +## Ignore time zones -### Tutorial: Calculating the time until an event +Use `Ignore time zones` when you want Budibase to save the selected value exactly as entered. -The same principle can be used for calculating the time since a past date or the time until a future date. In this case you would only use one date value and compare it to the current time instead of another date. To get the current time in milliseconds, use `{{ date now 'x' }}` +Leave it off when you want the browser timezone to affect the stored timestamp. -In all cases, subtract the earliest date from the latest date. For working out how long ago past events were, I used this binding: +## Use date/time values -`{{ duration (subtract (date now 'x' )( date Start Time 'x' )) "milliseconds" }} ago` +Date/time columns work well with: - +* Date picker components +* Bindings that format dates +* Formula columns that calculate durations or date differences -### Further reading +## Notes -* [Bindings Tutorial: Calculate age from Date of Birth field](https://docs.budibase.com/docs/form-bindings#tutorial-calculate-age-from-dob-field) -* [Handlebars Bindings: The date helper and chaining helpers ](https://docs.budibase.com/docs/bindings) -* [JavaScript Bindings: Using a date column](https://docs.budibase.com/docs/javascript#using-a-date-column) \ No newline at end of file +* The setting is also available for PostgreSQL and MySQL tables +* Changing `Ignore time zones` does not rewrite existing data diff --git a/docs/Data/budibasedb/index.md b/docs/Data/budibasedb/index.md index b2f2a2640..d9d56d99a 100644 --- a/docs/Data/budibasedb/index.md +++ b/docs/Data/budibasedb/index.md @@ -1,6 +1,6 @@ --- title: Budibase DB -excerpt: '' +excerpt: Use Budibase DB for native app data deprecated: false hidden: false metadata: @@ -10,153 +10,89 @@ metadata: next: description: '' --- -Budibase DB is our native datasource. Any data you add here is stored directly on your Budibase instance and can be used by any apps or automations within your Workspace. +Budibase DB is the native datasource for your workspace. -## Creating a table +Use it when you want data stored directly in Budibase and shared across apps and automations in the same workspace. -You can create a table when you are in the **Data** section of the workspace. +## Create a table -Click `Add source` and then click the `Create new table` button. +1. Open the **Data** section +2. Click `Add source` +3. Choose `Create new table` +4. Enter a table name +5. Save the table -{260} - Create a new table using this button - +## Add columns -All auto columns selected by default - Creating a new Budibase DB table - +Add columns from the table grid. -### Adding columns +1. Open the table +2. Click the `+` button +3. Choose the column type +4. Set the column name and options +5. Save the column -To add new columns to an existing Budibase DB table, navigate to the table you want to edit, then click the `+` button along the top-right of the grid view. This will display a popover where you can configure the column you want to add. +## Choose a display column -Adding a required text column - Adding a long form 'Address' field - +The display column is the value shown in relationship fields and other linked views. -### Editing columns +Set a display column when you want records to appear by name instead of ID. -1. Step into the table through the sidebar -2. Hover over the column name you want to edit -3. Click the three dots and select *Edit column* +## Use auto columns -Click the pencil icon to edit column - Click the pencil icon to edit column - +Budibase DB supports system-managed auto columns such as: -### Selecting the display column +* `Auto ID` +* `Updated By` +* `Updated At` -The display column is an important aspect when you're setting up relationships in tables. The column you select as a display column will be the one visually displayed inside a relationship column in another table. - -Selecting a column during the table creation is only possible if you import data using a `CSV` file. To select a display column in any other situation, you can set it from the edit column dropdown. - -Use as display column - Use as display column - - -### Auto-columns - -Budibase DB supports system-managed auto columns that populate themselves when rows are created or updated. - -When adding a column, select *Auto column*, then choose the subtype offered in the picker. - -Selecting the 'Auto Column' data type - Selecting the 'Auto Column' data type - - -The current builder exposes `Auto ID`, `Updated By`, and `Updated At` in the add-column picker. `Created By` and `Created At` are still supported by the data model and may appear in existing tables or generated schemas, but they are not currently shown as add-column options in the UI. - -| Name | Description | UI availability | -| :---------- | :------------------------------------------------------- | :------------------------------------------- | -| Auto ID | An automatically generated numeric ID | Available in the picker | -| Updated By | The user who updated the row last | Available in the picker | -| Updated At | The time when the row was updated last | Available in the picker | - -> 👍 Create table from CSV -> -> You can [Import a CSV/JSON](doc:csv-import) file as a new Budibase table. - -*** +Use these when you need values generated by Budibase instead of entered by a user. ## Data types -Within Budibase DB there are several data types to choose. - -| Name | Description | -| :-------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | -| [Text](doc:text) | Storage of (relatively) short text | -| Long Form Text | Allows you to store large amounts of texts, also supports markdown | -| Options | Predefined list of options of which one can be selected | -| [Multi-select](doc:multi-select) | Predefined list of options of which multiple can be selected | -| [Number](doc:number) | Storage of number | -| [Boolean (True/False)](doc:boolean-truefalse) | Storage of true/false | -| [Date/time](doc:datetime) | Storage of a date with a time | -| [Attachments](doc:attachments) | Storage of a file. Limited to 20MB per file | -| [Relationships](doc:relationships) | Creates a link between this table and another table | -| [Formula](doc:formula) | Allows you to set a formulated column, which will be calculated based on what you define. You can use handlebars or JavaScript | -| [JSON](doc:json) | Allows you to store JSON within a row, with the option to define a schema | -| [Barcode/QR](doc:barcodeqr) | A text representation of a barcode or QR code | -| Auto Column | Auto columns are system-managed columns. Add them after table creation by selecting `Auto column`. | - -If using an external [SQL Datasource](doc:sql-datasource), the native SQL data types will be mapped to one of these Budibase types for use in your workspace. For more detail, look [here](https://github.com/Budibase/budibase/blob/178fd100af09ac1bc8b8395db52c629c572dc4bb/packages/server/src/integrations/utils.ts) for how the mappings are handled. - -## Column definitions - -Common column options: - -| Property Name | Description | -| :-------------------------- | :------------------------------------------------------------------------------------------------------------------------ | -| Name | The name of the column, used for querying and displaying | -| Type | The type of data you want to store. | -| Use as table display column | Enabling this will make the newly created column the display column. This will also automatically make the field required | -| Primary index | Enabling this allows you to search in this field | -| Secondary index | When primary index is in use, you can enable a second index for searching | - -
- -| Property Name | Description | Data Types | -| :------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------- | -| Enable Rich Text Format Support | Enabling this will allow you to store markdown | Long Form Text | -| Options | The select-able options available for this column, one per line. | Options, Multi-select | -| Table | Allow a relationship to the specified table | Relationship | -| Column name in other table | The relationship created will also be visible in the related table, this will set the new column name on the related table | Relationship | -| Formula | Allows you to set a formulated column, which will be calculated based on what you define. Allows you to define handlebars and JavaScript | Formula | +Common Budibase DB column types include: + +* Text +* Long Form Text +* Options +* Multi-select +* Number +* Boolean +* Date/time +* Attachments +* Relationships +* Formula +* JSON +* Barcode/QR ## Constraints -The following column constraints are available: - -| Constraint Name | Description | Data Types | -| :-------------- | :----------------------------------------------------------------------------------- | :--------- | -| Required | When enabled, a value must be set for this field | All | -| Maximum Length | The maximum length that can be stored in this column | Text | -| Min Value | When set, any value entered in the database lower than this number will be rejected | Number | -| Max Value | When set, any value entered in the database higher than this number will be rejected | Number | -| Earliest | When set, any date before the specified date is rejected for new rows | Date/Time | -| Latest | When set, any date after the specified date is rejected for new rows | Date/Time | +Use constraints to validate values in Budibase DB tables. -> 📘 External datasource constraints -> -> You can add Budibase constraints to external table columns, however this is entirely for form validation and will not restrict the data that is saved.\ -> Instead, you must add data constraints yourself to any external table schemas. +Common constraints include: -*** +* Required +* Maximum length +* Minimum value +* Maximum value +* Earliest date +* Latest date -## Data sync between environments +Constraints on external tables are used for form validation only. -When using the Budibase DB, there are two environments to consider. +## Development and production data -The **Development** environment represents the data that you see and interact with when using the app builder, which includes the *Data* and *Design* sections, and the [App preview](https://docs.budibase.com/docs/quickstart#preview-and-publish). +Budibase DB keeps separate development and production data. -If in doubt, you can see if you are in the dev environment from the URL, which will show `/app/app_dev_abc...` in the path. In production, the URL will appear without the `_dev` part. +* Development data is what you see in the builder +* Production data is what your app users see -**Production** represents your live environment. This is the data that your End Users will interact with. When in the app builder, production data will continuously sync and update your development data, although a page refresh may be needed to see the new changes. +When you publish an app, development changes are pushed to production. -Whenever you [Publish](https://docs.budibase.com/docs/quickstart#preview-and-publish) your app, any edits, inserts or deletes made in your dev data will be pushed into production, which may overwrite existing data. +## Related pages -> 📘 External datasources -> -> Things are a little different when using an external database such as [SQL](doc:sql-datasource).\ -> In this case the data in either environment will read and write to the database that you connected to. -> -> You can use [Environment variables 🔒](doc:environment-variables) to make use of development and production databases. +* [CSV Import](doc:csv-import) +* [Text](doc:text) +* [Number](doc:number) +* [Boolean (True/False)](doc:boolean-truefalse) +* [Options](doc:options) diff --git a/docs/Data/budibasedb/json.md b/docs/Data/budibasedb/json.md index 243c1a6a2..3477aaf97 100644 --- a/docs/Data/budibasedb/json.md +++ b/docs/Data/budibasedb/json.md @@ -1,223 +1,50 @@ --- title: JSON -excerpt: '' +excerpt: Store structured JSON data in Budibase DB deprecated: false hidden: false metadata: title: '' - description: kba_5hf9e + description: '' robots: index next: description: '' --- -The JSON data type is available for internal tables. JSON fields have a schema, which can be configured when creating or editing the column. Having the correct schema is important as the builder uses this to know what bindings are available and what form fields are available. Extra data that is not in the schema can be stored, but no bindings will exist for it. - -The JSON field schema can be edited with either a form or by providing an example JSON payload. If you are using deep JSON structures (e.g. multiple levels of objects or arrays) then you will need to use the JSON schema editor, as the form editor only goes one level deep. - -Schema editor button when creating or editing a JSON column: - -![](https://files.readme.io/1ef75ae-145810969-46b3262f-03b1-4750-b490-fb51ba48538a_1.png "145810969-46b3262f-03b1-4750-b490-fb51ba48538a (1).png") - -## Editing JSON (Form) - -Using the JSON form editor, you can update your JSON without having to write JSON. - -![](https://files.readme.io/c1fee5f-145811398-fccb00cf-ae4d-4758-b777-19ea98f93e7d_1.png "145811398-fccb00cf-ae4d-4758-b777-19ea98f93e7d (1).png") - -## Editing JSON (raw) - -Using the JSON schema editor, you can write and edit raw JSON. - -![](https://files.readme.io/d019a49-145811736-9ad06ea6-15c7-4a06-b3a3-936927e09720_1.png "145811736-9ad06ea6-15c7-4a06-b3a3-936927e09720 (1).png") - -## Displaying data within a JSON column - -JSON field schema is merged with table schema in client apps, and basically treated as new top level columns. This means you can filter on nested values, or display them inside tables, as if they were normal fields in your table. Here's an example of a table showing all columns inside the table containing the JSON field above: - -![](https://files.readme.io/27347e2-145813246-1ed77cd1-4613-4ee8-8f85-a1b1d8a39da5_1.png "145813246-1ed77cd1-4613-4ee8-8f85-a1b1d8a39da5 (1).png") - -## Displaying JSON arrays - -In that screenshot, you can see that it has pulled out fields from within the JSON field and displayed them automatically. It also is showing the JSON fields as a whole (as it shows all columns by default) - but you can easily control what gets displayed by using the table setting: +Use a JSON column when a row needs to store structured data with nested fields or arrays. -![](https://files.readme.io/e4d3026-145813415-de271d75-99e2-47f5-964c-d71e33476225_1.png "145813415-de271d75-99e2-47f5-964c-d71e33476225 (1).png") +JSON columns include a schema so Budibase can expose the available bindings and form fields. -*** +## Create a JSON column -## Filtering +1. Open the table +2. Click `Create column` +3. Set the type to `JSON` +4. Define the schema +5. Save the column -You can filter using fields inside your JSON. Here's an example of filtering using the nested value Car.Make: +Use the form editor for simple structures. Use the raw JSON schema editor when you need nested objects or arrays. -![](https://files.readme.io/665a9f1-145813879-c03d502f-29e7-4a38-84f6-da03bc950d85_1.png "145813879-c03d502f-29e7-4a38-84f6-da03bc950d85 (1).png") +## Use JSON columns -*** +Budibase treats schema fields as normal top-level fields in tables, forms, filters, and bindings. -## Data bindings +That means you can: -Data bindings will be automatically generated for all available fields inside your JSON, including nested fields (e.g. *Car.Make*). Data bindings will be generated until an array is hit, at which point no further bindings can be generated. You can read about how arrays are handled down below. Bindings are also provided for the JSON field as a whole and any array fields, both of which integrate very nicely with JS bindings. - -Here's an example of all the data bindings provided for the JSON field above. My table is called **People** and my JSON column is called **Data**. - -![](https://files.readme.io/2b3ab0c-145812656-2bd83f85-524e-46bc-a83c-5dcf9d321428_1.png "145812656-2bd83f85-524e-46bc-a83c-5dcf9d321428 (1).png") - -*** +* Bind to nested values +* Filter on nested values +* Display nested fields in tables +* Save nested fields from forms ## Arrays -Arrays inside JSON fields can be used as data sources. For this example, I've added a new property called **Friends** inside my JSON field, which is an array. - -```json -"Friends": [ - { - "Name": "Bill", - "Address": { - "Number": 1, - "Street": "High Street", - "City": "New York" - } - }, - { - "Name": "Ben", - "Address": { - "Number": 18, - "Street": "Shore Road", - "City": "Carrickfergus" - } - }, - { - "Name": "Bert", - "Address": { - "Number": 249, - "Street": "Mountain Cresent", - "City": "Lima" - } - } - ] -``` - -Here's an example using a table block to display data of *Friends*. The structure is: - -* a [Data Provider](doc:data-provider) with [Repeater](doc:repeater) (to get the rows that contain the JSON fields), -* then a table block (to show the data inside the array inside the JSON field). - - - -You can see from this screenshot that the schema correctly determines all available fields inside the array objects and is listing them in the table. If you have an array of primitives (e.g. an array of numbers, or strings) then a fake schema entry **value** is generated. You can then display data inside primitive arrays using *Field.something.value*. - -You can nest arrays as deep as you like. If your JSON structure looked something like this: - -```json -{ - "countries": [{ - "name": "England", - "cities": [{ - "name": "London", - "boroughs": ["Barnet", "Brent", "Camden", "Croydon", "Harrow", "Sutton"] - }] - }] -} -``` - -Then you can use a repeater on *Column.countries*, then put a repeater block inside that and target *countries.cities*, then put another repeater block inside that and target *cities.boroughs*, to finally get out the borough values. You can chain this as long as you like and the schema will always be available. - -*** - -## JSON form field - -There is a new form field component for JSON fields. It will render a text area that pretty prints the content as JSON. It also has forced validation to ensure that the input is valid JSON. - -The new JSON field component: - -![](https://files.readme.io/1d34354-145822205-4eaf0f40-4f3f-455b-85c4-e2aa1d07373f_1.png "145822205-4eaf0f40-4f3f-455b-85c4-e2aa1d07373f (1).png") - -Validation enforcing JSON syntax: - -![](https://files.readme.io/498d8bc-145822308-9acafdf1-5af8-4165-af0e-f5b50fe1f1ba_1.png "145822308-9acafdf1-5af8-4165-af0e-f5b50fe1f1ba (1).png") - -*** - -## JSON form integration - -Since nested JSON fields are considered normal fields, you can bind a form component to a nested JSON field. In my example, I have the field *Car.Make*. If I want to update this, I can simply add a text field and bind it to *Car.Make*, then save my whole row as normal. This will transparently update the value inside the JSON field with no extra configuration. - -Binding a form component to a nested JSON field: - -![](https://files.readme.io/d539e3e-145822912-6a5b6fce-8004-4e8e-85a1-67e7087c3bd9_1.png "145822912-6a5b6fce-8004-4e8e-85a1-67e7087c3bd9 (1).png") - -When generating form components automatically (via the `Update form fields` button on [Field groups](doc:field-groups)) the builder will always insert an actual JSON field form component for the whole JSON field, rather than individual inputs for every nested property. You can always add/remove fields as you see fit if you want to be able to directly update some nested fields. - -If you have a form targeting a subsection of your JSON field, then the best way to save your full row value is to write a small [JavaScript Binding](doc:javascript) and make use of the new *Form.Value* binding (which is an object of the whole value of the form) to insert the value into your JSON field. This is only really needed when you are iterating over JSON arrays and want to update one of the array elements. - -### Example: Questionnaires - -1. Add a **Topic** table with a *Name* column and a JSON type *Questionnaires* column with the following schema: - -![](https://files.readme.io/127d302-Screenshot_2023-02-06_at_11.11.53.png) - -2. After clicking `Save Column`, insert a row for each of your topics. - - - -3. Create a [Screen](doc:screens) for the `Topic` table. Insert a [Cards block](https://docs.budibase.com/docs/blocks#cards-block). Assign the *Title* property to the topic name binding (`{{ New Cards block.Topic.Name }}`, and optionally set the *Subtitle* to display the number of questionnaires: `Questionnaires: {{ length New Cards block.Topic.Questionnaires.values }}` -4. Tick the `Link card title` setting, and provide the following URL: `/new-questionnaire/:topicId` - - - -5. Create another screen, and set the route to the link destination: - -![](https://files.readme.io/058ab59-Screenshot_2023-02-06_at_11.26.55.png) - -6. Add a [Repeater block](https://docs.budibase.com/docs/blocks#repeater-block) with a filter on the *topicId* - -![](https://files.readme.io/341fdf6-Screenshot_2023-02-06_at_11.30.02.png) - -7. Add a [Headline](https://docs.budibase.com/docs/displaying-text#headline) for the topic name, with the following binding: `Topic: {{ Topics Repeater block.Topic.Name }}`. -8. Nest a [Form](doc:forms) within the repeater block. Select the *Questionnaires* column as the schema. - -![](https://files.readme.io/c7f15d2-Screenshot_2023-02-06_at_11.34.01.png) - -9. Now you'll be able to add the form fields as defined by the JSON schema earlier. - - - -10. Finally add a submit [Button](doc:button). `Define actions` and select the **Save Row** action. Choose the repeater block as the *Datasource*, with *Topic* as the target table. Click `Add Column` so that the JSON *Questionnaires* array can be populated correctly. - -![](https://files.readme.io/ff5595d-Screenshot_2023-02-06_at_11.43.43.png) - -```javascript Questionnaires.values -return [...($("Topics Repeater block.Topic.Questionnaires.values") || []), { - title: $("Questionnaire Form.Fields.title"), - rating: $("Questionnaire Form.Fields.rating"), - comments: $("Questionnaire Form.Fields.comments") -}]; -``` - -#### Result - - - - - +JSON arrays can be used with repeaters and table blocks. - - - +When an array contains objects, Budibase exposes the object fields automatically. - - - +When an array contains primitives, Budibase exposes a `value` field. - - - -
- Q1 - - Q2 -
- - - -
+## Notes -![](https://files.readme.io/9b029a8-Screenshot_2023-02-06_at_11.50.25.png) \ No newline at end of file +* The schema controls which nested fields are available in the builder +* Fields not in the schema can still be stored, but they will not have bindings +* Use the JSON form component to validate input before saving diff --git a/docs/Data/budibasedb/multi-select.md b/docs/Data/budibasedb/multi-select.md index 6a5e9f27d..9a9393623 100644 --- a/docs/Data/budibasedb/multi-select.md +++ b/docs/Data/budibasedb/multi-select.md @@ -1,157 +1,44 @@ --- title: Multi-select -excerpt: Using the multiple options data type in Budibase +excerpt: Store multiple selected values in Budibase DB deprecated: false hidden: false metadata: title: '' - description: kba_5hfb6 + description: '' robots: index next: description: '' --- -In Budibase, there are two data types that allow a value to be set from a list of options. - -The first is the [Options](https://docs.budibase.com/docs/text#options) type, which is compatible with the *Text* data type, and only allows a single option to be chosen. - -The **Multi-select** type is similar to the options type, but it allows you to select multiple options, and is not convertible to any other type. You can still select a single option or none at all. - -A common use of the multi-select data type is to pair it with the [Multi-select picker](doc:multi-select-picker) in your [Forms](doc:forms). +Use a multi-select column when a field should allow more than one value from a fixed list. -Multi-select column - Multi-select column - +## Create a multi-select column -Selecting multiple options - Selecting multiple options - +1. Open the table +2. Click `Create column` +3. Set the type to `Multi-select` +4. Add the allowed options +5. Save the column -When a multi-select value is saved to a data table, the values will be presented in individual coloured pills: +## Use multi-select columns -Multi-select row presenting two selected options - Multi-select row presenting two selected options - +Multi-select columns work well with the [Multi-select picker](doc:multi-select-picker) in forms. -
+Selected values appear as individual pills in tables and forms. ## Filtering -A number of array based [filters](doc:searchfilter-data) are available when using a multi-select. - -### Contains - -> The multi-select value must contain all of the selected comparison options. - - - - - - - - - - - - - - - - - - - - - - - -
- Filter - - Result -
- - - -
- - - -
- -
- -### Does not contain - -> The multi-select value must not contain all of the selected comparison options. - -#### Single value - - - - - - - - - - - - - - - - - -
- Filter - - Result -
- - - -
- -#### Multiple values - -Note that in this case only rows that have both *Senior* AND *Manager* are filtered out. - - - - - - - - - - - - - - - - - -
- Filter - - Result -
- - - -
+Use array-based filters when you need to match against multi-select values: -
+* `Contains` +* `Does not contain` +* `Has any` -### Has any +Use `Contains` when all selected comparison values must be present. -> The multi-select value contains any of the selected comparison options. +Use `Has any` when only one matching value is required. -Has any: Senior or Manager - Has any: Senior or Manager - +## Notes -Result - Result - \ No newline at end of file +* Multi-select columns are not convertible to other types +* They can still hold a single value or no value at all diff --git a/docs/Data/budibasedb/number.md b/docs/Data/budibasedb/number.md index a5584fb92..621d7e439 100644 --- a/docs/Data/budibasedb/number.md +++ b/docs/Data/budibasedb/number.md @@ -1,6 +1,6 @@ --- title: Number -excerpt: This topic describes the number data types, supported in Budibase +excerpt: Store numeric values in Budibase DB deprecated: false hidden: false metadata: @@ -10,23 +10,27 @@ metadata: next: description: '' --- -A number column is a good choice if you want to store data like age, scores, IDs, etc. The number column type is important when you need to do calculations within your data. Within the Number data type, you can provide min and max values. This allows you to add additional validation to your data type. +Use a number column for values such as quantities, scores, prices, and IDs. -## Creating a number column +## Create a number column -The process for creating a number column takes a few seconds. +1. Open the table +2. Click `Create column` +3. Enter a column name +4. Set the type to `Number` +5. Add any minimum or maximum values you need +6. Save the column -1. First, click the `+` button along the top-right -2. Give your column a name -3. Choose Number as your data type -4. Give it a min of 1, and a max of 5 -5. Click Save Column +## Use number columns -## Using the number data type +Number columns are useful when you need: -In the Design section, you can pull in information from your number column, using the [Repeater](doc:repeater) component and [bindings](doc:introduction-to-bindings) +* Calculations +* Range validation +* Numeric filtering and sorting -## Important considerations +## Notes -* A number column can only include numeric values and cannot include letters and symbols. -* Telephone numbers need to be stored as a text/string data type because they often begin with a 0 and if they were stored as an integer then the leading zero would be discounted. +* Number columns only accept numeric values +* Use text for values that can include leading zeros, such as phone numbers +* Add min and max constraints when the valid range is limited diff --git a/docs/Data/budibasedb/options.md b/docs/Data/budibasedb/options.md index 6af343ec8..cfffeff56 100644 --- a/docs/Data/budibasedb/options.md +++ b/docs/Data/budibasedb/options.md @@ -1,8 +1,6 @@ --- title: Options -excerpt: >- - `Options `data type is a straightforward way to provide _options_ for a - dropdown list or radio buttons in forms. +excerpt: Store a fixed list of values in Budibase DB deprecated: false hidden: false metadata: @@ -12,71 +10,27 @@ metadata: next: description: '' --- -
+Use an options column when a field should only allow a fixed set of values. -### Adding an `Options` column +## Create an options column -To add an options column to your table, select "Options" from this dropdown list. +1. Open the table +2. Click `Create column` +3. Enter a column name +4. Set the type to `Options` +5. Add the allowed values +6. Save the column - +## Use options columns -While creating the column, you will be able to add different options the user can select. These options can be edited later by clicking "Edit Column". +Options columns work well for: - +* Dropdowns +* Radio buttons +* Fixed-status fields -
+## Reorder options -### Use in Forms +Edit the column if you need to change the available values or their order. -Adding a `Form Block` component to your page, and setting the `Data` to your table will automatically populate fields into your form. Opening the settings panel will allow you to customise settings around your input. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Setting
LabelText that will display above the input
Placeholder TextText that is displayed the field before the user makes a selection. Defaults to "Choose an option"
On change[Configureable actions](https://docs.budibase.com/docs/form-actions) that run on change.
TypeChose between "Select" for a dropdown menu, or "Radio Buttons".

Radio buttons not quite what you're looking for? [Try Multi-select picker.](https://docs.budibase.com/docs/multi-select-picker)
Direction(Only available for Radio Buttons type input) Displays the options in vertically or horizontally arranged list.
Default ValueAssigns a default value should the user fail to make a selection
Help TextText that displays underneath, preceded by a question mark icon
AlphabeticalWhen unchecked, options will appear in the order that they shown in your data column.
- -#### Changing the order of your options - - - -To Change the order the options display in your form, firstly make sure "Alphabetical" is unchecked. Then, in the Data tab, click edit your column, and drag-and-drop your options. Alphabetical being checked will not change the order the options appear in the data tab, only the order in which they are displayed to the user in the form. - -
\ No newline at end of file +Keep the list short and stable so the column stays easy to use in forms and filters. diff --git a/docs/Data/budibasedb/relationships.md b/docs/Data/budibasedb/relationships.md index 7730b745c..7fed9ebe2 100644 --- a/docs/Data/budibasedb/relationships.md +++ b/docs/Data/budibasedb/relationships.md @@ -1,6 +1,6 @@ --- title: Relationships -excerpt: '' +excerpt: Link rows between Budibase DB tables deprecated: false hidden: false metadata: @@ -14,64 +14,32 @@ 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. +Use relationships to link rows between tables. -## Creating a relationship column +Relationships are bidirectional, so each table can reference the other. -1. Select two tables that the relationship should be formed between. -2. Make sure that in both tables there is a column defined that can be used for display purposes. When creating this column make sure to set it with the *Display column* toggle.\ - ![Showing the display column toggle.](https://files.readme.io/43d1a74-small-Screenshot_2023-05-15_at_12.46.57.png) -3. Click the *Create new column* button in either of the two tables and select the *Relationship* data type from the dropdown.\ - ![Relationship creation column option.](https://files.readme.io/5bc1f6c-small-Screenshot_2023-05-15_at_12.49.37.png) -4. Here you will need to select two options, the tables to which this column relates, and the name of the relationship column in the other table as well.\ - ![Full example of relationship creation.](https://files.readme.io/be8bbca-Screenshot_2024-01-17_at_08.09.48.png) -5. At this point, you will now have a relationship formed between the two tables. If you create a row in one of the tables, then go to the other table and create a row you should see the first row that was created as an option in the relationship multi-select.\ - ![Showcasing a new relationship and how it works on Budibase.](https://files.readme.io/0dbf6a3-showcasing_relationships.gif) +## Create a relationship -
+1. Make sure both tables have a display column +2. Open one of the tables +3. Click `Create new column` +4. Choose `Relationship` +5. Select the related table +6. Set the column name in the other table +7. Save the column -## 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. - -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. +## Relationship types ### 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. +Use one-to-many when one row can relate to many rows in another table. ### 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. - -### Building it in Budibase - -To create this in Budibase all we need to do is: - -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! - -{` -
-`}
- -## Considerations +Use many-to-many when both sides can relate to many rows and you have a join table. -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. +## Notes -{` - -`} +* Relationship columns are stored in Budibase DB, not in the display column itself +* Use nullable foreign keys in join tables for many-to-many relationships +* Budibase DB is best for simple relationship models diff --git a/docs/Data/budibasedb/text.md b/docs/Data/budibasedb/text.md index 7be4a4b2f..fb983f428 100644 --- a/docs/Data/budibasedb/text.md +++ b/docs/Data/budibasedb/text.md @@ -1,6 +1,6 @@ --- title: Text -excerpt: This topic describes the string/text data types, supported in Budibase +excerpt: Store short strings in Budibase DB deprecated: false hidden: false metadata: @@ -9,71 +9,33 @@ metadata: robots: index next: description: '' - pages: - - type: basic - slug: bindings - title: Bindings - - type: basic - slug: repeater - title: Repeater --- -The text data type stores a string of UTF-8 characters. A text column is a good choice if you want to store data like names or addresses It is a common data type and one you are more than likely going to use. +Use a text column for short strings such as names, addresses, labels, and identifiers. -*** +## Create a text column -## Creating a text column +1. Open the table +2. Click `Create column` +3. Enter a column name +4. Keep the type as `Text` +5. Save the column -The process for creating a text column takes a few seconds. +## Use text columns -1. First, click the `Create column` button. -2. Give your text column a name - such as 'Name'. -3. By default the text data type will be selected; so there's no need to change it. -4. Click `Save Column`. +Text columns work well with: -*** +* Display text components +* Text inputs +* Formula columns that build or transform strings -## Using the text data type +## Convert text columns -In the Design section, will be able to use a variety of components for [Displaying text](doc:displaying-text), as well as a number of form [Text inputs](doc:text-inputs) for accepting user input. +You can convert a text column into a related type when the data needs a stricter shape. -*** +Common conversions include: -## Convertible types +* Options +* Long Form Text +* Barcode/QR -The text data type can be converted into another related type. - -Changing the Text type - Changing the Text type - - -The most common reason to change the type of a text column will be to make it compatible with one of the following [Form](doc:forms) components: - -* [Options picker](doc:option-picker) -* [Long Form Field](https://docs.budibase.com/docs/text-inputs#long-form-field) -* [Barcode/QR Field](doc:barcodeqr-field) - -
- -### Options - -Options type - Options type - - -Allows a single value to be chosen from a dropdown of options. - -> 📘 -> -> Any existing text value will be kept, however it will appear as a *null* in the dropdown. - -Selecting an option - Selecting an option - - -
- -### Long Form Text - -Long form text type - Long form text type - +Keep existing values in mind before changing the type, especially if the new type needs a different format. diff --git a/docs/Data/budibasedb/users-1.md b/docs/Data/budibasedb/users-1.md index fe0427c11..c6bddf20e 100644 --- a/docs/Data/budibasedb/users-1.md +++ b/docs/Data/budibasedb/users-1.md @@ -1,6 +1,6 @@ --- title: User -excerpt: '' +excerpt: Store Budibase users in Budibase DB deprecated: false hidden: false metadata: @@ -10,77 +10,46 @@ metadata: next: description: '' --- -The Single User and Multi User column types allow you to select a Budibase user from a dropdown list as determined by the [Application access](doc:application-access). This list will include all admins of the tenant, and any members of the app. +Use user columns when a row needs to reference one or more Budibase users. -Note the slight variation in icons between Single User (team_leader) and Mutli User (team_members) columns - Note the slight variation in icons between Single User (team\_leader) and Multi User (team\_members) columns - +## Create a user column -With the user column added, you can now click the `+` within your data grid view to select a user as identified by their searchable email address. When using a Single User column, if you try to add another user, the current user will be removed. +1. Open the table +2. Click `Create column` +3. Choose `Single User` or `Multi User` +4. Save the column -> 👍 SQL support -> -> The user column is available for both the Budibase DB and external [SQL databases](doc:sql-datasource). -> -> In the case of SQL, when a user column is added within Budibase, it will create a varchar column in your table to hold the user id: -> -> +The dropdown includes app members and tenant admins. -
+## Use user columns -*** +User columns are commonly used for: -
+* Ownership +* Assignment +* Approvals -## Usage +In forms, use the [User Field](https://docs.budibase.com/docs/pickers#user-field) component. -A common usage of user columns in your tables is to indicate *ownership* or *assignment*. +## Filter by current user -For example, I can add an 'Assignee' user column to a 'Jobs' table to indicate who is responsible for completing that job. +Use `{{ Current User._id }}` to filter rows for the logged-in user. - +Use a contains filter when the column allows multiple users. -When making use of a user column in your [Forms](doc:forms), you need to use the [User Field](https://docs.budibase.com/docs/pickers#user-field) component. +## SQL support -
+User columns also work with external SQL datasources. -### Show current user records +Budibase stores the user ID in a varchar column in the SQL table. -For single user columns, you can [filter](doc:searchfilter-data) on the currently logged in user by using the `{{ Current User._id }}` [binding](https://docs.budibase.com/docs/users-table#current-user-bindings). +## Migrate existing relationships - +Apps created before v2.11.0 can migrate user-table relationship fields to user columns. -If your user column has *Allow multiple users* enabled, then the filter will be a [contains](https://docs.budibase.com/docs/multi-select#filtering) like so: +1. Open the table +2. Open the table menu +3. Choose `Migrate to user column` +4. Follow the prompts to create the new column - - -
- -*** - -
- -## Migrate to user column - -> 📘 -> -> As of **v2.11.0** you will no longer be able to create a relationship between the [Users table](doc:users-table) and a Budibase DB. -> -> To accommodate this change, apps that were created before **v2.11.0** can migrate existing user table relationship fields to the new user column, as outlined below. - -1. Open your existing app and navigate to the Budibase table that contains a user relationship -2. Click the hamburger menu, and select the last option: `Migrate to user column` - - - -3. Click `Continue` to create the new user column. As warned, you may need to update some existing bindings - - - -User column added - User column added - - -This will remove the link from the **App users** table and can improve the performance of your apps. - -It should also be noted that if you were [displaying user data](https://docs.budibase.com/docs/fetching-data#display-user-specific-data) through a migrated relationship link, this would also need to be updated as shown in the 'Usage' section above. +Update any bindings that referenced the old relationship field. 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/csv-import.md b/docs/Data/data-sources/csv-import.md index 5e0e68041..3a4cac912 100644 --- a/docs/Data/data-sources/csv-import.md +++ b/docs/Data/data-sources/csv-import.md @@ -1,6 +1,6 @@ --- title: CSV Import -excerpt: Importing a CSV or JSON into Budibase as a table +excerpt: Import CSV or JSON data into Budibase deprecated: false hidden: false metadata: @@ -10,56 +10,46 @@ metadata: next: description: '' --- -When you already have existing data, you can import this using a CSV file, which will create a new table in the internal [Budibase DB](doc:budibasedb). This will automatically identify columns and create them for you, after which you can specify data types per column. +Use CSV import when you already have data and want to create a table from it. -1. Click `Add source` and select `Upload CSV / JSON`. +Budibase can also import JSON files using the same flow. -![](https://files.readme.io/43e243af5476f19482f320a113f233a64d2f742c8eef8e877f5fe8e202eefbfc-image.png) +## Create a new table -2. Click `Continue`. You will now see a modal in which you can enter a table name. +1. Click `Add source` +2. Select `Upload CSV / JSON` +3. Upload the file +4. Enter a table name +5. Review the detected columns +6. Choose the data type for each column +7. Click `Create` -![](https://files.readme.io/e178d1252880767f4d27a60dec8ffcd9d65e5e396692acb3f794ac61c7d72072-image.png) +When you import a CSV, the first row is used as the column header row. -3. Click `Upload` and select the CSV or JSON file you want to import. +## Import into an existing table -> 📘 Column names -> -> When importing a CSV, the first row will be used to determine the column names. +Use this flow when you want to add rows to an existing Budibase table. -In the example below, I imported a CSV with 4 columns representing a table of countries. After the file was uploaded, the screen below was shown. +1. Open the target table +2. Click `Import` +3. Upload the CSV or JSON file +4. Match the source columns to the destination columns +5. Ignore any columns that do not match +6. Click `Import` -![](https://files.readme.io/e3cb064-csv-data-types.png "csv-data-types.png") +## Update existing rows -As you can see, it automatically identified the 4 columns and allowed me to pick the data types for each column. +You can also update rows from an import. -4. Click `Create` to build a new table from your imported CSV/JSON file. +1. Open the import flow for the target table +2. Enable `Update existing rows` +3. Select the identifier field +4. Import the file -
+Budibase uses the identifier field to match incoming rows against existing records. -## Importing rows into an existing table +## Notes -You may find that you want to update an existing table with new CSV/JSON data. To do so, click on the Budibase table you want to import into. Next click the `Import` button. - -![](https://files.readme.io/f1a71270cb420c2d3e3c1ca2b89b1025072d3164c903b21d178fc9e56bef53eb-image.png) - -Once you have selected a file, Budibase will match the column names from the CSV against the destination table. Column names that do not match will be ignored, and the modal will highlight the offending fields: - -![](https://files.readme.io/33448a3-csv-4c.png) - -Click `Import` to pull in the new rows. - -## Updating rows with CSV - -This is done in a similar fashion to importing a CSV for creating rows. The only difference being, is a toggle at the bottom which needs checked `Update existing rows`. Additionally, an identifier field needs selected. The purpose of this field is to check for records that are already existing. If one is found in the database that matches the CSV. Then this record will be updated with the CSV's data instead of a new record being created. - - - -> 🚧 Duplicate records -> -> As an **\_id** field is only assigned upon import, Budibase does not determine if a row has previously been imported. It will always import any rows provided in the CSV/JSON file. - -
- -> 👍 Reading CSV data from an S3 bucket -> -> If you have a CSV file in an S3 bucket, you can use the [S3](https://docs.budibase.com/docs/s3#read-csv) connector to read the CSV data. +* CSV imports need a header row +* JSON imports use the same import flow +* Rows without a matching identifier are imported as new records diff --git a/docs/Data/data-sources/google-sheets.md b/docs/Data/data-sources/google-sheets.md index 87bf403bf..02bfe52d2 100644 --- a/docs/Data/data-sources/google-sheets.md +++ b/docs/Data/data-sources/google-sheets.md @@ -1,6 +1,6 @@ --- title: Google Sheets -excerpt: '' +excerpt: Connect a Google Sheet as a datasource deprecated: false hidden: false metadata: @@ -10,104 +10,59 @@ metadata: next: description: '' --- -Google Sheets is a spreadsheet program included as part of the free, web-based Google Docs Editors suite. +Use Google Sheets when you want Budibase to read and write sheet data directly. -> 🚧 Google Sheets Compatibility -> -> The Google Sheets integration only supports simple table structures. For data fetching to work correctly, the sheet must have a clear header row as the first available row. +Budibase works best with simple tabular sheets. Make sure the first row contains headers. -## Setup +## Connect the sheet -Navigate to the spreadsheet you want to integrate into Budibase. Copy the URL. +1. Add a datasource and select `Google Sheets` +2. Sign in with a Google account that can access the spreadsheet +3. Paste the Google Sheet URL +4. Select the worksheets to import +5. Save the datasource -![](https://files.readme.io/5feaf25-Screenshot_2022-09-05_at_11.21.27.png) +## Work with sheet data -## Connect +Each worksheet appears as a grid in Budibase. -Click the `+` button to add a datasource, and then select 'Google Sheets'. +You can: -![](https://files.readme.io/8cfccf3d2fe0b0b2036d898f42f57945fcd26697df5126e30dceab677fe78bab-image.png) +* View rows in the builder +* Add, edit, and delete rows +* Use the sheet as a form schema +* Use row actions such as `Save Row` -You will then be prompted to sign-in with a Google account. This account should have permissions to view the spreadsheet you want to work with. +## Add a query -![](https://files.readme.io/096a6ca-Screenshot_2022-09-05_at_11.27.31.png) +Use a query when you need to create, read, update, or delete rows from a sheet. -Allow Budibase to access your Google account. +1. Open the Google Sheets datasource +2. Click `Add query` +3. Choose the operation you need +4. Provide the sheet name +5. Add the row data or row index required by the query -![](https://files.readme.io/b32a6e1-Screenshot_2022-09-05_at_11.29.01.png) - -> ❗️ Self-hosting -> -> If you are self-hosted, you will need to setup [Google SSO](https://docs.budibase.com/docs/sso-with-google) - -Once you have authenticated with Google, you will be asked to provide your Google Sheet URL - -![](https://files.readme.io/e03a8b1-Screenshot_2023-06-27_at_12.26.03.png) - -Once Budibase successfully connects to your Google Sheet, you can select which worksheets to import (or skip): - -![](https://files.readme.io/fb85e77-Screenshot_2023-06-27_at_12.26.10.png) - -> 🚧 Header row needed -> -> Your worksheets will need to have a header row to successfully import into Budibase. Your header row must be the first row in each sheet. - -## Data view - -Each sheet can be viewed and edited as a grid within the Budibase builder. - -![](https://files.readme.io/bdfb0bd9c762c62a57a2ccb506f6519cf2da6cd331034e04d7b6b4a8ba2c588b-image.png) - -You can edit columns, add rows, edit rows and delete rows via the Grid interface. Changes made in Budibase will be reflected in that sheet of your Google spreadsheet. You can also create views that will not be reflected in your Google Sheet, but will help you visualise existing data. - -![](https://files.readme.io/16e9bdc-Screenshot_2023-06-27_at_12.34.04.png) - -In addition, Google Sheets data tables can utilise the row actions, such as [Save Row](https://docs.budibase.com/docs/actions#save-row) and be used as a [Form schema](https://docs.budibase.com/docs/forms#form-schema) - -## Query - -The Google Sheets connector supports adding queries for when you might need to [transform data](https://docs.budibase.com/docs/transformers) or perform CRUD operations with specific [bindings](https://docs.budibase.com/docs/custom-queries#using-query-bindings). - -To add a query, select your Google spreadsheet datasource, and click `Add query` at the bottom of the configuration page. - -![](https://files.readme.io/a9adb33-Screenshot_2022-09-05_at_12.18.47.png) +## Query types ### Create -Allows you to insert a row. You must provide the name of the sheet as well as a JSON payload to specify the column names and value. - -![](https://files.readme.io/4427cd3-Screenshot_2022-09-05_at_13.04.36.png) - -The row number of the created entry will be returned on success. - -![](https://files.readme.io/1109724-Screenshot_2022-09-05_at_13.08.11.png) - -![](https://files.readme.io/b80505f-Screenshot_2022-09-05_at_13.09.01.png) +Insert a new row by providing the sheet name and a JSON payload of column names and values. ### Read -Simply returns all the rows of a specified sheet. The transformer allows you to filter and map the data into the schema you desire. - -![](https://files.readme.io/fd66d8ef963f4adb57b475f0e711689a540fed6612997dc0e8fd9c37c52ce7f3-image.png) +Return all rows from a sheet. Use a transformer if you need to filter or reshape the data. ### Update -Similar to *Create* in that you must provide a payload of data, however you must also provide a row index to be overwritten. - -> 📘 Row index -> -> Row indexing starts from zero - the first row below the header row (usually the second row). - -![](https://files.readme.io/ed9e641-Screenshot_2022-09-05_at_17.04.58.png) - -![](https://files.readme.io/052333b-Screenshot_2022-09-05_at_17.05.38.png) +Update an existing row by providing the sheet name, row index, and new values. Row indexes start at zero for the first data row below the header. ### Delete -The same as *Update*, a sheet name and row index must be provided. That row will be deleted. - -![](https://files.readme.io/d755faf-Screenshot_2022-09-05_at_17.07.56.png) +Delete a row by providing the sheet name and row index. Rows below the deleted row shift up. -Rows will be shifted up after deletion. +## Notes -![](https://files.readme.io/07371b1-Screenshot_2022-09-05_at_17.09.23.png) +* Your sheet must have a header row +* Self-hosted installations need Google SSO configured +* Use exact sheet and column names to avoid import errors 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/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 22b21346e..697489785 100644 --- a/docs/Data/data-sources/ms-sql-server.md +++ b/docs/Data/data-sources/ms-sql-server.md @@ -1,6 +1,6 @@ --- title: MS SQL Server -excerpt: Connecting Budibase to an existing Microsoft SQL Server +excerpt: Connect Microsoft SQL Server as a datasource deprecated: false hidden: false metadata: @@ -10,210 +10,36 @@ metadata: next: description: '' --- -> 👍 SQL Databases -> -> Budibase is designed to integrate with any core SQL database. -> -> Read more about [SQL Datasources](doc:sql-datasource). +Use MS SQL Server when you want Budibase to connect to an existing Microsoft SQL Server database. -# Connecting to SQL Server +Budibase supports SQL Server 2016 and later. -After clicking on the SQL Server datasource you will be prompted to enter connection details: +## Connect the datasource - +1. Open the **Data** section. +2. Add a new source. +3. Choose `MS SQL Server`. +4. Enter the connection details. +5. Fetch the tables you want to use. -## Advanced authorisation +If Budibase is running in Docker and the database is on the same machine, use `host.docker.internal` or `172.17.0.1` on Linux. -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. +## Temporal tables - +Budibase supports system-versioned temporal tables. It imports the main table, excludes history tables from fetch, and marks system-managed period columns as auto-columns. -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). +## Fetch tables -
+Fetch only the tables you need. You can fetch additional tables later if the schema changes. -*** +## Define relationships -## Temporal Tables +Add relationships after you fetch the tables. -Budibase supports MSSQL [System-Versioned Temporal Tables](https://learn.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables). When you fetch the schema for an MS SQL Server database, Budibase handles temporal tables as follows: +Use one-to-many relationships for foreign keys and many-to-many relationships when your schema includes a join table. -* **Primary Table**: The main temporal table is imported like any other base table. -* **History Table**: Budibase automatically detects and excludes history tables from the fetch process. This prevents your data schema from being cluttered with read-only history entities. -* **Generated Columns**: System-managed columns used for period definitions (such as `ValidFrom` and `ValidTo`, often defined as `GENERATED ALWAYS AS ROW START/END`) are automatically detected and marked as **Auto-columns** in Budibase. This ensures the table remains writable while respecting the system-managed nature of these specific fields. +## Custom queries -
+Use custom queries for joins, grouped results, or write actions from a form or button. -*** - -
- -# 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.\ -> In this case, `products`, `brands` and `categories` must all have public read access. - -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 }}` - -To explain, *brands* is the name of the relationship field. The `.0` is required as relationship fields are always considered to be an array, however in this case we know that it will only ever be one element. Finally the `primaryDisplay` corresponds to the [table display column](https://docs.budibase.com/docs/budibasedb#selecting-the-display-column). - -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. - -After setting up your relationships, as outlined earlier in the tutorial, go to the **Design** section and click `Add screen`. Next click on `Autogenerated screens`. - -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. +See [Working with SQL datasources](doc:sql-workflow) for the shared workflow after the connection is in place. diff --git a/docs/Data/data-sources/mysql-mariadb.md b/docs/Data/data-sources/mysql-mariadb.md index e9beb317d..76db9e013 100644 --- a/docs/Data/data-sources/mysql-mariadb.md +++ b/docs/Data/data-sources/mysql-mariadb.md @@ -1,6 +1,6 @@ --- title: MySQL / MariaDB -excerpt: Using a MySQL Database Server as a datasource for Budibase +excerpt: Connect a MySQL or MariaDB database as a datasource deprecated: false hidden: false metadata: @@ -10,345 +10,37 @@ metadata: next: description: '' --- -> 👍 SQL Databases -> -> Budibase is designed to integrate with any core SQL database. -> -> Read more about [SQL Datasources](doc:sql-datasource). +Use MySQL / MariaDB when you want Budibase to connect to an existing relational database. -# Video tutorial +Budibase supports: - +* MySQL 8.0 and later +* MariaDB 10.6 and later -
+## Connect the datasource -*** +1. Open the **Data** section +2. Add a new source +3. Choose `MySQL / MariaDB` +4. Enter the connection details +5. Fetch the tables you want to use -# Tutorial: Building a HR portal +If Budibase is running in Docker and the database is on the same machine, use `host.docker.internal` as the host value. -In this tutorial we will look at building a Budibase app from scratch using a MySQL employees sample database. +## Fetch tables -The full dataset and installation instructions can be found on [GitHub: datacharmer/test\_db](https://github.com/datacharmer/test_db). +Fetch only the tables you need. You can fetch more tables later if the schema changes. -
+## Define relationships -## Adding the datasource +Add relationships after you fetch the tables. -When you have a MySQL or MariaDB Server instance running, with the sample database installed, we can begin pulling that data into Budibase. +Use one-to-many relationships for foreign keys and many-to-many relationships when your schema includes a join table. -First create a new Workspace. We will set up our MySQL datasource and app here. +If Budibase rejects a join table, update the source table so the foreign key columns are nullable, then fetch the table again. - +## Custom queries -Once the new workspace has been created, click `Add source` and select `MySQL`, even if you are using MariaDB, or any other storage engine. +Use a custom query when you need joins, grouped results, or write actions from a form or button. -![](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 -ALTER TABLE `employees`.`dept_emp` -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: - - - -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 - - -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 - -Now that we have the data pulled into Budibase, let's create a screen that allows HR to see the various departments and the org structure for each. - -### Step 1 - Adding the row explorer - -On the home screen, click `Add component` and select the *Row Explorer Block*. For the table select **departments**, and remove the height - we will display all nine departments at once without the need for scroll. - -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. - -1. Within Budibase, click on the **departments** table, and click `Create column`. -2. Add a [Text](doc:text) column called **icon\_url**. -3. For each department row, add a URL path to an appropriate icon. I have found [svgrepo.com](https://www.svgrepo.com/) to be a good resource for free SVG icons. For your convenience, I have provided SQL update statements: - -```mysql -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/428772/marketing-market-social.svg' WHERE dept_no = 'd001'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/381027/finance-bank-piggy-business-money.svg' WHERE dept_no = 'd002'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/218257/human-resources-search.svg' WHERE dept_no = 'd003'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/430190/production-industrial-automation.svg' WHERE dept_no = 'd004'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/428736/development-cognitive-progress.svg' WHERE dept_no = 'd005'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/422994/quality-premium-certificate.svg' WHERE dept_no = 'd006'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/430192/sales-shop-analytics.svg' WHERE dept_no = 'd007'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/119008/research.svg' WHERE dept_no = 'd008'; -UPDATE departments SET icon_url = 'https://www.svgrepo.com/show/429955/customer-service-hotel.svg' WHERE dept_no = 'd009'; -``` - -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: - -```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) - -### Step 2 - Adding the manager and employee cards - -After ejecting the row explorer block, we need to change the Data provider source to the *Get Departments Only* as we do not want the relational employee data in this simple list of departments. - -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. - -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: - -```sql -SELECT * FROM departments d -JOIN dept_manager dm on d.dept_no = dm.dept_no -JOIN employees e on dm.emp_no = e.emp_no -JOIN titles t on t.emp_no = e.emp_no -WHERE d.dept_name = {{ dept_name }} AND (e.emp_no, t.from_date) in (select t.emp_no, max(t.from_date) from titles t group by emp_no) -``` - -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) - -
- -## Employees screen - -As this data set has thousands of employees per department, cards are not an ideal way to display the data. Instead we can display this data in a paginated [Table block](doc:table-block) filtered on an encoded department ID passed via [URL variables](doc:url-parameters). - -To get started, click `Add screen` and select `Autogenerated screens`. Tick the **employees** table and confirm. - -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 - - -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. - -### Linking from the home screen - -The employee screen is ready to go, but we still need to link it to the home screen. - -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 - -The **salaries** table holds a historic record of each employees salary at a particular time. This time series can be displayed in a chart. - -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 -
- - - -
+See [Working with SQL datasources](doc:sql-workflow) for the shared workflow after the connection is in place. diff --git a/docs/Data/data-sources/oracle.md b/docs/Data/data-sources/oracle.md index 850b04f01..d242c09c0 100644 --- a/docs/Data/data-sources/oracle.md +++ b/docs/Data/data-sources/oracle.md @@ -1,6 +1,6 @@ --- title: Oracle -excerpt: Connecting Budibase to an existing Oracle database +excerpt: Connect an Oracle database as a datasource deprecated: false hidden: false metadata: @@ -10,308 +10,32 @@ metadata: next: description: '' --- -> 👍 SQL Databases -> -> Budibase is designed to integrate with any core SQL database. -> -> Read more about [SQL Datasources](doc:sql-datasource). +Use Oracle when you want Budibase to connect to an existing Oracle database. -# Tutorial: Building a Departments Portal +Budibase supports Oracle 12.1 and later in Thin mode and Oracle 11.2 and later in Thick mode. -In this tutorial we will be building an app to allow executive staff to view and manage department and employee details. +## Connect the datasource -To get started, follow the instructions from the [Database Star sample database](https://github.com/bbrumm/databasestar/tree/main/sample_databases/oracle_hr) repo, running the setup scripts against your Oracle instance. +1. Open the **Data** section +2. Add a new source +3. Choose `Oracle` +4. Enter the connection details +5. Fetch the tables you want to use -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). +## Fetch tables -## Adding the datasource +Fetch only the tables you need. You can fetch more tables later if the schema changes. -With your Oracle instance running, and the sample database installed, we can begin pulling that data into Budibase. +## Define relationships -First create an app - no sample data needed. +Add relationships after you fetch the tables. -![](https://files.readme.io/e745f7b-oracle-create-your-app.png) +Use one-to-many relationships for foreign keys and many-to-many relationships when your schema includes a join table. -Once the new app has been created, click `Add source` and select `Oracle`. +If Budibase rejects a join table, adjust the source tables and fetch them again. - +## Custom queries -Click `Continue` and then fill out the connection config with the host, service name and user of your Oracle instance. +Use custom queries for joins, grouped results, or write actions from a form or button. -![](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 - -Our **REGION** table includes four regions. To start of with, let's present the user with a world map from which they can select a region and further drill down into country > location > department > employees. - -Click on the **Design** tab along the top. Next add the [Background image](https://docs.budibase.com/docs/image#background-image) component, with a URL to a [World Map image](https://www.pixelstalk.net/wp-content/uploads/2016/06/Free-desktop-world-map-wallpapers-HD.jpg). Set the *Height* and *Width* to `100%`. - -Next add a [Section](doc:using-sections) and set the type to `Three columns` and [Custom CSS](doc:custom-css) to set the height: - -```css -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 - -With our region map setup, we can add a country screen that will list the countries of the selected region. - -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. - -Untick the setting `Show button above table`. All the countries have already been added, and we don't want the user to be able to enter new records. - -### Search fields - -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 - -As a nice visual cue, we can also add [Image](doc:image) components to each row of our table. To do this we must first [Eject](https://docs.budibase.com/docs/blocks#ejecting-blocks) the table block. Next select the [Table](doc:table) component, and click the `Add component` button. - -Select the image component, and set the *Width* and *Height* to `64px` and `36px`. - -Finally, for the *URL* property, click the lightning icon to provide the following JavaScript Binding: - -```javascript -const country = $("Table.COUNTRIES.COUNTRY_NAME")?.toLowerCase()?.replaceAll(" ", "-"); - -if (country === "united-states-of-america") { - return "https://www.rankflags.com/wp-content/uploads/2015/04/National-Flag-Of-United-States.jpg" -} - -if (country === "israel") { - return "https://upload.wikimedia.org/wikipedia/commons/d/d4/Flag_of_Israel.svg" -} - -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 - -While the countries screen is setup, we still need to filter the countries by region and link the screen to the chosen region. - -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 - -The next level of data to drill into is the list of departments for the selected country. - -In the `/countries/:region_id` screen, delete the **Details form block**. The countries should be static and not editable by the user - we only want to display the list of departments here. - -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.\ -> As relationship links in Budibase are stored in this format, this field must be used when filtering on side panel state IDs. - -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 - -The last screen we want is for displaying all the employees of a selected department. Click `Add screen` and add a `List view` screen for the **EMPLOYEES** table. - -Change the *Route* to `/employees/:department_id`. Then in the components view, click on the Table block and `Define filters`. Add a filter to match `{{ URL.department_id }}` against `DEPARTMENT.DEPARTMENT_ID`. - -You can also eject the table block so that you can deselect some of the employee form fields, such as the ID and the department fields. - -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 - -As both the employees screen and the countries screen require an ID in the URL, we do not want to show the nav link for these screens. - -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 - -Currently the departments listed for a location are read-only. It may be the case that you want *Admin* users to be able to add new or update existing departments. - -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 - +See [Working with SQL datasources](doc:sql-workflow) for the shared workflow after the connection is in place. diff --git a/docs/Data/data-sources/postgresql.md b/docs/Data/data-sources/postgresql.md index 301fab185..2ec7dca12 100644 --- a/docs/Data/data-sources/postgresql.md +++ b/docs/Data/data-sources/postgresql.md @@ -1,6 +1,6 @@ --- title: PostgreSQL -excerpt: Using a Postgres Database Server as a datasource for Budibase +excerpt: Connect PostgreSQL as a datasource deprecated: false hidden: false metadata: @@ -10,403 +10,34 @@ metadata: next: description: '' --- -> 👍 SQL Databases -> -> Budibase is designed to integrate with any core SQL database. -> -> Read more about [SQL Datasources](doc:sql-datasource). +Use PostgreSQL when you want Budibase to connect to an existing PostgreSQL database. -# Video tutorial +## Before you start - +Make sure you have: -
+* A running PostgreSQL instance +* Credentials for the database +* Permission to add datasources in Budibase -*** +## Connect the datasource -# 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 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 Budibase is running in Docker and the database is on the same machine, use the host value required by your environment instead of `localhost`. -![](https://files.readme.io/0c9bb3a-Screenshot_2023-02-07_at_15.39.23.png) +## Fetch tables and define relationships -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. +Fetch only the tables you need, then 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 your schema includes a join table. -## Datasource setup +## Custom queries -Assuming you have setup the example database on a running Postgres instance, we can start pulling data into Budibase. +Use custom queries for joins, grouped results, or write actions from a form or button. -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) - -### Database Privileges - -When connecting to PostgreSQL, the user provided in the connection configuration must have sufficient privileges to read the database schema. - -Specifically, the user needs: -* **USAGE** privilege on the schema (e.g., `public`). -* **SELECT** privilege on the tables you wish to import. - -If the user has `USAGE` privilege but is missing `SELECT` privilege, Budibase may be able to see that the tables exist but will be unable to read their columns. In this case, you will see an error message indicating that the user is likely missing `SELECT` privileges. To resolve this, grant select access to the user in your database: - -sql -GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_user; - - -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 `Saved` 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}/parents_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 - +See [Working with SQL datasources](doc:sql-workflow) for the shared workflow after the connection is in place. diff --git a/docs/Data/data-sources/redis.md b/docs/Data/data-sources/redis.md index 222e16df2..5d75b0d01 100644 --- a/docs/Data/data-sources/redis.md +++ b/docs/Data/data-sources/redis.md @@ -1,65 +1,52 @@ --- title: Redis -excerpt: '' +excerpt: Connect Redis as a datasource deprecated: false hidden: false metadata: title: '' - description: kba_5hgjm + description: '' robots: index next: description: '' --- -Redis is an open source (BSD licensed), in-memory data structure store used as a database, cache, message broker, and streaming engine. - -More information can be found in the [official Redis docs](https://redis.io/docs/about/). - -## Connect - -Add a data source and select Redis. - -![](https://files.readme.io/a9c9734-Screenshot_2022-09-02_at_15.55.33.png) - -![](https://files.readme.io/ad48705-Screenshot_2022-09-02_at_17.05.09.png) +Use Redis when you need a fast key-value store for simple read and write operations. -You will then be prompted to provide the URL, port, username and password. The default database index is 0. +For the official Redis documentation, see the [Redis docs](https://redis.io/docs/about/). -![](https://files.readme.io/346b986-small-Screenshot_2023-05-10_at_09.45.17.png) +## Connect Redis -> 📘 Connecting to a local docker instance -> -> If you are hosting Redis locally with docker, then use **host.docker.internal** +1. Add a datasource and select `Redis` +2. Enter the connection details +3. Save the datasource -## Redis Command +If you are using Redis locally in Docker, use `host.docker.internal` as the host value. -Select `Redis Command` from the *Function* dropdown. You will now be able to enter any valid Redis command into the query box below. +## Use the Redis Command query -![](https://files.readme.io/a761999-Screenshot_2022-09-02_at_17.01.49.png) +`Redis Command` is the most flexible query type. Use it when you want to run a Redis command directly. -This is the recommended function as it is the most flexible. The basic commands can be found below. +1. Open the Redis datasource +2. Create a query with the `Redis Command` function +3. Enter a valid Redis command in the query box +4. Test and save the query -For more information on the range of Redis data types and commands, click [here](https://redis.io/docs/data-types/). +## Common operations ### Create -This is the equivalent of Redis' SET command. Enter a **key / string value** pair. - -**Ttl** stands for *Time-to-live* and is the number of seconds that the data structure will exist. Leave this blank if you want your key/value to never expire. - -![](https://files.readme.io/9cf3e6d-Screenshot_2022-09-02_at_16.02.14.png) - -Only **strings** are supported by this function. +Use `SET` to create or update a key. You can also set a TTL in seconds. ### Read -This is the equivalent of Redis' GET command. Simply enter a **key** you want to get. The response will return the mapped value. - -![](https://files.readme.io/546ebe2-Screenshot_2022-09-02_at_16.07.40.png) - -![](https://files.readme.io/f335d90-Screenshot_2022-09-02_at_16.07.57.png) +Use `GET` to return the stored value for a key. ### Delete -This is the equivalent of Redis' DEL command, except you can only delete a single **key** at a time. +Use `DEL` to remove a key. + +## Notes -![](https://files.readme.io/7a41cbc-Screenshot_2022-09-02_at_16.15.12.png) \ No newline at end of file +* The basic query examples only support string values +* Use the command query when you need more than the built-in helpers +* Refer to the Redis docs for supported data types and commands diff --git a/docs/Data/data/index.md b/docs/Data/data/index.md index d18731a56..f34b54b5b 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 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 usually comes 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 too 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 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/Data/data/users-table.md b/docs/Data/data/users-table.md index 05b9eb6a4..474f58bdd 100644 --- a/docs/Data/data/users-table.md +++ b/docs/Data/data/users-table.md @@ -10,128 +10,43 @@ metadata: next: description: '' --- -The **App users** table is a special Budibase DB table that stores all of the users that have access to the app. +The **App users** table stores the users who can access your app. -It is anchored to the top of the Datasource list, and has a unique icon to differentiate it from other tables: +It is a read-only Budibase DB table that sits at the top of the datasource list. - +## What it contains -Unlike regular tables, you cannot add rows to the users table, this is a read only table. In addition, rows cannot be deleted so that the audit trail remains intact even if a users' access is revoked. +The users table includes standard user fields and any custom columns added by Budibase. -[User Management](doc:user-management) is handled through the [Admin Portal](doc:portal), and the [Users panel](https://docs.budibase.com/docs/application-access). - -The standard columns include: - - +You can use those values in bindings, filters, and conditional logic. ## Updated By columns -It is possible to add auto-columns to your tables, which includes the *updated by* column. - -Adding a 'Updated By' auto-column - Adding a 'Updated By' auto-column - - -This will create a linked column in the Users table with the following name format: - -* \[table name]-updated\_by - -These can be used to display user specific data for the currently logged-in user. - -When a row is created or updated through the UI, the user will appear in the 'Updated By' column. - - - -> 🚧 Autogenerated column -> -> The wand icon indicates that this column is autogenerated and auto-populated.\ -> The values cannot be overwritten or saved manually. - -## Edit roles +When you add an `Updated By` auto column to another table, Budibase creates a linked field in the users table. -You can also add custom roles to your app. More information [here](https://docs.budibase.com/docs/user-roles#adding-custom-roles). +Use these columns to display user-specific data for the current logged-in user. ## Current User bindings -There are globally available Bindings for every column in the Users table, including the custom columns. - - - -For example, these can be used to display the name of the currently logged-in user, or [Add filtering](doc:searchfilter-data) on the **\_id** to get related user data. - -### OAuthToken - -When the user logs in using SSO, an [OAuth token](https://docs.budibase.com/docs/authentication-and-sso#using-the-oauth-token) will be available for use in API headers. - -*** - -## Tutorial: Create/Edit user details screen - -You may want to allow a method for users to add additional details. This tutorial will outline how to create a table for users to add additional details about themselves. This requires creating an additional table called user details. - -#### Step 1 - Create a new table - -Add a new internal table data source in the data section and create a new table called user details. You can add as many fields as you like here, such as avatar, number, etc. - -#### Step 2 - Add a single user column - -Add a single user column to this table. Later, this will be used to assign a row's ownership to a specific user. As well as do filtering for conditional logic applied to components. - -#### Step 3 - Add the edit user profile button - -Navigate to **Design**, and click `Add component` and select [Sections](doc:using-sections) leaving the *Type* as `Main with sidebar`. - -Next add a [Headline](https://docs.budibase.com/docs/displaying-text#headline) with the following text Binding: `Welcome back {{ Current User.firstName }}!`. - -Now you could easily add a [Button](doc:button), but it would be nice to include a user icon for editing profile info, therefore add a [Container](doc:container) instead and set a background and border. - -Inside the container, add an [Icon](doc:icon), selecting *user-fill* and set the *Size* and *Color*. Then add a [Paragraph](https://docs.budibase.com/docs/displaying-text) component with the text 'Create my profile'. - - - -#### Step 4 - Add a Data provider - -Add a [Data provider](doc:data-provider), limit this to 1, and select your user details table as the source. Then apply the following filter; - - - -This will only pull rows that are assigned to the user via the user column we made earlier. We will use this later to do some conditional rendering on which form will be used depending on whether the user has already created a record. - -#### Step 5 - Create/Edit my profile side panel - -Add a [Side panel](doc:side-panel), and two nested [Form blocks](doc:form-block). Select the 'user details' *Table*. Set the second form block *Type* to 'Update'. - -In the second form block, set the *Row ID* to: `{{ User details data.Rows.0._id }}` and provide a *Title*. - - - -Select the **Container** and click `Define actions` beside the *On click* setting. Add the **Open Side Panel** and select the side panel in the dropdown. - - - -Add default values to the user field inside each of the form blocks. You can do this by clicking on the cog icon next to the field in the form block's settings. Once the context menu is open, click the lightning bolt next to the "default value" field and then apply this binding to the field `{{ Current User._id }}`. - -#### Step 6 - Finishing off - -Add conditions to the two forms. For this, we will be using the [Data provider](doc:data-provider) we discussed previously. For the create form, we will be using the below condition; +Use the `Current User` bindings to access logged-in user data in the builder. - +Common uses include: -Both forms will use this initial binding `{{ User details data.Rows Length }}`. For the update form, we will be using the below condition; +* Displaying the current user name +* Filtering rows assigned to the current user +* Using the user OAuth token in API headers - +## User columns -Lastly, we will add an if statement to the paragraph to communicate to the user whether they are editing or creating a record. The code below is how we will do this, once again we will be using the [Data provider](doc:data-provider) for this logic. +Budibase now prefers user columns over direct relationships to the users table. -```Text JS -if($("User details data.Rows Length") > 0) { - return "Edit my profile" -} -return "Create my profile" -``` +If you have an older app, you can migrate existing user-table relationship fields to a user column. -## User column +## Migrate existing relationships -With the implementation of the new `User column` eventually custom fields to the user's table will become depreciated. Meaning that you will no longer be able to add custom fields to the user's table. +1. Open the table that contains the user relationship +2. Open the table menu +3. Choose `Migrate to user column` +4. Follow the prompts -The new intended approach will be to create a new table e.g. `Users Metadata` and include all the additional user related information here. Then link the users to their rows within this newly created table. From here you will then be able to easily access additional fields based on the user link created with the User column. \ No newline at end of file +Update any bindings that referenced the old relationship field after the migration. diff --git a/docs/Data/data/views.md b/docs/Data/data/views.md index 2ec3c07bb..438b18230 100644 --- a/docs/Data/data/views.md +++ b/docs/Data/data/views.md @@ -1,6 +1,6 @@ --- title: Views -excerpt: Learn more about views within Budibase +excerpt: Create filtered or grouped views from table data deprecated: false hidden: false metadata: @@ -10,43 +10,17 @@ metadata: next: description: '' --- -Views are virtual tables that present data from a table with a preset filter or grouping. +Use views when you want to present table data with a preset filter, sort order, or grouping. -When you create a View within Budibase, it presents you with all the data from its linked table. This provides you with a canvas to manipulate your data without changing the data within the original table. This is crucial, as it protects your original data. It also allows you to create: +Views are virtual tables. They do not change the underlying data. -1. Filters -2. Sorts (including multi-column sorting) -3. Hide columns +## Create a view -When designing your UI, you can use a View with auto-generated screens, as well as for custom UI development. Say you have a table of Sales employees, and their total sales, you can create a view which gives you the total sales of all Sales employees. You can then reference the data from this View in the *Design* section of Budibase. - -## How to create a new view - -To create a new view, click the `Create view` button, and give it a name. - -{` -
-`}
- -## Filters - -One of the core features of views is the ability to filter rows according to particular criteria. When a Row is filtered, it is not deleted—it's just hidden from the particular view you're using and remains within the table (views are virtual tables!). - -Try adding filters when: - -* You need to focus on rows that meet certain conditions (e.g. Classes between May and June, and taught by Albert Einstein). -* You need to display certain information, to certain people (e.g Each salesperson can only view their own commission). - -### How to create a new filter - -To create a new filter: - -1. Click the `Filter` button -2. Click `Add Filter` -3. Select the Column you would like to filter -4. Select a filter function -5. Type your query -6. Click `Saved` +1. Open the table. +2. Click `Create view`. +3. Give the view a name. +4. Add any filters, sorting, grouping, or hidden columns you need. +5. Save the view. You can also save a filtered table directly as a new view. @@ -114,26 +88,36 @@ We can then *Group by* additional criteria to refine the data further. For examp Adding sales channel to the grouping breaks the counts down by both country and channel. -## Views and View Calculations as Data Sources +Use views when you need to: -The Screens button in the Data toolbar shows where a view or view calculation is currently being used. +* Focus on a subset of rows +* Hide or sort data without changing the source table +* Sort with one or more columns +* Reuse the same filtered dataset in screens or repeaters -Views and View Counts can be used as Data Sources, and manipulated in the same ways. Using a view calculation like "Calculate the Sum of Total Revenue, Group by Country" allows us to find the total revenue of sale per country. This data can then be used in components like **Charts** or **Repeater Blocks**. +## View calculations -Add a Repeater Block, and set the Data Source to the `view total_revenue_by_country`, then set the Sort Column to be Sum Total Revenue, descending, limited to 10. This will show us the top 10 countries by sum total sales revenue. +View calculations let you aggregate data from a table. -Inside the repeater block, add a container and nest inside it 3 Headline components +Supported calculations include: -The repeater example is built from a container with three nested Headline components. +* Average +* Sum +* Minimum +* Maximum +* Count -Set the first headline component to `{{ add New Repeater Block.Row Index 1 }}` - This is taking the Row Index and adding 1 to it. (Index starts counting from Zero, so in order to use row-index as the rankings we must add 1) +Use grouping when you want one result per category instead of a single total. -Set the second headline component to `{{ New Repeater Block.total_revete_by_country.Sum Total Revenue }}` - this fetches the sum total of the revenue. You can then set the third headline component to`{{ New Repeater Block.total_revete_by_country.Country }}` , and just like that we've built a basic leaderboard for Total Revenue by Country. +## Track usage -### Tracking View Usage +Use the **Screens** button in the Data toolbar to see where a view or view calculation is used. -In the Data section, you can use the **Screens** button in the toolbar to see a list of every screen and component where a View or View Calculation is currently being used. This makes it easier to perform impact analysis before modifying or deleting a view. +This helps you understand the impact before changing or deleting it. -Note that while standard Views support **Generate app screen** to automatically create new UI based on your data, this feature is not supported for View Calculations. +## Notes -The finished leaderboard combines the row index, total revenue, and country into a ranked list. +* Views can be used as data sources in the Design section +* View calculations are not supported by Generate app screen +* If you rename or delete a column used by a view filter, update or remove the filter +* Budibase fails closed when a filtered column is no longer valid, so the view returns no rows until it is fixed 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/environment-variables.md b/docs/Data/environment-variables.md index 89c502062..75185754a 100644 --- a/docs/Data/environment-variables.md +++ b/docs/Data/environment-variables.md @@ -1,83 +1,59 @@ --- title: Environment variables 🔒 -excerpt: Configuration for apps which switches per environment +excerpt: Configure values that change by environment deprecated: false hidden: false metadata: title: '' - description: kba_5hgqq + description: '' robots: index 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. - -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. - -## Unlocking environment variables - -If you are using the free tier you will see the following under the environment variables section: - - - -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. - -## 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. - -![](https://files.readme.io/543d5d3-image.png) - -> 🚧 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. - -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. - -![](https://files.readme.io/07c2455-image.png) - -To edit or delete an existing environment variables, click the `Edit` button. - - +Use environment variables when you need different values in development and production. -## Using environment variables in datasources +They are useful for secrets, datasource credentials, and environment-specific endpoints. -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. +## Unlock environment variables -![](https://files.readme.io/013c423-image.png) +Environment variables are locked on the free tier. -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. +Upgrade your plan to use them. -![](https://files.readme.io/a98e757-image.png) +## Create environment variables -Once configured the input fields will be disabled, with the environment variable contained within, as shown below. +1. Open **Settings > Environment** +2. Add a new variable +3. Set the development value +4. Set the production value +5. Save the variable -![](https://files.readme.io/9dd0d24-image.png) +Variable names cannot contain spaces. Use underscores instead. -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. +Values are encrypted and cannot be retrieved after saving. -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. +## Use environment variables in datasources -## Using environment variables in queries +Use environment variables in datasource settings when the connection details change by environment. -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. +After you select a variable, the field is locked to that value. -![](https://files.readme.io/8ee9866-image.png) +## Use environment variables in queries -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. +Use environment variables in query bindings when the value should be shared across requests. -![](https://files.readme.io/0398294-image.png) +Example: -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. +```handlebars +{{ env.env_variable }} +``` -![](https://files.readme.io/d36d61a-image.png) +## Use environment variables in automations -## Using environment variables in automations +Use environment variables in automations for reusable values such as webhook URLs or external service credentials. -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. +## Notes - \ No newline at end of file +* Development and production values are separate +* Publishing pushes the development configuration to production +* Environment variables are available in datasources, queries, and automations where supported diff --git a/docs/Data/pdf-exporting.md b/docs/Data/pdf-exporting.md index 483809175..0d200e102 100644 --- a/docs/Data/pdf-exporting.md +++ b/docs/Data/pdf-exporting.md @@ -1,14 +1,11 @@ --- title: PDF exporting 🔒 -excerpt: >- - The PDF Exporting feature allows you to generate downloadable PDF reports - directly from your Budibase app similar to how you would build standard - screens. +excerpt: Generate downloadable PDF screens from your app deprecated: false hidden: false metadata: title: '' - description: kba_5hgsi + description: '' robots: index next: description: '' @@ -17,41 +14,40 @@ next: slug: screens title: Screens --- -> 📘 Licensing🔒 -> -> The following feature is only available to customers with a **Premium** or **Enterprise** plan. -> -> You can view more details on [our pricing page.](https://budibase.com/pricing/) - -## Creating a PDF Screen - -When creating a new screen, you’ll see a [screen](doc:screens) option called PDF at the end of the screen list. Select this option to create a screen specifically for generating PDF documents. - - +Use PDF exporting when you want users to download a screen as a PDF. -Once selected, you’ll be taken to a new screen where you can begin creating your PDF. This includes standard grid functionality, allowing you to arrange content flexibly. +This feature is available on Premium and Enterprise plans. -## Building Your PDF +## Create a PDF screen -Within the PDF screen, you can use Budibase components such as tables, text, images, and more, just as you would on a regular screen. You can connect [data providers](doc:data-provider) to populate your report with dynamic content using Bindings. This enables you to generate personalised or context-specific PDFs for your users. +1. Create a new screen +2. Choose `PDF` +3. Add the components you want to appear in the document +4. Bind any data you need +5. Save the screen - +## Build the PDF -## Styling and Layout +Use standard Budibase components such as: -You can fully customise the layout and design of the PDF using Budibase’s grid functionality. [Components](doc:components) will be rendered in the exported file as on the PDF. +* Tables +* Text +* Images +* Data providers - +The PDF screen uses the same grid layout as a regular screen. -## Customisation options +## Configure the download experience -In addition to adding Budibase components to your PDF screens, you can customise the title and button text used for the PDF download experience. These options are available in the screen’s settings panel. +Use the screen settings to set: -Both fields support Bindings, allowing you to tailor the PDF to the logged-in user or any other context-specific data. For example, you can include the user's name or role in the title or adjust the button text based on permissions. +* PDF title +* Download button text -* **PDF Title**: This is displayed at the top of the screen when users visit the PDF page. It also determines the filename of the downloaded PDF. -* **Button Text**: This controls the label shown on the PDF download button. +Both fields support bindings, so you can make the output depend on the current user or app context. -These fields help tailor the user experience and provide context-specific naming for your reports. +## Notes - \ No newline at end of file +* The PDF title also becomes the filename of the downloaded file +* Use the same layout patterns you would use on a regular screen +* Keep the report layout simple if you want the exported PDF to stay readable diff --git a/docs/Data/rest/index.md b/docs/Data/rest/index.md index fec63aa89..3a8f925cc 100644 --- a/docs/Data/rest/index.md +++ b/docs/Data/rest/index.md @@ -26,12 +26,12 @@ next: slug: rest-variables title: REST Variables --- -Budibase REST integrations are configured from **Workspace Settings > Connections > APIs**. +Use the REST data source when you want Budibase to connect to an external API. -A REST integration has two layers: +REST setup has two parts: -* **Connection-level config** in Settings (auth, base URL, shared headers/variables) -* **Query-level config** in API Editor (method, path, body, bindings, pagination, transformer, projects) +* **Connection settings** in **Workspace Settings > Connections > APIs** +* **Query settings** in the API Editor ## Create a REST connection @@ -46,7 +46,7 @@ A REST integration has two layers: 7. Add any required shared headers/URL params/static variables 8. Click **Save** -## Connection tabs reference +## Connection tabs | Tab | Purpose | Typical fields | | :-- | :-- | :-- | @@ -54,23 +54,21 @@ A REST integration has two layers: | Credentials | Shared request defaults | Base URL, URL parameters, headers, static variables | | Advanced | Transport behavior | Reject unauthorized, Download images | -## Open the API Editor and create your first query +## Create a query -You can start query creation from either path below: - -1. In the API builder sidebar, click **New API** to start a draft query -2. In Settings, open a saved connection and click **Open in API Editor** -3. Select or create the connection for your draft query -4. Set method and endpoint path -5. Add required params/headers/body -6. Pick auth config if needed +1. Open the API builder sidebar and click **New API** +2. Or open an existing connection and click **Open in API Editor** +3. Select or create the connection +4. Set the method and endpoint path +5. Add any required params, headers, body fields, or bindings +6. Select an auth config if needed 7. Click **Send** -8. Review response and schema +8. Review the response and schema 9. Click **Save Query** ## Common migration notes (old to new UI) -* Older docs and workflows may reference **APIs** or **datasources** from legacy menus +* Older docs may reference **APIs** or **datasources** from legacy menus * Current workflow for REST setup starts in **Settings > Connections > APIs** * Query authoring still happens in the API Editor via **Open in API Editor** diff --git a/docs/Data/rest/rest-authentication.md b/docs/Data/rest/rest-authentication.md index 138678783..34c5d96db 100644 --- a/docs/Data/rest/rest-authentication.md +++ b/docs/Data/rest/rest-authentication.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -REST authentication is configured at the **connection** level and selected at the **query** level. +Configure REST authentication on the connection, then select it on each query. ## Supported auth types in Connections @@ -21,28 +21,28 @@ REST authentication is configured at the **connection** level and selected at th ## Configure authentication on a connection 1. Open **Settings > Connections > APIs** -2. Open your connection +2. Open the connection 3. Go to **Authentication** 4. Click **Add authentication** -5. Select auth type -6. Fill required fields -7. Click **Save** +5. Select the auth type +6. Fill in the required fields +7. Save the auth config You can store multiple auth configs on one connection. ## Select auth in a query -1. Open connection in **API Editor** -2. Open/create a query +1. Open the connection in **API Editor** +2. Open or create a query 3. Select auth config for the query 4. Click **Send** -5. Save query +5. Save the query ## Auth configuration guidance -* Create separate auth entries per environment when needed. -* Use clear names (`Prod Bearer`, `Staging OAuth2`). -* Re-test all affected queries after editing a shared auth config. +* Create separate auth entries per environment when needed +* Use clear names such as `Prod Bearer` and `Staging OAuth2` +* Re-test affected queries after editing a shared auth config ## Using SSO token bindings diff --git a/docs/Data/rest/rest-bindings.md b/docs/Data/rest/rest-bindings.md index b582b5b06..90f8f0920 100644 --- a/docs/Data/rest/rest-bindings.md +++ b/docs/Data/rest/rest-bindings.md @@ -10,13 +10,9 @@ metadata: next: description: '' --- -Bindings pass runtime values into REST queries. +Use bindings to pass runtime values into REST queries. -Use bindings for values that vary by user, row, form input, URL parameter, or action context. - -## Binding syntax - -Use handlebars syntax: +Bindings are useful for values that change by user, row, form input, URL parameter, or action context. ```handlebars {{ bindingName }} @@ -25,10 +21,10 @@ Use handlebars syntax: ## Create a binding in a query 1. Open a query in API Editor -2. Add a value in URL/Params/Headers/Body using binding syntax +2. Add a value in the URL, params, headers, or body using binding syntax 3. Define binding name and default value -4. Click **Send** to test defaults -5. Save query +4. Click **Send** to test the default +5. Save the query ## Where bindings can be used @@ -38,9 +34,9 @@ Use handlebars syntax: * Request body * Transformer scripts -## Example: filtered list query +## Example -Query goal: return records by status. +Return records by status. 1. Create a `GET` query for the list endpoint 2. Add query param `status` @@ -52,8 +48,6 @@ Query goal: return records by status. ## Passing bindings from forms -Typical flow: - 1. Add form fields 2. Configure button action **Execute query** 3. Map form values to query bindings @@ -62,16 +56,16 @@ Typical flow: ## Binding design guidelines -* Use descriptive names (`userId`, `status`, `startDate`). -* Set safe defaults for optional values. -* Avoid reusing one binding name for different concepts. -* Validate string/number/date formatting expected by API. +* Use descriptive names such as `userId`, `status`, and `startDate` +* Set safe defaults for optional values +* Avoid reusing one binding name for different concepts +* Match the string, number, or date format expected by the API ## Troubleshooting -* Binding appears literal in request: syntax not parsed correctly -* Value missing at runtime: no input mapped in action -* Wrong filter result: default value taking precedence unexpectedly +* Binding appears literal in request: syntax is not parsed correctly +* Value missing at runtime: no input is mapped in the action +* Wrong filter result: the default value is taking precedence ## Related guides diff --git a/docs/Data/rest/rest-example.md b/docs/Data/rest/rest-example.md index ba2ff2ee5..698f7c1f9 100644 --- a/docs/Data/rest/rest-example.md +++ b/docs/Data/rest/rest-example.md @@ -6,17 +6,17 @@ hidden: false metadata: robots: index --- -This tutorial builds a simple users app backed by a REST API with read/create/update workflows. +This tutorial builds a simple users app backed by a REST API. ## Target architecture * One REST connection (`Users API`) * Four queries (`getUsers`, `getUser`, `createUser`, `updateUser`) -* One table view + two side-panel forms +* One table view and two side-panel forms ## Part 1: Prepare sample API -1. Create a sample endpoint (for example MockAPI) +1. Create a sample endpoint, such as MockAPI 2. Add fields: * `id` * `name` @@ -27,10 +27,10 @@ This tutorial builds a simple users app backed by a REST API with read/create/up ## Part 2: Create connection 1. Open **Settings > Connections > APIs** -2. Click **Add connection > Create custom** -3. Set display name to `Users API` -4. In **Credentials**, set **Base URL** -5. Save +2. Click **Add connection** and choose **Create custom** +3. Set the display name to `Users API` +4. In **Credentials**, set the base URL +5. Save the connection 6. Click **Open in API Editor** ## Part 3: Create CRUD queries @@ -46,7 +46,7 @@ For each query: 1. Set method and path 2. Configure bindings -3. Configure body for write queries +3. Configure the body for write queries 4. Click **Send** 5. Save query @@ -70,9 +70,9 @@ For each query: ## Part 5: Edit existing user -1. Add edit side panel with form (`name`, `address`) +1. Add an edit side panel with a form for `name` and `address` 2. Set default values from selected-row state -3. Add **Update** button +3. Add an **Update** button 4. Button actions: * Execute query `updateUser` * Map `id`, `name`, `address` @@ -82,9 +82,9 @@ For each query: ## Part 6: Create new user -1. Add **Add new user** button -2. Open create side panel with required fields -3. Add **Save** button +1. Add an **Add new user** button +2. Open a create side panel with the required fields +3. Add a **Save** button 4. Button actions: * Execute query `createUser` * Refresh table @@ -95,15 +95,15 @@ For each query: ## Validation checklist * Query tests return expected response codes -* Table loads initial data -* Edit flow updates row and refreshes UI -* Create flow inserts row and refreshes UI +* The table loads initial data +* The edit flow updates the row and refreshes the UI +* The create flow inserts the row and refreshes the UI * Error responses surface user-visible notifications ## Common improvements -* Add delete query/action (`DELETE /users/{{id}}`) -* Add client-side search/filter +* Add a delete query and action (`DELETE /users/{{id}}`) +* Add client-side search and filtering * Add form validation rules before execute-query actions ## Related guides diff --git a/docs/Data/rest/rest-oauth2.md b/docs/Data/rest/rest-oauth2.md index e9bb84b8a..11fcdb0aa 100644 --- a/docs/Data/rest/rest-oauth2.md +++ b/docs/Data/rest/rest-oauth2.md @@ -14,9 +14,9 @@ next: slug: rest title: REST API --- -Budibase supports OAuth2 in REST connections using **Client Credentials**. +Use OAuth2 when your REST connection needs machine-to-machine access. -This is intended for machine-to-machine API access. +Budibase supports OAuth2 in REST connections using **Client Credentials**. ## Required OAuth2 fields @@ -33,20 +33,20 @@ This is intended for machine-to-machine API access. ## Configure OAuth2 in a connection 1. Open **Settings > Connections > APIs** -2. Open/create a connection +2. Open or create a connection 3. Go to **Authentication** 4. Click **Add authentication** 5. Choose **OAuth2** type 6. Enter required fields -7. Save +7. Save the auth config ## Use OAuth2 in queries 1. Click **Open in API Editor** -2. Open/create query -3. Select OAuth2 config in query auth settings +2. Open or create a query +3. Select the OAuth2 config in the query auth settings 4. Click **Send** -5. Save query +5. Save the query ## Example (Spotify) @@ -59,10 +59,10 @@ Use your provider-issued client ID and client secret. | Error | Typical cause | Action | | :-- | :-- | :-- | -| `invalid_client` | Bad client ID/secret | Re-copy credentials from provider | +| `invalid_client` | Bad client ID or secret | Re-copy credentials from the provider | | `unsupported_grant_type` | Wrong grant configured | Set Client Credentials | -| `invalid_scope` | Scope format/value invalid | Match provider scope syntax | -| API call still unauthorized | Wrong auth config selected in query | Re-select auth config and resend | +| `invalid_scope` | Scope format or value invalid | Match the provider scope syntax | +| API call still unauthorized | Wrong auth config selected in query | Re-select the auth config and resend | ## Related guides diff --git a/docs/Data/rest/rest-pagination.md b/docs/Data/rest/rest-pagination.md index 1843ce872..846191fa3 100644 --- a/docs/Data/rest/rest-pagination.md +++ b/docs/Data/rest/rest-pagination.md @@ -6,7 +6,7 @@ hidden: false metadata: robots: index --- -Use pagination when an API returns list data in pages and you need reliable forward/backward navigation in app components. +Use pagination when an API returns list data in pages. ## Before you start @@ -24,23 +24,23 @@ Use pagination when an API returns list data in pages and you need reliable forw ## Configure query pagination -1. Open query in API Editor +1. Open the query in API Editor 2. Enable pagination -3. Select pagination type and location -4. Map request field names -5. Map response field path for continuation token/page value -6. Click **Send** repeatedly to validate progression -7. Save query +3. Select the pagination type +4. Map the request field names +5. Map the response field path for the next page value +6. Click **Send** to validate progression +7. Save the query ## Cursor-specific guidance -* Map to the API field that returns the **next** cursor token -* Verify token comes from raw response path expected by Budibase -* Ensure stable sort order to avoid duplicates/missed rows +* Map to the API field that returns the next cursor token +* Verify the token comes from the raw response path expected by Budibase +* Ensure stable sort order to avoid duplicate or missing rows ## Use paginated query in components -1. Bind query (or data provider) to table/repeater +1. Bind the query or data provider to a table or repeater 2. Enable component pagination controls where applicable 3. Validate first, next, previous, and final page behavior @@ -48,10 +48,10 @@ Use pagination when an API returns list data in pages and you need reliable forw | Symptom | Likely cause | Fix | | :-- | :-- | :-- | -| Always shows page 1 | Request page/cursor field not mapped | Re-check request field mapping | -| Stops after first page | Response continuation path incorrect | Correct response field path | -| Duplicate rows across pages | Non-deterministic API sorting | Add stable sort in API query | -| Missing rows | Offset/page-size mismatch | Verify API math and defaults | +| Always shows page 1 | Request page or cursor field not mapped | Re-check request field mapping | +| Stops after first page | Response continuation path incorrect | Correct the response field path | +| Duplicate rows across pages | Non-deterministic API sorting | Add stable sort in the API query | +| Missing rows | Offset or page-size mismatch | Verify API math and defaults | ## Related guides diff --git a/docs/Data/rest/rest-queries.md b/docs/Data/rest/rest-queries.md index a065b2449..c86432bf4 100644 --- a/docs/Data/rest/rest-queries.md +++ b/docs/Data/rest/rest-queries.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -REST queries are configured in API Editor for a saved REST connection. +Create REST queries in the API Editor for a saved REST connection. ## Create a query @@ -47,7 +47,7 @@ To protect your security, Budibase automatically sanitizes this preview: | Area | What to configure | Notes | | :-- | :-- | :-- | | Method | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` | Must match endpoint contract | -| URL/Path | Endpoint path or full URL | Usually path + connection base URL. Full URLs require a protocol prefix and must match the datasource origin. | +| URL/Path | Endpoint path or full URL | Usually path plus the connection base URL. Full URLs require a protocol prefix and must stay on the datasource origin. | | Params | Query-string key/value pairs | Supports bindings | | Headers | Request headers | Supports bindings and shared defaults | | Body | Payload for write/query APIs | Use valid JSON/XML/Text as required | @@ -66,9 +66,9 @@ Before first use: Before production use: -1. Test with realistic runtime bindings -2. Validate empty-state response behavior -3. Validate error-state handling in app actions +1. Test with realistic runtime bindings. +2. Validate empty-state response behavior. +3. Validate error-state handling in app actions. ## Transformer example (flatten nested response) @@ -92,14 +92,13 @@ After applying a transformer: ## Common issues -* **Missing protocol**: Full URLs must include `http://` or `https://` to be valid. The **Send** button will be disabled and a warning displayed if the protocol is missing. -* `401/403`: wrong or missing auth config. -* `404`: wrong path or base URL. -* `400`: REST query path must remain on the datasource origin. This occurs if an absolute URL or dynamic binding targets a different origin than the one configured in the datasource. -* `400`: Redirect to a different origin is not permitted. Cross-origin redirects are blocked for security to prevent datasource credentials from being sent off-origin. -* `400/422`: request payload does not match API contract. -* Empty rows with `200`: binding values not populated as expected. -* Schema mismatch in app: query changed but app bindings not updated. +* **Missing protocol**: Full URLs must include `http://` or `https://` to be valid. +* `401/403`: wrong or missing auth config +* `404`: wrong path or base URL +* `400`: the query must stay on the datasource origin. Cross-origin redirects are blocked. +* `400/422`: request payload does not match the API contract +* Empty rows with `200`: binding values were not populated as expected +* Schema mismatch in app: the query changed but app bindings were not updated ## Related guides diff --git a/docs/Data/rest/rest-query-import.md b/docs/Data/rest/rest-query-import.md index 791957d7b..fef9323b8 100644 --- a/docs/Data/rest/rest-query-import.md +++ b/docs/Data/rest/rest-query-import.md @@ -10,7 +10,7 @@ metadata: next: description: '' --- -Import lets you create multiple REST queries at once from API definitions. +Use query import to create multiple REST queries at once from API definitions. ## Supported formats @@ -28,7 +28,7 @@ Import lets you create multiple REST queries at once from API definitions. * **File**: upload spec file * **Raw text**: paste spec text 6. Click **Import** -7. Review imported queries +7. Review the imported queries 8. Open key queries and click **Send** 9. Save any adjusted queries @@ -43,10 +43,10 @@ When importing from a URL, Budibase applies the same security hardening and vali 1. Rename generic query names 2. Confirm auth config per query -3. Confirm base URL/path compatibility with your environment +3. Confirm base URL and path compatibility with your environment 4. Add or correct bindings for runtime values 5. Confirm request body formats -6. Validate schema output after first successful run +6. Validate the schema output after the first successful run ## Importing from Postman @@ -59,9 +59,9 @@ Postman collections should be converted to OpenAPI first. ## Common import issues -* Unknown/unsupported fields in spec: simplify or clean OpenAPI before import -* Imported query fails auth: map to correct connection auth config -* Paths duplicate base URL: correct path/full URL handling +* Unknown or unsupported fields in the spec: simplify or clean the OpenAPI file before import +* Imported query fails auth: map to the correct connection auth config +* Paths duplicate the base URL: correct the path or full URL handling ## Related guides diff --git a/docs/Data/rest/rest-templates.md b/docs/Data/rest/rest-templates.md index 048ca9b99..cf930d0cb 100644 --- a/docs/Data/rest/rest-templates.md +++ b/docs/Data/rest/rest-templates.md @@ -1,22 +1,25 @@ --- -title: REST Templates +title: REST templates +excerpt: Start REST connections from a template deprecated: false hidden: false metadata: + title: '' + description: '' robots: index --- REST templates provide connection starters and allow you to reuse OpenAPI specifications across your workspace. You can find them under **Settings > APIs > API Specs**. -Templates are useful when you want known endpoint structures, default headers, and static variables preloaded. +Templates can include endpoint structure, default headers, static variables, and suggested auth. ## What templates usually include Templates can provide: * Base URL defaults -* Suggested endpoint actions -* Required static variables (for example owner/repo, project identifiers) -* Suggested auth pattern +* Suggested endpoints +* Required static variables such as owner, repo, or project identifiers +* Suggested auth patterns * Template collections with child APIs for the same provider Template content can still be edited after creation. @@ -54,8 +57,8 @@ Once imported, your spec will appear in the **Imported API specs** section, wher Some template collections include child APIs and use one of two connection modes: -* **Shared**: child APIs share connection settings (for example base URL and auth). You choose the child API when creating or editing queries. -* **Independent**: each child API is treated as its own connection choice. You select the child API when creating the connection. +* **Shared**: child APIs share connection settings such as base URL and auth +* **Independent**: each child API is treated as its own connection choice ## Validate the template connection @@ -69,10 +72,10 @@ Some template collections include child APIs and use one of two connection modes ## Troubleshooting template setup * `401/403` after template import: auth is missing or invalid -* `404` on template query: base URL/path mismatch for your target service -* Empty response: required bindings not set or wrong defaults -* Template variable locked/required: ensure value exists in **Credentials > Static Variables** -* Missing endpoint list for a child API: confirm the correct child API is selected for the connection or query +* `404` on a template query: the base URL or path does not match the target service +* Empty response: required bindings are missing or have the wrong defaults +* Template variable locked or required: ensure the value exists in **Credentials > Static Variables** +* Missing endpoint list for a child API: confirm the correct child API is selected ## When to use Create custom instead diff --git a/docs/Data/rest/rest-variables.md b/docs/Data/rest/rest-variables.md index 8f01eb850..444a4cc54 100644 --- a/docs/Data/rest/rest-variables.md +++ b/docs/Data/rest/rest-variables.md @@ -10,29 +10,29 @@ metadata: next: description: '' --- -REST variables let you reuse values across multiple queries in the same connection. +Use REST variables to reuse values across multiple queries in the same connection. ## Variable types * **Static variables**: manually defined constant values -* **Dynamic variables**: values extracted from response headers/body +* **Dynamic variables**: values extracted from response headers or body data ## Static variables Use static variables for shared constants: * API version -* Host/tenant identifiers -* Shared language/region codes +* Host or tenant identifiers +* Shared language or region codes * Reused query fragments ### Create static variables 1. Open **Settings > Connections > APIs** -2. Open your connection +2. Open the connection 3. Go to **Credentials** 4. Add entries under **Static Variables** -5. Click **Save** +5. Save the connection ## Dynamic variables @@ -40,25 +40,25 @@ Use dynamic variables to chain queries. Common patterns: -* Auth query returns token used by later queries -* Lookup query returns ID used by update/delete query +* Auth query returns a token used by later queries +* Lookup query returns an ID used by an update or delete query * Cursor response field reused for pagination calls ### Create dynamic variables -1. Open connection in API Editor +1. Open the connection in API Editor 2. Run a source query -3. Create dynamic variable from response header or schema field. -4. Name the variable clearly. -5. Save query changes. +3. Create a dynamic variable from a response header or schema field +4. Name the variable clearly +5. Save the query changes ### Edit dynamic variables -1. Open connection in **Settings > Connections > APIs**. -2. Go to **Credentials**. -3. Open **Dynamic Variables**. -4. Update expression/path. -5. Save and retest downstream queries. +1. Open the connection in **Settings > Connections > APIs** +2. Go to **Credentials** +3. Open **Dynamic Variables** +4. Update the expression or path +5. Save and retest downstream queries ## Expression examples @@ -87,9 +87,9 @@ Use **bindings** when values are supplied per execution. ## Common issues -* Variable resolves empty: source query response shape changed. -* Variable points to object instead of scalar: expression path too broad. -* Query retries/fails with variable errors: source variable query not returning expected value. +* Variable resolves empty: the source query response shape changed +* Variable points to an object instead of a scalar: the expression path is too broad +* Query retries or fails with variable errors: the source variable query is not returning the expected value ## Related guides 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..065b73cb8 --- /dev/null +++ b/docs/Data/sql-workflow.md @@ -0,0 +1,83 @@ +--- +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 after you connect a SQL datasource. + +## 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 setup: + +* [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 setup later. + +## Define relationships + +Add relationships for the joins you want to reuse in screens and bindings. + +Use: + +* One-to-many for foreign keys +* Many-to-many when you have a join table + +If Budibase rejects a join table, fix the source constraints 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 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/Data/transformers.md b/docs/Data/transformers.md index 978eed97d..5141c004d 100644 --- a/docs/Data/transformers.md +++ b/docs/Data/transformers.md @@ -1,6 +1,6 @@ --- title: Transformers -excerpt: Using Budibase query transformers +excerpt: Shape query results before they reach your app deprecated: false hidden: false metadata: @@ -10,100 +10,62 @@ 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 a transformer when a query returns data in a shape that needs to be simplified or reshaped before it reaches your app. -> 📘 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). +Transformers are written in JavaScript. -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. +## What transformers receive -## Accessing bindings +Transformers can access: -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. +* `data` - the query results +* `params` - the bindings passed to the query - +## Create a transformer -## Tutorial +1. Create a datasource and query +2. Open the transformer editor for the query +3. Write JavaScript to reshape the response +4. Send the query to test the output +5. Save the query -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. +## Return shape -When you first create a query you'll see the transformer code editor in its own section, as seen below. +A transformer must return an array. -![](https://files.readme.io/d0712b5-transformers.png "transformers.png") +If you return a single object, Budibase wraps it as one row. -> 📘 -> -> 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. +If you return an array of values, Budibase treats each value as a row. -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: +## Example -1. Setup a REST data source, with our URL set to +Use a transformer to count breweries by state. -``` -https://api.openbrewerydb.org -``` - -2. Created a query and set the path to *breweries* -3. Ran the query to see the schema - -The schema for this query appears as below: - - - -Using this information we can now write the transformer function that will be used. Initially we just want to write a function which will: - -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. - - - -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. +```javascript +const counts = {} -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. - - - -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! - -## 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: - -```json -{ - "a": 1, - "b": 2, +for (const brewery of data) { + const state = brewery.state + counts[state] = (counts[state] || 0) + 1 } -// Budibase will convert this to: -[ - { "a": 1, "b": 2 } -] +return Object.entries(counts).map(([state, count]) => ({ + state, + count, +})) ``` -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: +You can also add derived fields, such as a flag URL, before returning the final rows. -```json -// outputs [ "a", "b" ] -return Object.keys({ "a": 1, "b": 2 }) - -// Budibase will break this array into the following response: -[ - { "value": "a" }, - { "value": "b" }, -] -``` +## Common uses -If we were to take the above example and add it to a table within Budibase it would appear as seen below. +* Flatten nested API responses +* Count or group records +* Add derived fields +* Convert API data into a table-friendly shape -![](https://files.readme.io/fadc6e2-image.png) +## Notes -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. +* Keep the query working first, then refine the transformer +* Use `params` for binding values passed into the query +* Re-test the query after changing the transformer 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: '' --- -
- -`} - -## 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. - -This guide will demonstrate how to allow an End User \<\{` -Challenge:
-★★★☆☆ -`} - -*** - -## Steps - -1. In the Data section, create a new table using Budibase DB, name it Distance -2. - - Add two columns to your events 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. - - -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. - - -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. - - +## Build the form - Add 3 options: +1. Add a create form for the table +2. Add an options picker for the unit field +3. Use custom options for the supported units - | 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: +## Calculate the value - ```javascript JavaScript - const previousUnit = $("New Form.Fields.units"); - const newUnit = $("Field Value"); - const previousDistance = $("New Form.Fields.distance") +1. Add an `On change` action to the unit picker +2. Read the previous unit and the new unit +3. Recalculate the value with `Update Field Value` - return (previousDistance * (previousUnit / newUnit)).toFixed(4); - ``` +## Save the row -> 📘 Previous and new values on change -> -> It's worth bringing attention to the use of the options picker bindings. -> -> `$("New Form.Fields.UnitPicker")` will get the value of the field before the change occurs. -> -> `$("Field Value")` is the new value that will update the field when the *on change* finishes. +1. Add a save button +2. Save the form data +3. Multiply the entered value by the selected unit factor before saving +4. Clear the form after saving -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. +## Why this works - +The user sees the unit they selected, but the table always stores one consistent value. -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 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. - -![](https://files.readme.io/88a94978f705527876863326f28c6b196c8d4ed08d3186e9110ff8906ccaec3d-image.png) - -
- -11. Add another On Click action to validate your 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. - -![](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. - - - -
- -
- -*** - -## Workspace export +## Workspace export *Downloads may take a few seconds.* @@ -122,19 +47,17 @@ This guide will demonstrate how to allow an End User \<\ Download -`} \ 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..a84cb3f22 100644 --- a/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md +++ b/docs/Getting started/examples-and-guides/cascading-dropdown-filters.md @@ -10,83 +10,38 @@ metadata: next: description: '' --- -## Try it out! - -{` - -`} +Use cascading dropdown filters when one picker should limit the values in another. ## Scenario -You have a **Country** table and a **City** table, with a relationship defined between them 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. - -{` -Challenge:
-★★☆☆☆ -`}
- -*** - -## Steps - -1. `Add component`: **Form** -2. In the Settings Panel, set *Schema* to 'Country' - - +This guide uses a `Country` table and a related `City` table. -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* +The country picker controls which cities appear in the city picker. - +## Build the form -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' +1. Add a [Form](doc:forms) +2. Set the form schema to `Country` +3. Add a [Data provider](doc:data-provider) for the country table +4. Add an [Options picker](doc:option-picker) for the country field +5. Add a [Relationship picker](doc:filter-by-relationships) for the cities field - +## Filter the cities -11. `Add component`: **Relationship Picker** and select the '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. Open the relationship picker filters +2. Match the city rows to the selected country +3. Disable the city picker until a country is selected +4. Clear the city value when the country changes - +## Why this matters -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` +This keeps the second picker limited to valid values and avoids stale selections. - +## Try it out -> 👍 Layout -> -> Use [Field group layouts](https://docs.budibase.com/docs/field-groups#layout) or [Containers](doc:container) to align the pickers as desired. -> -> 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 -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` - - - -
- -*** - -## App export - -*Downloads may take a few seconds.* +{` + +`} {` @@ -96,19 +51,17 @@ Your form will have an [Options picker](doc:option-picker) that will allow the e -`} \ No newline at end of file +`} 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..35bbbf6d4 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 @@ -13,143 +13,33 @@ metadata: next: description: '' --- -> 🚧 Heavy JavaScript usage -> -> This guide uses a lot of JavaScript, which might be difficult to restructure if you have limited coding experience. +Use this pattern when you need a basic audit trail for row updates. -## Scenario +When a user updates a row in `Patients`, an automation compares the old and new values and logs each change in `Patient audit`. -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. +## Build the tables -Use this to: +Create `Patients` and `Patient audit`. -* 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 +Store the field name, old value, new value, action type, related patient, and timestamp in the audit table. -{` -Challenge:
-★★★★☆ -`}
+## Build the screen + +Generate a table screen for `Patients`. + +This gives you the list screen plus the create and edit forms. -## Steps - -1. Create the tables\ - In the Data area, create the following two tables: - - 1. Patients - 1. First\_name - type text - 2. Last\_name - type text - 3. DOB - type date - 4. Phone - type text - 5. Email - type text - 6. Address - type long form text - 7. Last\_visit\_date - type date - 8. Audit\_logs - relationship (one to many) - 2. Patient audit - - 1. Column\_name (field that changed) - type text - 2. Old\_value - type text - 3. New\_value - type text - 4. Action\_type (e.g. "UPDATE") - type single select - 5. Patient - type relationship (many to one) - 6. Changed\_at - type text and set the default value to `{{ now }}` - - -2. Generate screens - - 1. Go to the Design area - 2. Click the plus to add a new screen - 3. Select Table - - - 4. Select Patients as the source for this new screen - - - 5. Then select New screen, this will generate the following; - - - - 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\ - Navigate to the Automation area and create a new automation: - - 1. Click the `Updated by` trigger type for your automation - - - 2. Select Patients as the source table it will watch for changes - 3. Add a new step called JavaScript - - - 4. Copy the below code into the automation step - - ```javascript - const oldRow = $("trigger.oldRow"); - const newRow = $("trigger.row"); - - const fieldsToCheck = [ - "First_name", "Last_name", "DOB", - "Phone", "Email", "Address", "Last_visit_date" - ]; - - const changedFields = fieldsToCheck.reduce((changes, field) => { - const oldVal = oldRow[field]; - const newVal = newRow[field]; - const normOld = normalize(oldVal); - const normNew = normalize(newVal); - - if (!(normOld == null && normNew == null) && normOld !== normNew) { - changes.push({ - Column_name: field, - Old_value: oldVal == null ? "" : String(oldVal), - New_value: newVal == null ? "" : String(newVal), - Action_type: "UPDATE", - _id: $("trigger.row")._id - }); - } - return changes; - }, []); - - return changedFields; - - function normalize(v) { - if (v == null) return null; - if (v instanceof Date) return v.toISOString(); - if (typeof v === "string") { - const d = Date.parse(v); - return !isNaN(d) ? new Date(d).toISOString() : v.trim(); - } - return v; - } - - ``` - - This returns an array of changed fields in the format expected by the audit table. - 5. Add a Create row step with the source set to the Patient audit table - - - - 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 | - | :----------- | :------------------------------------ | - | Column\_name | `{{ loop.currentItem.Column_name }}` | - | Old\_value | `{{ loop.currentItem.Old_value }}` | - | New\_value | `{{ loop.currentItem.New_value }}` | - | Action\_type | `{{ loop.currentItem.Old_value }}` | - | Patient | `{{ loop.currentItem.\_id }}` | - -## Example - -**Automation Output** +## Build the automation - +1. Trigger the automation when a `Patients` row is updated +2. Add a JavaScript step to compare the old and new row values +3. Return one item for each changed field +4. Loop over the returned items +5. Create one audit row per changed field -**Audit logs in app** +## Why this works - +Each update produces one audit row per changed field, so you can review the history later. ## App export @@ -161,19 +51,17 @@ Use this to: `} 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..9c6bb509d 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 @@ -1,5 +1,5 @@ --- -title: Filter table with options picker +title: Filter a table with an options picker excerpt: Filter by region dropdown or country name deprecated: false hidden: false @@ -10,66 +10,31 @@ metadata: next: description: '' --- -## Try it out! - -{` - -`} +Use an options picker when the table should filter from a fixed list instead of free-text search. ## 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). - -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. - -{` -Challenge:
-★★☆☆☆ -`}
- -*** +This guide filters a sales table by region. -## Steps +You can adapt the same pattern for any field with a fixed set of values. -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. +## Build the screen - 1. -3. You may need to reject columns that were unsuccessfully imported, and select a Display Column. +1. Add a [Table](doc:table) for the sales data +2. Add a [Form](doc:forms) +3. Add an [Options picker](doc:option-picker) inside the form +4. Set the picker field and label to `Region` +5. Use custom options for the allowed values - ![](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. +## Add the filter - -7. Next, 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. +1. Open the table settings +2. Add a filter on the region column +3. Bind the filter value to the options picker field - ![](https://files.readme.io/ccceae83f7577e14b24240c57bff967d28d08b3c5cf22d9ae50a8c565ba02864-image.png) -10. Click Define options: `Add Option` for each region: +## Multi-select variant - 1. Australia and Oceania - 2. Central America and the Caribbean - 3. Middle East and North Africa - 4. Sub-Saharan Africa - 5. Asia - 6. North America - 7. Europe -11. Head back 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. - -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. - -![](https://files.readme.io/1938cfa4d4d6644cd7212336107828c04d4b3eece342f22c048b903691f97e99-image.png) - -
- -*** +Use a [Multi-select picker](doc:multi-select-picker) and an `Is In` filter when users should choose more than one region. ## App export @@ -83,19 +48,17 @@ You may also decide that you want to filter by multiple region, for example when -`} \ No newline at end of file +`} diff --git a/docs/Getting started/examples-and-guides/index.md b/docs/Getting started/examples-and-guides/index.md index e26090222..e6e4c053c 100644 --- a/docs/Getting started/examples-and-guides/index.md +++ b/docs/Getting started/examples-and-guides/index.md @@ -10,58 +10,25 @@ metadata: next: description: '' --- -To help you adopt Budibase quicker and uncover what's possible, we've dedicated this documentation section to guides, examples, templates, and more. +This section collects step-by-step guides, example apps, templates, and reference material. ## Guides -Within this section you will find a list of step-by-step tutorials for building common workflows within Budibase. +The guides in this section follow a common pattern: -Each follows a common consistent layout as follows: - -| Section | Description | -| :---------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Try it out! | Displays an interactive [Embedded Budibase app](doc:embedded-app) so that you can quickly see if this use-case is relevant to the problem you are trying to solve | -| Scenario | A description of what the recipe will entail, the problem being solved, and a star guide as a rough estimate to the challenge involved in implementing | -| Steps | Direct steps including screenshots. Most guides will assume your [Datasource](doc:data-sources) has been configured | -| App export | A download link for the [App export](https://docs.budibase.com/docs/export-and-import-apps) so that you can explore the recipe further | +* `Try it out!` shows an embedded example app +* `Scenario` explains the problem the guide solves +* `Steps` walks through the build +* `App export` provides a downloadable example ## Blogs and discussions -If you can't find the recipe you are looking for, there are a number of blogs and Github discussions you can explore. - -| Title | Guide | -| :----------------------------------------------------- | :----------------------------------------------------------------------------------------------- | -| How to build a CRUD app with Budibase and Next.js | [Blog](https://budibase.com/blog/building-a-crud-app-with-budibase-and-next.js/) | -| Creating related rows in more than one table | [Github answer](https://github.com/Budibase/budibase/discussions/4998) | -| Access child form fields data from the parent | [Github answer](https://github.com/Budibase/budibase/discussions/5119) | -| Add a linking/lookup table | [Github answer](https://github.com/Budibase/budibase/discussions/5299) | -| Appending a relationship | [Github answer](https://github.com/Budibase/budibase/discussions/7888#discussioncomment-3760973) | -| Navigating to detail screen for multiple selected rows | [Github answer](https://github.com/Budibase/budibase/discussions/8759#discussioncomment-4207094) | -| Filtering related data on selected rows | [Github answer](https://github.com/Budibase/budibase/discussions/7419) | -| Verify row is unique before saving | [Github answer](https://github.com/Budibase/budibase/discussions/6294#discussioncomment-2938345) | -| Edit form fields inline | [Github answer](https://github.com/Budibase/budibase/discussions/9536) | -| Conditional table cell - setting text color | [Github answer](https://github.com/Budibase/budibase/discussions/10204) | -| How to build a public form | [Blog](https://budibase.com/blog/public-forms-how-to-build-them-in-minutes/) | - -## Build an internal app in 15 minutes - -[@Jamesqquick](https://twitter.com/jamesqquick) - - +Use these when you want a worked example or a community answer that does not fit a guide. ## Templates -Explore many [Budibase templates](https://budibase.com/templates/). Templates are free, 100% customizable, and take a couple of clicks to install. Find 6 of our favorite templates below: +Use templates when you want a starting point you can install and adapt quickly. -{` -
    -
  1. Employee timesheet app
  2. -
  3. IT asset management app
  4. -
  5. Ticket system
  6. -
  7. Applicant tracking system
  8. -
  9. Employee directory
  10. -
  11. Multi-step lead form
  12. -
+## Related pages -Explore more templates
-`}
+* [Keyboard Shortcuts](doc:keyboard-shortcuts) diff --git a/docs/Getting started/examples-and-guides/keyboard-shortcuts.md b/docs/Getting started/examples-and-guides/keyboard-shortcuts.md index 5cd04c614..c293d19fe 100644 --- a/docs/Getting started/examples-and-guides/keyboard-shortcuts.md +++ b/docs/Getting started/examples-and-guides/keyboard-shortcuts.md @@ -10,228 +10,37 @@ metadata: next: description: '' --- -## Generic Shortcuts - -
- -| Key | Function | -| :----- | :---------- | -| ESCAPE | Close Modal | - -## Data Shortcuts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Key - - Function -
- ⌘ + Enter - CTRL + Enter - - Create new row\ - Save current row (while editing a row) -
- ESCAPE - - Cancels edit -
- ⇥ (TAB) - - Shift focus one cell to the right -
- SHIFT + Click - - With a cell selected, SHIFT + CLICK will select all cells between -
- SHIFT + ↑↓←→ - - With a cell selected, SHIFT + ↑↓←→ will select another row or column depending on which arrow pressed -
- -
- -## Component Tree Shortcuts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Key - - Function -
- ⌘ + ↑ - CTRL + ↑ - - Move the component up -
- ↑ - - Select the next component above -
- ⌘ + ↓\ - CTRL + ↓ - - Move the component down -
- ↓ - - Select the next component below -
- ⌘ + D\ - CTRL + D - - Duplicate the component (and it's children) -
- ⌘ + X\ - CTRL + X - - Cut the component (and it's children) -
- ⌘ + C\ - CTRL + C - - Copy the component (and it's children) -
- ⌘ + V\ - CTRL + V - - Paste from the clipboard (clipboard must hold a component, component must be valid child-component for the location) -
- ⌘ + ←\ - CTRL + ← - - Collapse all nested components -
- ← - - Collapse selected component -
- ⌘ + →\ - CTRL + → - - Expand all nested components -
- → - - Expand selected component -
\ No newline at end of file +Use keyboard shortcuts to move faster in the builder and data views. + +## General + +| Key | Action | +| --- | --- | +| `Escape` | Close modal | + +## Data + +| Key | Action | +| --- | --- | +| `Cmd + Enter` / `Ctrl + Enter` | Create a new row or save the current row | +| `Escape` | Cancel editing | +| `Tab` | Move one cell to the right | +| `Shift + Click` | Select a range of cells | +| `Shift + Arrow keys` | Extend the current selection | + +## Component tree + +| Key | Action | +| --- | --- | +| `Cmd + Up` / `Ctrl + Up` | Move component up | +| `Up` | Select the component above | +| `Cmd + Down` / `Ctrl + Down` | Move component down | +| `Down` | Select the component below | +| `Cmd + D` / `Ctrl + D` | Duplicate component | +| `Cmd + X` / `Ctrl + X` | Cut component | +| `Cmd + C` / `Ctrl + C` | Copy component | +| `Cmd + V` / `Ctrl + V` | Paste component | +| `Cmd + Left` / `Ctrl + Left` | Collapse all nested components | +| `Left` | Collapse selected component | +| `Cmd + Right` / `Ctrl + Right` | Expand selected component | +| `Right` | Expand selected component | diff --git a/docs/Getting started/examples-and-guides/lookup-record.md b/docs/Getting started/examples-and-guides/lookup-record.md index c6391b9e7..ff91c4ecd 100644 --- a/docs/Getting started/examples-and-guides/lookup-record.md +++ b/docs/Getting started/examples-and-guides/lookup-record.md @@ -10,97 +10,39 @@ metadata: next: description: '' --- -## Try it out! +Use a lookup query when a form needs to check whether a record exists before the user continues. -{` - -`} - -*Note: The email addresses are displayed for demo purposes, so that you can test the lookup.* - -## 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). - -{` -Challenge:
-★★★☆☆ -`}
- -*** - -## Steps - -1. In the **Data** section, click on your external Datasource, and click on the `Queries` tab. Click `Create new query`. - - - -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. +## Build the query - +1. Open the relevant datasource +2. Create a query that looks up the row you need +3. Add a binding for the lookup value +4. Save and test the query -6. Navigate to the **Design** section, `Add component`: **Form** -7. `Add component`: **Field Group**, and set *Type* to 'Main with Sidebar' -8. `Add component`: **Text Field**, and enter a *Field* name and *Label* -9. `Add component`: **Icon**, and set the *Icon*, *Size* and *Color* +## Build the form - +1. Add a [Form](doc:forms) +2. Add the input field you want to check +3. Add a button to run the lookup query -10. Click the button beside *On click* -11. `Add Action`: **Execute Query** - 1. Select the *Datasource* - 2. Select the *Query* - 3. Check *Do not display default notification* - 4. Provide the email binding, e.g. `{{ Search Form.Fields.Search Email }}` +## Add the actions - +1. Run the lookup query +2. Save the returned row ID to app state +3. Stop the action chain when the query returns no rows +4. Show a warning notification when the record is not found -12. `Add Action`: **Update State** - 1. *Set value* 'EmployeeID' to JavaScript binding: - 2. ```javascript JavaScript - return $("Action 1.Query result")?.data?.[0]?.["EMPLOYEE ID"] - ``` -13. `Add Action`: **Continue if / Stop if** - 1.
+## Show the result - +1. Add a [Repeater](doc:repeater) or [Form block](doc:form-block) +2. Filter the data by the saved row ID +3. Hide the component when no record was found -14. `Add Action`: **Show Notification** - 1. Set *Type* to 'Warning' - 2. Set *Message* to 'Employee not found!' - 3. Check *Auto dismiss* -15. Be sure to `Save` +## Try it out - - -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` - - - -19. Click on the `Conditions` tab, and 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` - - - -
- -*** - -## App export - -*Downloads may take a few seconds.* +{` + +`} {` @@ -110,19 +52,17 @@ In some [Forms](doc:forms), it is important to verify that the entered details a `} 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..da9c75332 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 @@ -10,88 +10,32 @@ metadata: next: description: '' --- -## Try it out! +Use this pattern when a REST query should return success or failure immediately so the UI can react. -{` - -`} +## Build the automation + +1. Create an automation triggered by an app action +2. Add the query fields you need +3. Run the REST query +4. Collect the query response so it returns to the UI -## Scenario +## Handle the response -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. +1. Save the response code to app state +2. Stop the action chain when the status is not `200` +3. Add success actions such as refreshing a provider or closing a panel +4. Show an error component when the response is not successful -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. +## Why this works -To accomplish this, we will make use of [Synchronous automations 🔒](doc:synchronous-automations). +The UI can branch immediately based on the status code returned by the query. -For demonstration purposes, this guide will use a dummy query that will either return a 200 or a 404 in the response body. +## Try it out {` -Challenge:
-★★☆☆☆ + `}
-*** - -## 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. - - - -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 }}` - - - -Our query with 'resource' binding as seen in the Data section - 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. - - - -8. With the automation setup, we can now go to the Design section, and `Add component`: **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* - 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) - - - -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` - - - -15. `Add component`: **Headline** for the error scenario -16. Click on the `Conditions` tab: `Configure conditions` -17. `Add Condition`: - 1. *Show component* IF `{{ State.ResponseCode }}` *Like* 4 - 2. `Save` - - - -*** - -
- -## App export - -*Downloads may take a few seconds.* - {` @@ -100,19 +44,17 @@ For demonstration purposes, this guide will use a dummy query that will either r `} 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..9101c302c 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 @@ -14,65 +14,43 @@ next: slug: url-parameters title: URL variables --- -# Try it out! +Use URL parameters when a list screen needs to open a detail screen for a selected row. -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. +## Build the list screen -Firstly, I'll add a `Data Provider`, and nest a `Repeater` component, and then add `Container` component inside the Repeater. +1. Add a [Data provider](doc:data-provider) +2. Add a [Repeater](doc:repeater) inside the provider +3. Nest a Container inside the repeater +4. Use bindings from the repeater row to show the values you want -![](https://files.readme.io/c264816-image.png) +## Build the detail screen -
+1. Create a screen at a path such as `/staff/:id` +2. Add a [Data provider](doc:data-provider) for the same table +3. Filter the provider by `_id` +4. Set empty filter behavior to return no rows +5. Disable pagination +6. Use `{{ New Data Provider.Rows.0 }}` to read the returned row -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. +## Navigate to the detail screen -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. +Add an `On Click` action to the list item or row container. -![](https://files.readme.io/6f1b3c9-image.png) +Use `Navigate To` and pass the row `_id` in the URL, for example: -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. +`/staff/{{ New Repeater.Employees._id }}` -![](https://files.readme.io/236ee22-image.png) +## Recommended settings -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. +Use `_id` rather than a human-readable field such as email. -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`. +That keeps the URL stable and avoids guessable values. -![](https://files.readme.io/4da7075-image.png) +## Try it out -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. - -![](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. - -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. - -## 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. - -![](https://files.readme.io/ed82c1e-image.png) - -
- -
- -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` - -![](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. - -![](https://files.readme.io/00d60ff-image.png) - -Try it for yourself, and click below to download the app used to create this guide. +{` + +`} {` @@ -82,19 +60,17 @@ Try it for yourself, and click below to download the app used to create this gui `} 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..39994fa8a 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 @@ -10,66 +10,35 @@ metadata: next: description: '' --- -## Try it out! +Use this pattern when a picker should load a selected record into a form. -{` - -`} - -## 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. - -[App state](doc:app-state) will be used to allow communication between our search field, and the details form. - -{` -Challenge:
-★★☆☆☆ -`}
- -*** - -## Steps +The picker stores the selected row ID in app state, and the form reads that value back. -1. `Add component`: **Form** -2. `Add component`: **Data Provider** -3. In the Settings Panel, select the 'Employees' table -4. Untick *Paginate* +## Build the picker - +1. Add a [Form](doc:forms) +2. Add a [Data provider](doc:data-provider) +3. Add an [Options picker](doc:option-picker) +4. Set the picker to use the data provider +5. Set the picker value to the row `_id` +6. Save the selected `_id` into app state on change -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* +## Build the detail form - +1. Add a [Form block](doc:form-block) +2. Set the form type to `View` +3. Point it at the same table +4. Bind the Row ID to the saved state value -10. In the **Data** section, right-click the 'Employees' row you want to be the Default Value. Click `Copy row _id`. +## Why this works - +The picker chooses the record and the form reads the matching row directly from the table. -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` +## Try it out - - -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 }}` - - - -
- -*** - -## App export - -*Downloads may take a few seconds.* +{` + +`} {` @@ -79,19 +48,17 @@ Have a [Form block](doc:form-block) that displays some fields for a table record `} diff --git a/docs/Getting started/examples-and-guides/public-form.md b/docs/Getting started/examples-and-guides/public-form.md index b0e295457..932eb4207 100644 --- a/docs/Getting started/examples-and-guides/public-form.md +++ b/docs/Getting started/examples-and-guides/public-form.md @@ -5,69 +5,42 @@ deprecated: false hidden: false metadata: title: '' - description: >- - The document provides a step-by-step guide on creating a secure public form - using Budibase 3.0, allowing data collection from unauthenticated users - while ensuring only app admins can access the submitted data. It includes - instructions on setting up tables, designing forms, configuring automations, - and publishing the app. + description: '' robots: index next: description: '' --- -## Try it out! - -{` - -`} - -## 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. - -{` -Challenge:
-★★☆☆☆ -`}
- -*** - -## Steps +Use this pattern when unauthenticated users should submit data, but only app admins should access the stored records. -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. +The public screen submits form data through an automation, which writes to the secure table. - -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. +## Build the table - +Create the table that will store the submitted data. -> ℹ️ 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. +## Build the screen -5. In the Automation section, create a **new automation** that is triggered by an *App Action* +1. Create a new screen +2. Set the screen access to `Public user` +3. Add a form with fields that match the table schema - -6. **Change the role** for this automation to `Public user` -7. **Add fields** that match the fields in your form +## Build the automation - -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 +1. Create an automation triggered by an app action +2. Set the automation role to `Public user` +3. Add fields that match the form +4. Add a create row step for the secure table +5. Bind the trigger fields into the row columns - -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 +## Submit the form - -13. **Publish the app** and test the public form in a private window +1. Add a button to the public screen +2. Trigger the automation on click +3. Pass the form field values into the automation -
+## Why this works -*** +The public user can only call the automation, not read the secure table directly. ## App export @@ -81,19 +54,17 @@ This is for situations where you want to collect data from unauthenticated users `} 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..5872bcc79 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 @@ -1,5 +1,5 @@ --- -title: Link two entities in one form +title: Save two linked tables in one form excerpt: 'Example: Creating an employee record and linking them to a newly created job' deprecated: false hidden: false @@ -10,111 +10,28 @@ metadata: next: description: '' --- -## Try it out! +Use this pattern when one form needs to create a parent row and optionally create a related child row. -{` - -`} - -## 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. - -{` -Challenge:
-★★★★☆ -`}
- -*** - -## Steps - -1. `Add component`: **Form Block** - - -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. -4. `Add component`: **Options Picker** -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`: - 1. | Label | Value | - | :----------------------- | :----- | - | Select existing employee | SELECT | - | Create new employee | NEW | +## Build the form - +1. Add a [Form block](doc:form-block) +2. Set the table to `Jobs` +3. Eject the form block +4. Add an [Options picker](doc:option-picker) for choosing an existing or new employee +5. Add conditions so the relationship field and the new employee fields only show when needed -13. In the component tree, drag the **Relationshipfield** below the **Options Picker** -14. Click on the `Conditions` tab -15. `Configure conditions`: `Add condition` - 1. Hide component IF `{{ Form.Fields.ExistingEmployee }}` Equals Binding NEW - 2. `Save` +## Save the rows - +1. Save the job first +2. Save the employee second when `NEW` is selected +3. Use the saved job ID to link the employee row to the new job -16. `Add component`: **Container** -17. Click on the `Conditions` tab -18. `Configure conditions`: `Add condition` - 1. Hide component IF `{{ Form.Fields.ExistingEmployee }}` Equals Binding SELECT - 2. `Save` +## Why this works - - -19. `Add component`: **Headline**. Set *Text* to 'New Employee' -20. `Add component`: **Field Group** - - -21. 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 - - - -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' - - ![](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** - 1. Continue if `{{ Form.Fields.ExistingEmployee }}` Equals NEW -31. `Add Action`: **Save Row** - - 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! - - ![](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. -> -> The same is also true for options that are defined by the table schema, such as *Employee Level* in this case. - -
- -*** +The first save creates the job row, and the second save can reference that new job ID. ## App export -*Downloads may take a few seconds.* - {` @@ -123,19 +40,17 @@ When creating a new job, you want the option of creating and linking a new emplo `} 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..3c7198b13 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 @@ -1,5 +1,5 @@ --- -title: Saving in progress form +title: Save an in-progress form excerpt: Allow your end users to pick up where they left off deprecated: false hidden: false @@ -10,79 +10,32 @@ metadata: next: description: '' --- -## Try it out! +Use this pattern when a multi-step form should remember the user's progress after refresh or return visits. -> 👍 -> -> Refresh the page to see the saved form progress. +Save both the current step and the current form values to app state. -{` - -`} - -## 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. - -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. - -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. - -{` -Challenge:
-★☆☆☆☆ -`}
- -*** +## Build the form -## Steps +1. Add a create form +2. Split it into multiple form steps +3. Add back and next buttons for navigation -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 }}` - 2. Tick *Persist this value* +## Save progress - +1. Update the step value in app state when the user moves between steps +2. Persist the step value +3. Save the current form values to a separate state key +4. Persist the form values -2. Add another **Update State** action - 1. Set value 'FormValueStep1' `{{ literal New Employee Form.Value }}` - 2. Tick *Persist this value* - 3. Click `Save` - > 📘 FormValue state - > - > Each form step will need its own *FormValue* state, so form step two should be called 'FormValueStep2', etc. - > - > 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. +## Restore progress - +1. Bind the form's initial step to the saved step state +2. Bind each field's default value to the saved form state +3. Clear the saved state after submission -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 }}` +## Why this works -> 📘 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 - 2. Tick *Persist this value* -5. Add another **Update State** action for the number of form steps - 1. Set value 'FormValueStep1' to *blank* - 2. Tick *Persist this value* - 3. Click `Save` - - - -6. Click on the **Form** component, and in the Settings Panel 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 - - - -
- -*** +The step state restores where the user was, and the form value state restores the entered values. ## App export @@ -94,19 +47,17 @@ This recipe will make use of the [Spectrum meter](https://docs.budibase.com/docs `} 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..f23a6e1b0 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 @@ -10,72 +10,34 @@ metadata: next: description: '' --- -## Try it out! - -{` - -`} +Use `Scroll To Field` when a form action should move the view to a specific field. ## 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. - -{` -Challenge:
-★★☆☆☆ -`}
- -*** - -## Steps - -1. `Add component`: **Form** -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` - - +Use this pattern when a multi-step form should move the user to the next section after changing steps. -7. Click on the **Form** and set *Schema* to 'Expenses' +## Build the form -8. [Duplicate](https://docs.budibase.com/docs/components#editing) the **Form Step** +1. Add a [Form](doc:forms) +2. Set the form schema +3. Add a `Form Step` +4. Add a headline for each step +5. Add the relevant `Field Group` components -9. In the Settings Panel set *Step* to 2 +## Add the actions -10. Change the **Headline** *Text* to 'Expenses' +1. Add a button to the first step +2. Add a `Change Form Step` action +3. Add a `Scroll To Field` action +4. Choose the target form and field -11. Click on the **Field Group**: `Update form fields`: `Update` +Repeat the same pattern for later steps if you want the view to keep following the form. -12. `Add component`: **Button** and set *Text* to 'Back' +## Try it out -13. Set the *On click*: `actions` - -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' - -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' -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` - - - -
- -*** +{` + +`} ## App export @@ -89,19 +51,17 @@ The Scroll To action can be useful when using [Form steps](doc:form-steps), for `} diff --git a/docs/Getting started/examples-and-guides/show-button-on-condition.md b/docs/Getting started/examples-and-guides/show-button-on-condition.md index 70eb46d5e..8007f7619 100644 --- a/docs/Getting started/examples-and-guides/show-button-on-condition.md +++ b/docs/Getting started/examples-and-guides/show-button-on-condition.md @@ -10,56 +10,36 @@ metadata: next: description: '' --- -## Try it out! +Use conditional UI when a button should only appear after a user has searched for an existing record. -{` - -`} - -## Scenario - -Only show a 'create new record' button if the user has already searched the existing records for potential duplicates. - -{` -Challenge:
-★☆☆☆☆ -`}
+## Build the search area -*** +1. Add a [Data provider](doc:data-provider) for the `Employees` table +2. Add a table inside the provider +3. Add a form above the provider +4. Add a text field to the form for the search term +5. Add a filter to the provider using the form field binding -## Steps +## Build the create button -1. Start by adding a Data Provider, set to fetch rows from the Employees table -2. Add a table nested inside the Data Provider, with the data source as the Data Provider (not fetching data directly) +1. Add a button under the provider +2. Set the button text +3. Add an action to open a modal +4. Add a form block inside the modal to create a new employee - -3. Above the Data Provider component, add a a Form component (not to be confused with a Form Block). -4. Add a text field to the form, setting the field to "email" and the label to "Search Employee Email" +## Add the condition - -5. In the settings of the Data Provider, click to add a filter (Important: be sure to set the filter on the Data Provider itself, not the table) -6. Add the filter `Email` is `Like` the `Binding` `{{ New Form.Fields.email }}` +1. Open the button's `Conditions` tab +2. Add a `Show Component` condition +3. Set the condition to check whether the provider has zero rows - -7. Add a button underneath the Data Provider, with the button text to "Add new employee" -8. Add a Settings Panel with "Ignore clicks outside" checked, and the size set to "Medium. -9. Add a Form Block to the modal, set to create a new row in the Employees Table. +The button only appears when the search returns no matches. - -10. In the button, set an On Click action to open the modal, and click save. +## Try it out - ![](https://files.readme.io/4392a571a78e64769ba1149d855d96b3c73882e70cbba933195128c50c074c20-image.png) -11. In the Button component, head to the Conditions tab -12. Add a condition to `Show Component` `IF` `{{ New Data Provider.Rows Length }}` `Equals` `Number` `0` -13. Remember to save - - - -Now if a user tries to search for an employee that doesn't exist, they can create a new record. - -
- -*** +{` + +`} ## App export @@ -73,19 +53,17 @@ Now if a user tries to search for an employee that doesn't exist, they can creat `} diff --git a/docs/Getting started/examples-and-guides/table-rows-status-icon.md b/docs/Getting started/examples-and-guides/table-rows-status-icon.md index 06ae34b25..a730db3a5 100644 --- a/docs/Getting started/examples-and-guides/table-rows-status-icon.md +++ b/docs/Getting started/examples-and-guides/table-rows-status-icon.md @@ -1,6 +1,6 @@ --- title: Table row status -excerpt: Add an icon to graphically indicate the status of your records +excerpt: Highlight a row status with conditional styling deprecated: false hidden: false metadata: @@ -10,46 +10,28 @@ metadata: next: description: '' --- -## Try it out! - -{` - -`} +Use conditional styling when a table cell should visually reflect a row status. ## Scenario -In this example we have a table of sales records and we want to display an icon to show if the sale was made _Online_ or _Offline_. +This pattern is useful when a field stores values like `Online` and `Offline`, or any other status values. -The same approach could be applied for status based workflows, e.g. _Approved_, _In Progress_, _Complete_, etc. - -{` -Challenge:
-★☆☆☆☆ -`}
+## Build the table -*** +1. Add a [Table](doc:table) for the relevant data +2. Hide any actions you do not need -## Steps +## Add the condition -1. Add a table to your screen, and point it to the Sales table (available in the download link at the bottom of the page) -2. In the Table settings, disable "Add rows", "Edit rows", "Delete Rows" -3. In the Table settings, under columns, click the cog/sprocket icon for the Sales Channel -4. Add a condition by clicking "No conditions set" +1. Open the column settings for the status field +2. Add a condition for the `Offline` value +3. Set the cell background to red +4. Duplicate the condition for the `Online` value +5. Set the matching cell background to green - -5. Add the condition "Update `Cell` `Background color` to [red] if value `Equals` `Value` Offline" +## Why this works - -6. Duplicate the condition, and adjust it to show green for "Online" -7. Save - - - -
- -
- -*** +The table stays readable, but the status is easier to scan at a glance. ## App export @@ -63,19 +45,17 @@ _Downloads may take a few seconds._ `} 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..60cfb1374 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 @@ -10,134 +10,31 @@ metadata: next: description: '' --- -## Try it out! - -{` - -`} +Use this pattern when one field should recalculate related date fields as the user changes a value. ## Scenario -You're building an app and you want to set a project length in days, and then dynamically calculate start and end dates. - -{` -Challenge:
-★★★☆☆ -`}
- -*** - -## Steps - -1. `Add component`: **Form** -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' - - - -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 -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` - - - -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* - - +This guide uses a duration field to update start and end dates automatically. -13. [Duplicate](https://docs.budibase.com/docs/components#editing) the **Date Picker** -14. Replace 'Start' with 'End' in the *Field* and *Label* settings +## Build the form -> 👍 -> -> Time to make the field values dynamically update! +1. Add a [Form](doc:forms) for the `Jobs` table +2. Add a number field for the duration +3. Add a date picker for the start date +4. Add a date picker for the end date -15. In the Settings Panel under *On change*: `Define actions` +## Add the actions - 1. **Validate Form** - make sure to select the form in the dropdown - 2. **Update Field Value** +1. Add a `Validate Form` action to the duration field +2. Add an `Update Field Value` action that calculates the start date +3. Add a matching `Update Field Value` action for the end date +4. Add a guard so the end date only updates when the start date exists - 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: +Use bindings to read the current value and JavaScript to add or subtract days. - ```javascript JavaScript - //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date - Date.prototype.subtractDays = function(days) { - var date = new Date(this.valueOf()); - date.setDate(date.getDate() - days); - return date; - } +## Why this works - return new Date($("Field Value")).subtractDays($("Jobs Form.Fields.Duration")); - ``` - -> 📘 -> -> The **Validate Form** action will prevent the **Update Field Value** from firing if there's any validation errors. -> -> 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. -> -> Also note that you may need to replace the `$("Jobs Form.Fields.Duration")` binding to match your form name. - - - -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: - - ```javascript - //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date - Date.prototype.addDays = function(days) { - var date = new Date(this.valueOf()); - date.setDate(date.getDate() + days); - return date; - } - - return new Date($("Field Value")).addDays($("Jobs Form.Fields.Duration")); - ``` -17. Finally click on 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' "" - 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: - - ```javascript - //Source: https://stackoverflow.com/questions/563406/how-to-add-days-to-date - Date.prototype.addDays = function(days) { - var date = new Date(this.valueOf()); - date.setDate(date.getDate() + days); - return date; - } - - return new Date($("Form.Fields.Works Start")).addDays($("Field Value")); - ``` - -> 📘 -> -> In this case we first check that the number of days is a valid number. -> -> 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 user edits one value, and the other dates stay in sync. ## App export @@ -151,19 +48,17 @@ You're building an app and you want to set a project length in days, and then dy `} diff --git a/docs/Getting started/quickstart-budibase-ai.md b/docs/Getting started/quickstart-budibase-ai.md index 8f41d4dac..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,37 +18,51 @@ next: slug: generating-javascript-with-ai title: Generating JavaScript with AI --- -## Enabling Budibase AI +Connect a model provider in your workspace settings before you use Budibase AI. -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/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/Getting started/templates/change-requests.md b/docs/Getting started/templates/change-requests.md index acd937b57..6df91a0ab 100644 --- a/docs/Getting started/templates/change-requests.md +++ b/docs/Getting started/templates/change-requests.md @@ -1,7 +1,7 @@ --- title: Change Requests excerpt: '' -deprecated: false +deprecated: true hidden: false metadata: title: '' @@ -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) diff --git a/docs/Getting started/templates/expense-approval.md b/docs/Getting started/templates/expense-approval.md index 752d9cf63..a13428f70 100644 --- a/docs/Getting started/templates/expense-approval.md +++ b/docs/Getting started/templates/expense-approval.md @@ -1,7 +1,7 @@ --- title: Expense Approval excerpt: '' -deprecated: false +deprecated: true hidden: false metadata: title: '' @@ -10,314 +10,98 @@ metadata: next: description: '' --- -Our expense approval template offers a ready-to-use solution for enabling employees to submit claims for review and authorization. However, it’s also fully customizable, providing a basis for creating your own bespoke solution in Budibase. +Use the Expense Approval template to manage employee claims through a straightforward submission and approval process. -In this guide, we’re outlining how our template works, how it’s built, and a few examples of changes you could make to reflect your own internal expense processes. +To use this template, [open it here](https://budibase.app/builder?template=app/expense-approval). -To use this template, [click here](https://budibase.app/builder?template=app/expense-approval). +## What this template includes -Let’s jump in. +The template is built around: -## What does this template do? +* Employee expense submissions +* Manager review and approval +* Receipt uploads for supporting evidence +* Status updates for submitted claims +* Email notifications when a claim is resolved -Handling expenses is one of the most common administrative tasks across businesses in all industries. At the most basic level, this involves: +## Roles and access -1. Enabling employees to submit structured expense data. -2. Routing submitted expenses to the appropriate authority for review. -3. Applying defined business logic to approve or reject submissions. -4. Recording outcomes and communicating them to stakeholders. +The app uses two primary role groups: -Our template is built around a simple approval workflow with two types of users. +* `Employees` create and manage their own claims +* `Managers` review all claims and approve or reject them +* `App Admins` manage the underlying data and app configuration -**Employees** can submit itemized claims relating to specific company **events**. +Keep access rules aligned with the claim lifecycle. Employees should only see their own submissions, while managers should see everything they need to review. -Their **Managers** can then view, review, and approve these claims. +## Data model -This is built on top of our internal database. +The template uses three internal tables. -Let’s break down the core functionality. +| Table | Purpose | +| :--- | :--- | +| `Events` | Stores claimable events and supporting details | +| `Expense Claim` | Stores each claim submission | +| `Expense Item` | Stores the individual line items and receipts | -### CRUD Operations +### Relationships -The core of our app is allowing different types of users to carry out defined CRUD operations on our underlying data. This relies on providing users with differing permissions to access data or carry out actions subject to their roles. +The main relationships are: -Firstly, **Employees** can view expenseable events and create new claims using a dedicated data collection form. +* `Expense Item` links to `Expense Claim` +* `Expense Claim` links to `Events` +* `Expense Claim` links to `Users` for submitter and reviewer ownership - +Use `Relationship` columns for table links and `Single User` columns for ownership fields. -They can also view their own previous claims, including their current statuses, but not the claims of their colleagues. +## Workflow -Within existing claims, they can update the **Status** attribute to **Cancelled**. +The claim flow is: -Users with the higher **Manager** role inherit all permissions from **Employees**. On top of this, they can view all claims, as well as carrying out update actions, enabling them to approve or reject submissions. +1. An employee creates a claim from an event. +2. The employee adds line items and receipts. +3. The claim is submitted for review. +4. A manager approves or rejects it. +5. The employee receives a notification about the result. - +Employees can also cancel their own claims before they are resolved. -### Receipt uploads +## Screens -To help validate claims and maintain effective records, users can submit receipts with their expense submissions. +The template uses role-specific screens for common tasks: -Our submission form features a **File Upload** component, which users can use to provide evidence supporting their claims. +* Employees browse events, create claims, and review their own submissions +* Managers review claim details and apply approval actions +* Admins manage the event table and supporting data -This is stored in an **Attachment** column alongside each individual expense item. +Use autogenerated screens where possible, then tighten the layout and permissions for each role. -### Approval workflows +## Automations -Our template is based around a simple, single-step approval workflow, with one class of users responsible for authorizing all expenses. This works by updating the **Status** attribute of the original claim to either **Approved** or **Rejected**. +The main automations cover: -These are performed using **Row Actions**, enabling approvers to respond to expense claims at the press of a button, rather than manually updating the **Status** attribute. +* Claim submission +* Claim cancellation +* Approval and rejection +* Email notifications to the submitter -### Tracking change statuses +If you add a new claim status or a new review step, update the row actions and notifications together. -Within any approval workflow, tracking the status of submissions as they progress is critical. +## Customising the template -**Employees** can view their previous expense claims to check if the status has updated when a reviewer responds. As we’ll see in the next section, they’ll also be notified when the **status** of their claim is updated. +Start by adjusting: - +1. Claim statuses +2. Expense categories +3. Event fields +4. Role permissions +5. Approval messaging -### Automated emails +If you swap in a different data source, keep the claim, item, and event relationships intact. -A key time sink within approval processes is handling communications. Specifically, notifying users that something needs their attention. To solve this problem, our template utilizes email automations triggered by specific user actions. +## Related guides -In our workflow, this occurs at the point at which an expense claim receives a response. - -When this happens, the user who initially submitted the request is emailed, informing them of the outcome. - -This utilizes **Email** actions within the respective **Reject** and **Approve** Row Actions. We’ll examine how **Row Actions** work a little later. - -Take a look at our documentation on [working with email automations](https://docs.budibase.com/docs/send-email). - -## How does it work? - -Now that we have an understanding of how our template functions from the perspective of end-users, we can move on to thinking about how it’s actually built. - -Within Budibase, app-building is divided into separate concerns. Let’s check out how our template works across each section of the Budibase builder. - -### User roles - -Budibase’s custom RBAC tools allow us to configure the exact data, screens, and actions that different users are able to access. - -We can add or edit roles using our visual RBAC editor and grant them access to specific tables or Views within Budibase’s Data section. - - - -Our template utilises three distinct roles to control how user cohorts interact with data across our apps. - -**Employees** are able to view expensible events, submit itemized expenses, and view the current state of their own previous submissions. They can also update or cancel claims that they have created but not submitted. - -**Managers** can view, review, and respond to all **Employees** requests. - -**App Admins** have full CRUD access across all data tables. - -We’ll see the database Views we’ve created for each in the next section. - -### Data structure - -As we said earlier, our application is built on top of Budibase’s internal database. Check out our documentation on [Budibase DB](https://docs.budibase.com/docs/budibasedb) to learn more. - -Here’s how our data model works. - -#### Tables - -Our app utilizes three internal tables: - -1. **Events** - storing information relating to company events which expenses can be claimed against. -2. **Expense Claim** - storing information about employees’ expense submissions. -3. **Expense Item** - storing information about individual items within expense claims. - -Additionally, our template’s data model uses the **Single User** data type to establish relationships between our data and Budibase’s internal **Users** table, enabling us to assign rows to specific end users. - -The Events table stores columns with the following names and data types: - -* **Title** - Text, -* **Description** - Long-Form Text, -* **Location** - Text, -* **Start Date** - Date, -* **End Date** - Date, -* **Claim Deadline** - Date, -* **Max Claim** - Number, -* **Claims** - Relationship, -* **Image** - Single Attachment. - -The Expense Claim table stores: - -* **Summary** - Formula, -* **Submitter** - Single User, -* **Reviewer** - Single User, -* **Status** - Single Select, -* **Date** - Date, -* **Expense Items** - Relationship, -* **Event** - Relationship, -* **Total** - Number, -* **Submitter Notes** - Long-Form Text, -* **Reviewer Notes** - Long-Form Text. - -Lastly, our Expense Item table stores the following attributes: - -* **Description** - Text, -* **Price** - Number, -* **Category** - Single-Select, -* **Claim** - Relationship, -* **Receipt** - Single Attachment. - -We’ll check out some examples of how you might want to modify these later. - -#### Relationships - -Our three tables are linked using Budibase’s Relationship data type. - -This allows us to define how individual entries across each of our tables relate to each other. We can then utilize attributes from directly related tables across **View Joins** within Budibase’s Data section or throughout our Designs and Automations. - -Our app relies on two Relationships: - -* **A Many-To-One Relationship** from the **Expense Item** table to the **Expense Claim** table. -* **A Many-To-One Relationship** from the **Expsense Claim** table to the **Events** table. - - - -As we said a second ago, we also use **Single User** attributes to link specific pieces of data to users within Budibase’s internal **Users** table. - -There are two instances of this in our app, both within the **Expense Claim** table: - -* **Submitter** - An attribute that links each entry to the **User** that initially created the request. The value of this is set automatically, using the *default to current user* option. -* **Reviewer** - An attribute that assigns records the **Reviewer** of the expense request. - -#### Views - -A **View** is a subset of our data that’s used to define which rows, columns, actions, or aggregated data specific users can access across one or more tables. - -In Budibase, these can be used to centrally configure all aspects of how our end-users interact with connected data within the Data section. Once we’ve created a view, we can use it to autogenerate role-specific screens and automations in just a few clicks. - -Our expense approval app utilises several views. Here’s a summary of the views we’ve created across our three tables. - -On top of the **Events** table, we’ve created one view called **Employee Events**. This provides a **Read-Only** version for the **Events** table for users with the **Employee** role, omitting the **Expense Claims** column. - - - -Within the **Expense Claims** table, we’ve created three views, called **Claims to Review**, **Submitted Claims**, and **Unsubmitted Claims**. - -The **Claims to Review** View is reserved for the **Manager** role for both **Read** and **Write** actions. It also uses a filtering expression to only include the rows where the **Status** attribute is equal to **Submitted**. All columns are writable except **Submitter Notes**, which is read-only. - - - -The **Submitted Claims** View provides **Read-Only** access to **Employees**, using a filtering expression to only include rows where the **Status** is **Submitted** and the **Submitter** is equal to the **Current User**. - -The **Unsubmitted Claims** View provides the same access for **Employees**, except the **Status** filter is set to **Not Submitted**. - -Our **Expense Items** table has a single View, giving **Employees** access only to the rows where the **Submitter** attribute in the related **Expense Claims** table is equal to the **Current User**. - -### User interfaces - -Our app features several distinct screens for each role. Check out our docs page on [working with screens within Budibase](https://docs.budibase.com/docs/screens). - -We’ve created a home page as an initial screen for all **Employee** users. This allows them to navigate to expensible events. From here, they can navigate to a form where they can start logging itemised expenses. - -When they click this, a new **Expense** row is created for the **Employee** to start populating with related **Items**. - -![Button Actions](https://files.readme.io/3769f9782b2fda4c75606adba9d828ec3be58337b91c7060105655e80f7e4d0b-Expense_Management_Template_7_Button_Actions.png) - -**Employees** can also access a a screen for viewing their previous submissions. This features two tables - one displaying all of their submitted claims and the other for claims that are currently in review. - -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. - -![Two Tables](https://files.readme.io/9e3b30d74661cc1c85d2b45837d017eb46fab7f26a589cddddf33e7616a02cb9-Expense_Management_Template_8_Tables.png) - -**App Admins** can access a dedicated CRUD screen for creating, viewing, and editing **Events**. - - - -Managers are able to view the details of submitted claims and either approve or reject them using **Row Actions**, as we’ll see in the following section. - -### Automations - -Our app relies on automations for carrying out user actions in a controlled manner, including to create, approve, cancel, and reject claims. Take a look at our [automation docs](https://docs.budibase.com/docs/automation-steps) to learn more about automating workflows in Budibase. - -The majority of these are created using **Row Actions**. These are user-triggerable automations that relate to a specific row in one of our tables or Views. - -Our **Employees** can trigger two automations. The first of these, **Submit**, triggers when a user submits their claim, setting the **Date** to the current timestamp and the **Status** to **Submitted**. - - - -The other attributes, including the linked **Expense Items,** are then populated with a **Save Row** button action on the form UI itself. - -**Employees** can also trigger a **Row Action** called **Cancel**. With a button push, they can update the **Status** of their claim to **Cancelled**, removing it from the review process without deleting the original record. - - - -**Managers** also use **Row Actions** to respond to claims. Depending on whether they hit **Approve** or **Reject**, the **Status** is updated to **Approved** or **Rejected**. Then, the original requestor is emailed, notifying them. - -![Approve](https://files.readme.io/247cd5bfbd559f28bc90651a53f048eea1cb8f6ca2d093692c72293c095a1295-Expense_Management_Template_12_Approve.png) - -## Customising our change request template - -Budibase templates offer fully functional solutions for key use cases. However, they’re also intended as a basis for further customisation, enabling you to quickly create apps with your own data and business logic. - -Let’s check out some of the key modifications you might want to make to our expense approval template. - -### Updating the data model - -The Data section is the core of the app-building experience in Budibase. As we said earlier, our application is built on top of three tables within BudibaseDB. We can modify this by either swapping in an external database or making changes to our existing one. - -To connect to an external database, we’d need to recreate our internal DB’s views and access rules before swapping the existing UIs and automations for your new data. - -Alternatively, we can alter the schema of our existing tables using the Data section’s spreadsheet-like interface. - -Say we wanted to add a new **Text** column to our **Expense Items** table, to store the **Vendor**, for more detailed records. We could do so using the **Plus** icon. - - - -### Adding and altering user roles - -User permissions for both accessing data and carrying out actions on it are also configured within the Data section. Another key way we can modify our template is by altering this, including adding or removing roles, or updating the permissions granted to existing ones. - -We can add entirely new roles under **Manage Roles**. Budibase offers branching inheritance for custom roles within a visual editor. So, we can create hierarchical roles, as well as ones with entirely separate permissions. - -For instance, we might want to create an **Auditor** role that has **Read-Only** access across all data, but no **Write** permissions for any of our tables. - -To achieve this, we’d create a parallel branch of permissions. - -![Auditor Role](https://files.readme.io/a832856d88108ea0c63b9f3f392ecff97052a51e5b44564eb3950792b2dc4ccd-Expense_Management_Template_14_Auditor_Role.png) - -We’d then need to create **Auditor** Views of our data tables and assign read-only access to all attributes under the **Columns** tab. - - - -### Adding extra screens - -We can also modify our template by altering its UIs. We can add or remove screens or make adjustments to the components on existing ones. - -Let’s carry on with our example of providing **Read-Only** access to our **Expense Claims** to our new **Auditor** role. - -From our **Auditor View**, we’d hit Screens to generate a table UI with side panels. - - - -Then, all we need to do is make a few tweaks to the screen that’s outputted, including removing the **Create** form and setting the **Update** form to **View**. - - - -### Adding your own business rules - -Budibase templates are an ideal starting point for creating custom applications to enforce your own business rules while retaining our pre-built interfaces. - -For example, we could provide an action to allow our auditor to flag certain submissions as suspicious. - -To do this, we’d start by adding a **Row Action** to our new **Auditor View**. We’ll call this **Flag Expense**. - - - -We’re then brought to the automation editor. - - - -Back in the Data section, we’ll update the **Status** column on our **Expense Claims** table, adding an option called **Flagged**. - - - -Within our **Row Action**, we’ll then use the same flow as our existing automation rules, only this time we’ll update the relevant row’s **Status** to **Flagged**. - - - -Lastly, on our new **Auditor** screen, we’ll add a **Button** to the existing **Table** component, allowing them to trigger our **Row Action**. - - +* [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) diff --git a/docs/Getting started/templates/index.md b/docs/Getting started/templates/index.md index 468429f49..1ec0d6951 100644 --- a/docs/Getting started/templates/index.md +++ b/docs/Getting started/templates/index.md @@ -1,7 +1,7 @@ --- title: Templates excerpt: '' -deprecated: false +deprecated: true hidden: true metadata: title: '' diff --git a/docs/Getting started/templates/risk-management.md b/docs/Getting started/templates/risk-management.md index f0e674c52..cf9503cfb 100644 --- a/docs/Getting started/templates/risk-management.md +++ b/docs/Getting started/templates/risk-management.md @@ -1,7 +1,7 @@ --- title: Risk Management excerpt: '' -deprecated: false +deprecated: true hidden: false metadata: title: '' @@ -10,401 +10,107 @@ metadata: next: description: '' --- -Our risk management template provides a ready-to-use solution for recording, assessing, and working with data around risks, incidents, and improvement initiatives. +Use the Risk Management template to track risks, incidents, and improvement requests through a simple submission and approval flow. -It’s fully customizable, offering the perfect basis for creating your own custom solution utilizing your own data, logic, and processes. +To use this template, [open it here](https://budibase.app/builder?template=app/risk-management). -In this guide, we cover everything you need to know about working with our template, including what it does, how it’s built, and the key ways that you can modify it to suit your needs. +## What this template includes -To use this template, [click here](https://budibase.app/builder?template=app/risk-management). +The template is built for three submission types: -## What does this template do? +* Risks +* Incidents +* Improvements -At its core, our application is based around submission and approval workflows for risks, incidents, and improvements. +It provides: -This includes: +* Role-based submission and review workflows +* Status tracking for submitted records +* Approval and rejection actions +* Email notifications for key workflow events +* A project table for approved work -* Enabling **App Users** to submit new risks, incidents, or improvements. They also can view and cancel their own previous submissions. -* Routing submissions to **Power Users** for review and approval. -* Providing records of all ongoing and previous submissions. -* Notifying stakeholders of changes to the status of submissions or when there are new submissions that need their attention. +## Roles and access -Our template utilizes simple approval workflows for each type of submission, with two distinct user roles in addition to our **App Admin** role. +The app uses three role groups: -It’s built on top of five tables within Budibase’s internal database. We’ll examine what each of these is and what it stores a little later. +* `App Users` create submissions and manage their own records +* `Power Users` review all submissions and apply approvals or rejections +* `App Admins` manage the full dataset and app configuration -Let’s check out the core functionality first. +Keep role permissions aligned with the workflow. Each role should only see the records and actions it needs. -### CRUD operations +## Data model -Our application enables different kinds of users to perform specific CRUD actions across the various underlying tables, with user permissions varying according to their roles. +The template uses five internal tables plus Budibase’s `Users` table. -**App Users** can create new records on our Improvements, Risks, or Incidents tables using dedicated data submission forms, populating only a subset of each table’s columns. +| Table | Purpose | +| :--- | :--- | +| `Glossary` | Reference definitions for the template content | +| `Risks` | Stores risk submissions | +| `Incidents` | Stores incident submissions | +| `Improvements` | Stores improvement submissions | +| `Improvement Projects` | Stores accepted work and related follow-up activity | -![Risk Management Template](https://files.readme.io/6806d4815318b3fa6729e66de8de6c76dbda0fe78bd578cdc37c20173171a95e-Risk_Management_Template_1.gif) +### Table relationships -However, they have limited permissions to **Read** or **Update** entries across the tables. Specifically, they’re only able to access their own previous submissions. Within these, they can update the **Status** attribute to **Canceled** via a **Row Action**. +The main relationships are: -![My Submissions](https://files.readme.io/f96209a0a016a4b4ba76c839ba65d0686cfdb13441a910c1f22fcc41edf0c857-Risk_Management_Template_2_Previous_Submissions.png) +* `Improvement Projects` links to `Risks` +* `Improvement Projects` links to `Incidents` +* `Improvement Projects` links to `Improvements` +* Each submission table links to `Users` for ownership and auditing -This works the same way for **Improvements, Risks**, and **Incidents**. +Use `Single User` fields for ownership, creator, or reviewer tracking, and `Relationship` fields for the links between tables. -### Approval workflows +## Workflow -**Power Users** inherit all permissions from our **App Users**. On top of this, they can view all incoming submissions across our three tables. +The submission flow is: -They can also carry out **Update** actions relating to certain fields. +1. A user creates a risk, incident, or improvement. +2. The record is assigned a submission status. +3. A power user reviews the record. +4. The record is approved, rejected, or canceled. +5. Email notifications are sent at the relevant step. -Specifically, they can use **Row Actions** to either **Approve** or **Reject** the row in question, updating its status attribute. At the same time, they can use a form UI to populate the **Feedback** column**.** +Approved items can be linked to an `Improvement Projects` record for follow-up work. -If a submission is **Approved**, it can also be assigned to a specific **Improvement Project** for implementation by populating a relationship column. +## Screens -![Approval Flow](https://files.readme.io/84e3c0c5f6cf6c7968eaef00ff73d48f729218d8044e4ec1bdf991ff6d8a2676-Risk_Management_Template_3_APproval_Flow.png) +The template uses a mix of autogenerated and custom screens. -### Tracking submission statuses +* App users use submission forms and personal status views +* Power users use review screens for approvals and rejections +* Admins use management screens for monitoring and reporting -Both classes of users are able to track the status of the submissions that are relevant to them. +Keep these screens role-specific. That makes the workflow easier to scan and reduces unnecessary branching in the UI. -Again, this matches the level of data exposure that’s provided for each Role, as we laid out earlier. +## Automations -So, **App Users** can access dedicated screens where they can check the status of any of their own previous submissions. +The main automations cover: -Meanwhile, **Power Users** are able to edit submissions, regardless of the user who created them, including viewing or updating their statuses. +* Submission notifications +* Approval and rejection updates +* Cancellation handling +* Scheduled email summaries for power users -### Automated emails +If you change the statuses or add a new workflow stage, update the related automations at the same time. -Lastly, our application utilizes Budibase’s built-in email automation actions to send notifications to stakeholders based on defined events in our approval workflows. +## Customising the template -Specifically, the original creator of a submission across any of our three tables is notified when it has a response. +Start by adjusting: -In the case of a **Rejection** or **Approval**, the user is notified of this outcome. When they **Cancel** their own submissions, they’ll also receive email confirmation of this. +1. Role names and permissions +2. Status values +3. Submission fields +4. Review actions +5. Email notification content -**Power Users** receive a summary of the submissions that require their attention at fixed intervals via a separate automation. +If you replace the internal tables with your own data model, update the views and automations together. -Take a look at our documentation on [working with email automations](https://docs.budibase.com/docs/send-email). +## Related guides -## How does it work? - -Now that we know what our template does, we can drill deeper into how it is built across the different sections of the Budibase builder. - -### User roles - -Our risk management template relies on three user roles within Budibase’s RBAC system. RBAC enables us to assign a role to individual users in order to grant them access to appropriate data and actions. - -We’ll see how permissions are actually granted in the next section. - -Users with the **App User** role can primarily create submissions across our three tables. They can also view key details of their own previous submissions, including their status, or cancel the submission. - -**Power Users** can view all submissions, as well as triggering approval or rejection automations and assigning them to projects. They also inherit all permissions from **App Users**. - -Roles are configured using Budibase’s visual RBAC editor. We can use branch UIs to define how roles relate to one another, including permission inheritance. - - - -We can use this to define which actions and data each role is permitted to access from within the data section, as we’ll see in the following section. - -Users with the **App Admin** role have full CRUD permissions across all tables. - -### Data structure - -Our template utilizes Budibase’s internal database, enabling us to define and manage schemas using our Data section’s visual editor. - -Check out our documentation on [Budibase DB](https://docs.budibase.com/docs/budibasedb) to learn more. - -Our application relies on several interrelated internal tables, as well as role-specific **Views** based on these. - -Let’s break it down. - -#### Tables - -As we said earlier, our template utilizes five internal tables. These are: - -* **Glossary** - Storing definitions of our different kinds of submissions. This is provided as a reference for **App Admins**. -* **Risks** - For storing submissions relating to potential risks. -* **Incidents** - Where incidents are recorded and tracked. -* **Improvements** - Allowing customers to suggest new improvement initiatives. -* **Improvement Projects** - Which accepted Risks, Incidents, or Improvements can be related to. - -Our app also relies on Budibase’s internal **Users** table to enable individual rows across these to be assigned to specific users, as we’ll see in the next section. - -Our glossary simply stores definitions for each of our other tables. - -Each of our other tables stores data that’s required to record and process submissions. Here’s a summary of the attributes within each. - -**Improvement Projects:** - -* **title** - Text, -* **id** - Number, -* **created\_by** - Single User, -* **last\_updated\_by** - Single User, -* **description** - Long Forn Text, -* **created\_at** - Date, -* **status** - Single Select, -* **start\_date** - Date, -* **end\_date** - Date, -* **project\_manager** - Single User, -* **improvement** - Relationship, -* **risks** - Relationship, -* **incidents** - Relationship, -* **updated\_at** - Date. - -**Improvements:** - -* **title** - Text, -* **id** - Number, -* **start\_date** - Date, -* **end\_date** - Date, -* **created\_at** - Date, -* **updated\_at** - Date, -* **description** - Long Form Text, -* **created\_by** - Single User, -* **last\_updated\_by** - Single User, -* **Improvement Project** - Relationship, -* **status** - Single Select. -* **feedback -** Long Form Text. - -**Risks:** - -* **title** - Text, -* **id** - Number, -* **created\_at** - Date, -* **updated\_at** - Date, -* **created\_by** - Single User, -* **last\_updated\_by** - Single User, -* **description** - Long Forn Text, -* **improvement\_project** - Relationship, -* **status** - Single Select, -* **feedback** - Long Form Text. - -**Incidents:** - -* **title** - Text, -* **id** - Number, -* **reported\_by** - Single User, -* **employee\_involved** - Single User, -* **date\_of\_incident** - Date, -* **date\_created** - Date, -* **notes** - Long Form Text, -* **status** - Single Select, -* **Improvement Project** - Relationship, -* **feedback** - Long Form Text. - -#### Relationships - -Our app utilizes two distinct types of relationships. - -Relationships between tables in BudibaseDB are created using a special **Relationship** column. This allows us to configure links between rows across tables, either within our Data section or in end-user applications. - -We’ve used three instances of this to create **Many-To-One** relationships from our **Improvement Projects** table to the **Improvements**, **Risks**, and **Incidents** tables. - - - -
- -Rows in each of our tables can also be linked to records in Budibase’s internal **Users** table. This allows us to record which user created or updated certain submissions, as well as assigning rows to particular owners. - -In Budbase, we have two dedicated columns for linking tables to **User** records - the **Single User** or **Multi-User** columns. - -Our app utilizes Single User columns across each of our tables to represent various relationships with users. - - - -#### Views - -**Views** are subsets of data across one or more tables, with specific rules around accessing and interacting with data. - -In Budibase, these are used to centrally configure what each user role can do with our stored data, including granting read or write permissions at the row or column level. We can then use these to autogenerate CRUD UIs and automation rules. - -Our underlying tables have their **Access** settings to only be readable or writable by **App Admins**. - - - -Each of our tables has distinct Views for each of our two core user roles. - -For **App Users**, the views for our **Risks, Incidents**, and **Improvement** tables are broadly similar, enabling them to create records, read their own submissions, or set the status attribute to cancel via a **Row Action**. - -The specific attributes that users can read or write are then defined under the **Columns** tab, so **App Users** are able to access the columns that are required to initially create their submission, check its status, or perform a cancellation. - -![](https://files.readme.io/a8aa13345e6000c18daed0c70abcaad8a242e612d0d2413c369038bad9bf4ffd-Screenshot_2025-08-13_at_09.44.16.png)Each of these tables has two additional **Views** for **Power Users**. The first provides full **Read** and **Write** access across the tables, along with two **Row Actions** to either **Approve** or **Reject** submissions. - -This is attached to the respective **Review** screens for each of our submissions tables. - -The other provides **Read-Only** access for each of the submission tables. This populates the **Projects** screen. - -We can also use **Views** to perform key calculations on our database tables. Our template features views for each of our three submissions tables to provide counts of submissions for individual users based on their statuses. - -For instance, we have a **View** called **My Improvements Count**. Using the **Configure Calculations** tab, we’ve set this to return the **Count** of rows, **Grouped By** the **status** attribute. - -This will return each unique status, along with the number of relevant entries in our table. - - - -However, we don’t want to include any submissions that have either been canceled or rejected. We also only want to include the rows that are related to the current user in the front end. - -So, we’ve applied three filtering rules. The first includes rows that have been submitted by the current user. The other two exclude rows where the **status** is **Rejected** or **Canceled**. - - - -These are then displayed on the home screen for App Users, as we’ll see in a moment. - -### User interfaces - -Our application uses a combination of fully custom screens and UIs built around Budibase’s autogenerated layouts. - -Check out our docs page on [working with screens within Budibase](https://docs.budibase.com/docs/screens). - -The screens available for each user cohort across our three types of submissions follow a broadly similar pattern. - -**App Users** can access three kinds of screens. Firstly, there are three data collection forms, where they can create records on our three submission tables. These rely on Budibase’s autogenerated **Form** layout, with minor changes to their design. - - - -We’ve provided fully custom screens for **App Users** to view, track, or cancel their own submissions. These are made up of a variety of nested components wrapped in **Data Providers** and **Repeaters** to populate display elements with values from the relevant Views. - -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. - - - -We’ve also created a dedicated home screen for **App Users**. This provides links to navigate to the screen for each type of submission. Its design relies on stylized **Container** and **Text** components. - -The **Container** relating to each type of submission displays the total number of entries that the user has created, along with how the active submissions break down by status. - -First, we have a **Text** component that displays the total number of each type of submission by the current user, by calculating the length of the relevant **View**. So, for improvements, we use `{{ My Improvements Data Provider.Rows Length }} Submitted` - -The My Improvements Data Provider has a filtering expression to exclude entries where the **status** is set to **canceled**. - - - -Beneath this, we have a second **Text** component which is wrapped in a **Data Provider** and **Repeater**. - -These components will connect to a data source and display each of the elements nested within them for each individual row. In our case, we’re displaying the **status** and **count** from our **View Calculation**, using: - -``` -{{ Improvements Counts Repeater.My Improvements Counts.Count id }} {{ Improvements Counts Repeater.My Improvements Counts.status }} -``` - - - -**App Users** can also use buttons to navigate to either the submission form or table UI for each respective type of submission. - -Our **Power User** screens for reviewing submissions follow the same pattern as the **App User** versions we saw earlier, with the additional ability to **Approve** or **Reject** records. - -They can add additional details on a modal form that’s displayed when they hit reject. - - - -**Power Users** can also access a similar screen for viewing or editing **Improvement Project** records, including reading all of the details of associated submissions, via the **View** we discussed earlier. - -### Automations - -In Budibase, the Automation section is used to create workflow logic within our applications, including enabling users to take specific actions. Take a look at our [automation docs](https://docs.budibase.com/docs/automation-steps) to learn more. - -Our template makes extensive use of **Row Actions**. These are user-triggerable automation workflows that run on a specific row within a database table. These can be created from the Data section, under the **Row Actions** tab within a database table or view. - -The **App User** view for each of our submission tables features a **Row Action** called **Cancel**. - -Once triggered, this performs two actions. First, it updates the **Status** attribute of the trigger row to **Cancelled**. Then, it sends a template email to the user, confirming that this has been successful. - - - -**Power Users** have two additional **Row Actions** for each submission table, called **Approve** and **Reject**. These follow the same structure as our **Cancel** action, changing the **Status** to **Approved** and **Rejected**, respectively. - -They then send an email template to the original submitter, notifying them of the outcome. - - - -Lastly, we’ve built an Automation called **Outstanding Attributes**, using a **Chron Trigger**. This enables us to set rules which are executed at defined intervals. Ours runs every Monday and Thursday morning at 09:30. - -We’ve set our Cron Trigger manually, but we also have the option of using AI to generate an expression. - - - -This uses three **Query Rows** steps to return all of the rows from our **Risks**, **Incidents**, and **Improvements** tables with **Status** attributes set to **Pending**. - -We then use a **Condition** block, with some custom JavaScript, to count the total number of rows across all three tables that are currently **Pending**. If this is **not 0**, we continue. - -Lastly, we use an **Email** action to notify relevant users that submissions need their attention. By default, this is set to notify the current user, but this can be overridden to target a specific email address or a comma-separated set of emails. - -Alternatively, we could configure this to notify all users with a particular role, such as **Power User** or **App Admin**. - -By default, this Automation is set to **Paused**. - -## Customizing our risk management template - -Budibase templates are created as ready-to-use solutions, but they also provide a basis for you to build your custom workflow apps. - -Let’s think about some of the key ways that you can modify our change management template within Budibase. - -### Updating the data model - -The Data section is the core of every Budibase app. Our template utilizes Budibase’s internal database. So, we have two broad options for customizing our data model. We could swap this for an entirely different database, or we could alter the schema of our existing one. - -If we wanted to connect to an external SQL database, for example, we could recreate the various Views that we have in place for our existing database before connecting this to our existing UIs and automations. - -We can also easily modify the schema of our existing database, including adding, removing, or editing existing tables and columns, using the spreadsheet-like interface in Budibase’s Data section. - -For example, say we wanted to add a new Long Form Text column to our **Risks** table, called inspector\_notes. - -We could do this by hitting the **+** icon at the top of our table. - - - -At the same time, we might update our existing **status** attribute by adding an option called **Inspected**. - - - -### Adding and altering user roles - -Another key area where you can modify our template is its user roles. Budibase offers a fully visual interface for creating and configuring user roles, including with branching inheritance. - -We’re going to create a new role called **Inspector** this will inherit permissions from the existing **App User** role, but it will be placed in its own branch, separate from the **Power User** role. - -This means that **Inspectors** will be able to create any submissions that **App Users** can, as well as whatever additional permissions we grant them. However, this will be unrelated to the existing **Power User** role’s permissions. - - - -To go along with this, we’ll create a new **View** and set its **Access** to the **Inspector** role. We’ll then make all columns except for **Inspector Notes** read-only. - - - -We’ll also set a filter to only include entries where the **status** is set to **Pending**. - - - -Now, **Inspectors** have permission to view all pending **Risks** entries, and add their notes. - -### Adding extra screens - -Next, we need to provide an interface for our inspection workflow. - -This will be relatively simple, enabling **Inspectors** to read our entries and populate the **Inspector Notes** field. - -From our new view, we’ll start by autogenerating a **Table** screen with the **Side-Panel Form** option. - - - -Then, within the Design section, we’ll make a couple of UX tweaks. Specifically, we want to remove the **Create Form**. On our remaining **Edit** form, we’ll remove the **Delete** button and set all fields except for **Inspector Notes** to **Disabled**. - - - -### Adding your own business rules - -Lastly, we can use the Automation section to add our own application logic. To carry on our example we want to add an automation flow so that when the **Inspection Notes** field is populated, the **status** is updated to **Inspected**. - -We’ll then email the original submitted, notifying them of this update. - -We’ll start by creating a **Row Action** from our new database View. We’ll call this **Inspect**. - - - -We’ll then mimic the structure of our existing **Row Actions**, first adding an **Update Row** step, followed by an **Email** step. - -To update our row, we’ll set the **ID** to our trigger ID and the **status** to **Inspected**. We’ll populate the **Send To, Subject**, and **Body** fields of our **Email** action too. - - - -Next, we need to provide a way to trigger this automation from our app’s UI. Head back to the Design section, and we’ll add a **Button Action** to the form on our **Inspection** screen. - -Here, we’ll add a **Row Action** step. Our **Form Block** has an attribute called **RowID**, which we’ll copy into the corresponding field on our button action. - - +* [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) diff --git a/docs/References/budibase-architecture.md b/docs/References/budibase-architecture.md index 6b03a72ec..15ef07c4b 100644 --- a/docs/References/budibase-architecture.md +++ b/docs/References/budibase-architecture.md @@ -10,33 +10,32 @@ 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 +## Overview -In this section, we will cover the core services that make up the Budibase self-hosted platform and how this architecture fits together. +Budibase runs as a small set of services behind a single proxy. -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. +The proxy is the public entry point. It routes traffic to the app and worker services, while CouchDB stores app data, MinIO stores files, Redis stores shared metadata and sessions, and LiteLLM powers Budibase AI and agent features. LiteLLM uses Postgres for its own metadata. -This architecture will look the same no matter the method of self hosting, all of the above services are required for Budibase to function. +The exact container layout differs between deployment methods, but these logical services are part of the default self-hosted platform. -## Optional architecture +## Core services -Some services are not included in all installations - they are optional, they may only provide a service which is useful to that particular environment. - -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. [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. [Cache (Redis)](https://redis.io/) - stores commonly accessed metadata and active session data. +6. [AI service (LiteLLM)](https://docs.litellm.ai/) - provides the proxy used for Budibase AI and agent features. +7. [AI database (Postgres)](https://www.postgresql.org/) - stores LiteLLM metadata when Budibase AI is enabled. ## 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/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 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/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 +
diff --git a/docs/References/troubleshooting-sql.md b/docs/References/troubleshooting-sql.md index 0498b169a..9b15c923d 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,34 +32,6 @@ 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"` - -## SQL Schema export - -> 📘 Schema export is designed for debugging -> -> 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. - -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. - -## 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. - -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. - -![](https://files.readme.io/4919ff4-image.png) - -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. - -![](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 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. diff --git a/docs/Self-hosting/reverse-proxy.md b/docs/Self-hosting/reverse-proxy.md index 65e9a5cb1..c05f90ee9 100644 --- a/docs/Self-hosting/reverse-proxy.md +++ b/docs/Self-hosting/reverse-proxy.md @@ -17,65 +17,55 @@ next: slug: accessing-minio title: Accessing MinIO --- -One of the main things you will want to set up before putting your Budibase platform into production use is a proxy, which can control access to the cluster via a domain (removing the need for a port number and so on) as well as allow the use of HTTPS for a domain that you own. In this section, we will provide some configuration options to get this up and running easily with [NGINX](https://www.nginx.com/) or [Caddy](https://caddyserver.com/docs/automatic-https). +Use a reverse proxy to expose Budibase behind a domain name and enable HTTPS. -{` -
-`}
+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: - -* [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/) +NGINX is the better fit when Budibase is one service behind a larger proxy setup. -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. +Use a server block that: -Here is a basic reverse proxy configuration that will simply pass all requests from a domain/sub-domain/path to your Budibase platform. +* 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` +Example: -# Budibase -``` +```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,28 +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 machine, 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. -When Budibase is deployed behind an external reverse proxy such as Nginx Proxy Manager and external authentication is enabled, requests can fail with `502 Bad Gateway openresty`. +## Proxy buffer issues -This usually happens when response headers, such as a `Content-Security-Policy` header with many whitelisted domains, exceed the proxy buffer limit. Budibase reduces the likelihood of this by removing CSP headers from JSON API responses and increasing the internal proxy buffer size to 16k. +If you see `502 Bad Gateway openresty` with external authentication, increase the proxy buffer sizes. -If you still see this error when using an external proxy, increase the proxy buffer size. An example Nginx configuration is shown below: +Example: -``` +```nginx server { proxy_busy_buffers_size 512k; proxy_buffers 4 512k; @@ -114,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 -
+* [Accessing CouchDB](doc:accessing-couchdb) +* [Accessing MinIO](doc:accessing-minio) +* [Hosting methods](doc:hosting-methods) diff --git a/docs/Settings/_order.yaml b/docs/Settings/_order.yaml index 87eb6c3b9..347b3c39e 100644 --- a/docs/Settings/_order.yaml +++ b/docs/Settings/_order.yaml @@ -12,6 +12,8 @@ - audit-logs - backups-1 - metrics +- email +- email-templates - branding - v2-recaptcha - translations diff --git a/docs/Settings/authentication-and-sso/sso-with-keycloak.md b/docs/Settings/authentication-and-sso/sso-with-keycloak.md index 4a444b9af..8f9990d54 100644 --- a/docs/Settings/authentication-and-sso/sso-with-keycloak.md +++ b/docs/Settings/authentication-and-sso/sso-with-keycloak.md @@ -12,78 +12,106 @@ next: --- > 📘 OpenID Connect > -> To become familiar with OpenID Connect in Budibase, see: [OpenID Connect](doc:openid-connect) +> To become familiar with OpenID Connect in Budibase, see [OpenID Connect](doc:openid-connect) -## Configuration +Use Keycloak to configure OIDC-based SSO in Budibase. -
+## Realm setup -### Realm Setup +Use a realm other than `master`. In Keycloak, `master` is reserved for top-level administration. -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. +To create a new realm: -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. +1. Sign in to Keycloak at `/admin`. +2. Open the realm dropdown on the left. +3. Select `Create realm`. +4. Save the new realm name. -### Add a Client +## Create 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, you can skip this step. -### Capability config +## Enable client authentication -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 configuration 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. +## Add the Budibase callback URL + +Copy the callback URL from Budibase under `Settings > Auth > OpenID Connect`. -Copy the callback URL and add it to the 'Valid Redirect URIs' field in Keycloak then click 'Save'. +In Budibase, this field is labeled **Callback URL**. + +Add that URL to **Valid Redirect URIs** in Keycloak, then save. -### Find your configuration details +## Find your configuration details + +### Config URL + +Open **Realm settings** in the Keycloak admin console, then open the **General** tab. + +Scroll to **OpenID Endpoint Configuration** and copy the URL. + +Paste the URL into the **Config URL** field in Budibase. -#### Client ID +### 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 +### 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. +Paste it into the **Client secret** field in the Budibase OIDC panel. -#### Configuration URL +### Optional settings -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. +Budibase also lets you configure: -You can then paste this URL into your Budibase OIDC Config as the Configuration URL, and Budibase will be integrated with Keycloak for OIDC. +* **Name**: The text shown on the login button +* **Icon**: The provider icon shown on the login button +* **PKCE Method**: Available on enterprise licenses +* **Activated**: Enables the OIDC provider +* **Allow unverified email linking**: Only use this if you trust the identity provider to assert verified email addresses +* **Auth Scopes**: Includes `openid` plus any additional scopes you need -# Managing Users +## Activate OIDC in Budibase -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 you finish the configuration fields, turn on **Activated** in the Budibase OpenID Connect settings and save. -Make sure you enter a username and email address for your user. + - +## Manage users -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. +After Budibase is set up, create users in the Keycloak realm. -Now the user is created, you can sign in as that user through Budibase OIDC using Keycloak! +Open the **Users** tab in the Keycloak admin panel and click **Create user**. - +Enter a username and email address. + + + +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. + +You can now sign in through Budibase using Keycloak. diff --git a/docs/Settings/branding.md b/docs/Settings/branding.md index 1d87b1501..987c66366 100644 --- a/docs/Settings/branding.md +++ b/docs/Settings/branding.md @@ -10,141 +10,62 @@ 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. +Use these fields to customise the login page header and button text. -#### Title +These values apply to the Budibase login page and can be used 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) diff --git a/docs/Settings/email-templates.md b/docs/Settings/email-templates.md new file mode 100644 index 000000000..f3d774079 --- /dev/null +++ b/docs/Settings/email-templates.md @@ -0,0 +1,60 @@ +--- +title: Email templates +excerpt: Manage Budibase's built-in email templates. +deprecated: false +hidden: false +metadata: + title: '' + description: '' + robots: index +next: + description: '' +--- +Budibase includes ready-made email templates for common system messages. + +Open `Settings` > `Email` > `Templates` to review, edit, preview, and export them. + +## Available templates + +The built-in templates cover common email flows such as: + +* Password recovery +* Invitations +* Welcome emails + +If custom templates are enabled in your workspace, they also appear in this list. + +## Open a template + +1. Open `Settings` > `Email` > `Templates`. +2. Select a template from the table. +3. Edit the contents. +4. Preview the result. +5. Save your changes. + +## Edit template content + +The template editor supports Handlebars bindings. + +Use bindings for values such as: + +* Recipient email address +* Organisation name +* Logo URL + +On the edit screen, the bindings panel is split into: + +* Template bindings +* Common bindings + +## Preview templates + +Use the Preview tab to see the rendered email content before saving. + +## Export templates + +The templates list page includes export actions for the default template set. + +If custom templates exist, Budibase also shows an export action for them. + +This is useful when you want to back up template changes or move them between environments. diff --git a/docs/Settings/email.md b/docs/Settings/email.md index 6aabc40cd..bbb2d0cbc 100644 --- a/docs/Settings/email.md +++ b/docs/Settings/email.md @@ -9,151 +9,73 @@ metadata: robots: index next: description: '' + pages: + - type: basic + slug: email-templates + title: Email Templates --- -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 so Budibase can send emails 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 email templates are managed on a separate page. - - +See [Email templates](doc:email-templates) for the available templates and how to edit them. - +## Use email in automations - - +Once SMTP is configured, you can send email from automation actions. - - - - - - - +Common uses include: - - +* User invitations +* Password recovery +* Workflow notifications +* Approval and rejection messages - +Keep sender addresses and template content aligned with your domain so mail is less likely to be flagged as suspicious. - - - -
- 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. - 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 -
- Default from email address - - Used by system emails and SMTP automations that do not specify a Send From address. Your SMTP provider may restrict or rewrite this address. - - [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 - - AKIAX5ZKVGGJ2SASAHT2M7Z -
- Password (visible when require sign-in is checked) - - Password for SMTP server - - Password!23IhopeNot -
+## Troubleshooting -  +If email does not send: -## Templates +* 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 -Budibase comes with three different email templates: Password Recovery, Invitation, and Welcome. In addition to that, you can also create custom templates. +## Related guides -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. - -The email templates work on all devices, email platforms, and themes (light and dark modes). Below is an image of the invitation email template. - - - -## Video tutorial - -{` - -`} \ No newline at end of file +* [Automation actions](doc:automation-actions) +* [User management](doc:user-management) +* [Branding](doc:branding) +* [Email templates](doc:email-templates) diff --git a/docs/Settings/user-management/index.md b/docs/Settings/user-management/index.md index 65533227c..115bfa4c0 100644 --- a/docs/Settings/user-management/index.md +++ b/docs/Settings/user-management/index.md @@ -1,8 +1,7 @@ --- title: User management excerpt: >- - The user management page contains all you'll need to invite, delete and create - new users as well as change their Budibase application roles. + Manage users, roles, groups, and SCIM provisioning across Budibase. deprecated: false hidden: false metadata: @@ -18,21 +17,59 @@ next: - type: basic slug: user-roles title: User Roles + - type: basic + slug: workspace-access + title: Workspace Access + - type: basic + slug: in-app-user-management + title: In-app User Management + - type: basic + slug: user-groups + title: User Groups + - type: basic + slug: scim-provisioning + title: SCIM Provisioning --- -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 access they have, and how they are grouped across Budibase. + +Users are shared across the whole Budibase installation. + +## Invite users + +You can invite users from two places: + +* The `Invite users` button in the builder sidebar +* `Settings` > `People` in the Budibase portal + +Use [Adding users](doc:adding-users) for the full invite flow. + +## Reset passwords + +If a user needs a password reset: + +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 -> 📘 Adding new users -> -> Invite users from the workspace **Invite user** flow. Read more in [Adding Users](doc:adding-users). +Users can have both tenant-level and workspace-level access. -## Resetting passwords +Use `User Roles` to configure access to specific apps and workspaces. -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. +## Delete users -## Configure user roles +Delete users from the user menu when they no longer need access. -Users can have roles for both the Budibase installation and workspaces, read more about that in [User Roles](doc:user-roles). +Treat deletion as permanent. If you need the user again later, invite them again instead. -## Deleting a user +## Related guides -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. +* [Adding Users](doc:adding-users) +* [User Roles](doc:user-roles) +* [Workspace Access](doc:workspace-access) +* [In-app User Management](doc:in-app-user-management) +* [User Groups](doc:user-groups) +* [SCIM Provisioning](doc:scim-provisioning) diff --git a/docs/Settings/user-management/scim-provisioning.md b/docs/Settings/user-management/scim-provisioning.md index e58038b8d..8dd4fcee6 100644 --- a/docs/Settings/user-management/scim-provisioning.md +++ b/docs/Settings/user-management/scim-provisioning.md @@ -10,146 +10,108 @@ metadata: next: description: '' --- -SCIM (System for Cross-domain Identity Management) is an open standard for managing user identity information. +SCIM 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*. +It is designed for one-way provisioning: -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**. +* Budibase receives users and groups from your identity provider. +* Synced users and groups are then managed externally. +* Manual users and groups can still be created and edited 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. +Common providers include Azure Active Directory and Okta. -You can still manually add or import users outside your organization; these users will remain fully configurable within Budibase. +## Access -## Unlocking SCIM provisioning +SCIM provisioning is available on the enterprise plan. -Contact sales to enquire about upgrading to the enterprise plan [https://budibase.com/contact/](https://budibase.com/contact/) +Contact sales to upgrade: [budibase.com/contact](https://budibase.com/contact/) ## Enable SCIM -Login to the Budibase portal, and click on the `Settings` tab. Select the `Auth` tab. +Open `Settings` > `Auth` in the Budibase portal. - +Turn on `Activated` under the SCIM section. -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. +When SCIM is enabled, Budibase shows: - +* `Provisioning URL` +* `Provisioning Token` -> 👍 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). +Copy both values into your identity provider. -*** +The provisioning URL uses the current platform URL and the SCIM endpoint: -## Example: Azure Active Directory +```text +{platformUrl}/api/global/scim/v2 +``` -This example will look at provisioning active directory users from Azure into Budibase +The provisioning token is the current user API key shown in the SCIM settings screen. -### Step 1 - Create an enterprise application +## SSO requirement -First, we need to create an Enterprise application to manage the users and groups that we want to provision for Budibase. +SCIM provisioning does not disable password-based sign-in on its own. -Log in to Azure Active Directory, and Navigate to `Enterprise applications`. +If you want to require SSO-only login, enable [Enforce SSO](doc:enforced-sso) separately. -Click on `New application` +## Disable SCIM - +If SCIM is already enabled and you turn it off, Budibase asks what to do with existing SCIM-provisioned users. -Then click on `Create your own application`. A side panel should appear on the right hand side of your screen. +You can choose between: -Create new application - Create new application - +* Remove SCIM users +* Convert to regular users -Select the *(Non-gallery)* option and give your app a name. +Removing SCIM users deletes them permanently. - +Converting them keeps the users in Budibase, but they are no longer synced with your identity provider. -Assuming you already have some users in your active directory, you can now add them to your enterprise application. +## Manage synced users -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. +Synced users are matched by email. - +When a user is managed through SCIM: -### Step 2 - Provisioning +* Their email, first name, and last name are read-only in Budibase. +* Other non-synced fields can still be edited. +* The user is marked as externally synced in the builder. -Under the *Manage* section, click on `Provisioning`. Then click `Connect your application`. +## Manage synced groups - +Synced groups are matched by name. -Copy and paste the URL and Token from the Budibase settings page as the admin credentials. +When a group is managed through SCIM: - +* The group name is read-only in Budibase. +* Non-synced fields can still be edited. +* The group is marked as externally synced in the builder. -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. +## First sync -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. +When SCIM is activated for the first time: - +* Existing Budibase users are matched to SCIM users by email. +* Existing groups are matched by name. +* Members already assigned to matched groups are replaced by the SCIM-provisioned members. -The Budibase portal now shows the users who have synced under the `Users` tab. +## Azure Active Directory example - +If you are using Azure AD, the provisioning flow is: -There is also a note in this section indicating that users are being synced from your AD. +1. Create an enterprise application in Azure AD. + +2. Add the users and groups you want to provision. +3. Open Azure provisioning settings and connect the application. + Create new application + Create new application + +4. Paste the Budibase provisioning URL and token into Azure. + + +5. Test the connection, create the provisioning setup, and start provisioning. + +6. Give the provisioned users app access in Budibase. -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 also need SSO, follow the [SSO with Azure AD](doc:sso-with-azure-ad) guide. - - - - -### 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. - -Furthermore, make sure you have given your users and groups [Application access](doc:application-access). - -Giving Carol basic app access - Giving Carol basic app access - - -{` -
-`}
- -## Managing SCIM - -### Initial SCIM Sync Activation - -#### What happens when a SCIM sync is activated for the first time? - -* User Matching - * Existing Budibase users are matched with SCIM users by email. - * Matched users are marked as externally synced and managed externally thereafter. -* Group Matching: - * Existing groups are matched by name. - * Groups with matching names (e.g., “engineering”) are taken over as externally synced. -* User Assignment in Synced Groups: - * Existing assigned users will be wiped out - * SCIM specified users will be mapped to the group. - -### Managing SCIM Users - -#### How to manage SCIM users? - -* Identifying Synced Users: - * Synced users are marked with a sync logo in the Budibase builder. - * Certain fields will be read-only for synced users. -* Fields for Synced Users: - * Read-Only Fields: Email, name, and surname (managed via external SCIM datasource). - * Editable Fields: Role and other non-synced fields can be edited in Budibase. -* Non-SCIM Users: - * Users created manually or not matched with SCIM are fully editable in Budibase. - -### Managing SCIM Groups - -### How to manage SCIM groups? - -* Identifying Synced Groups: - * Synced groups are marked with a sync logo in the Budibase builder. - * Some fields will be read-only for synced groups. -* Editable Fields for Synced Groups: - * 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 +After provisioning, assign the required [user roles](doc:user-roles) and [application access](doc:application-access) in Budibase. diff --git a/docs/Settings/user-settings.md b/docs/Settings/user-settings.md index 5e3f5c5ed..9d227641e 100644 --- a/docs/Settings/user-settings.md +++ b/docs/Settings/user-settings.md @@ -10,29 +10,36 @@ 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 page to manage your profile, theme, layout, and API key. -1389 +Open it from the user menu in the builder sidebar. -Let's go through the options one by one. +## My Profile -### Update user information +Use this section to update your email, first name, and last name. -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. +Keeping these details current helps with email templates and makes it easier for other people in your organisation to identify you. -384 +## Theme -### Update password +Use this section to update the Budibase portal theme. -Here, you can update the password for your own user account. +## API key -384 +This section displays your API key and a copy button. -### Toggle developer mode (Developer/Admin users only) +Use this value as the required header for the [Public API](doc:public-api). -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. +## Update password -### View API key +Use this action to open the password change flow. -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 +If your account is not using SSO, Budibase lets you update the password directly from the user menu or the profile modal. + +If you are the account portal owner in a cloud workspace, Budibase opens the account portal account page instead. + +## Close developer mode + +Use this action to return from the builder back to the apps view. + +This closes developer mode and takes you to the main workspace app list.