Merge pull request #8506 from ToolJet/release/templates-1.0

Release: Template 1.0 (v2.27.3)
This commit is contained in:
Akshay 2024-01-05 19:23:04 +05:30 committed by GitHub
commit 1a8694468e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
457 changed files with 853220 additions and 630505 deletions

View file

@ -171,6 +171,7 @@ jobs:
echo "SUB_PATH=/apps/tooljet/" >> .env
echo "NODE_ENV=production" >> .env
echo "SERVE_CLIENT=true" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
- name: Pulling the docker-compose file
run: curl -LO https://tooljet-test.s3.us-west-1.amazonaws.com/docker-compose.yaml && mkdir postgres_data

View file

@ -64,6 +64,7 @@ jobs:
echo "SSO_GIT_OAUTH2_CLIENT_SECRET=dummy" >> .env
echo "SSO_GIT_OAUTH2_HOST=dummy" >> .env
echo "SSO_GOOGLE_OAUTH2_CLIENT_ID=dummy" >> .env
echo "ENABLE_PRIVATE_APP_EMBED=true" >> .env
- name: Set up database
run: |

View file

@ -53,7 +53,7 @@ jobs:
],
"serviceDetails": {
"pullRequestPreviewsEnabled": "no",
"buildCommand": "npm i && npm run build",
"buildCommand": "bash build-latest-version.sh",
"publishPath": "build/",
"url": "https://tooljet-pr-${{ env.PR_NUMBER }}.onrender.com"
}

View file

@ -1 +1 @@
2.27.2
2.27.3

View file

@ -48,7 +48,7 @@ ToolJet is an **open-source low-code framework** to build and deploy internal to
## Quickstart
The easiest way to get started with ToolJet is by creating a [ToolJet Cloud](https://tooljet.com) account. ToolJet Cloud offers a hosted solution of ToolJet. If you want to self-host ToolJet, kindly proceed to [deployment documentation](https://docs.tooljet.com/docs/setup/).
You can deploy ToolJet on Heroku using one-click deployment.
You can deploy ToolJet on Heroku and DigitalOcean using one-click-deployment.
<p align="center">
<a href="https://heroku.com/deploy?template=https://github.com/tooljet/tooljet/tree/main"><img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy to Heroku" height=32></a>

View file

@ -0,0 +1,9 @@
#!/bin/bash
set -e
jq '[.[0]]' versions.json > tmp_versions.json
mv tmp_versions.json versions.json
npm i && npm run build
exec "$@"

View file

@ -6,8 +6,8 @@ title: 'Marketplace: Development Setup'
The Marketplace offers custom plugins that can be installed in your ToolJet instance. This guide aims to assist you in creating a new plugin for the ToolJet marketplace.
## Requirements
- [Node.js](https://nodejs.org/en/download/) **(v18.3.0)**
- [npm](https://www.npmjs.com/get-npm) **(v8.11.0)**
- [Node.js](https://nodejs.org/en/download/) **(v18.18.2)**
- [npm](https://www.npmjs.com/get-npm) **(v9.8.1)**
## Getting started

View file

@ -21,5 +21,5 @@ ToolJet client is a ReactJS application. Client is responsible for visually edit
## Requirements
1. **Node version 18.3.0**
2. **npm version 8.11.0**
1. **Node version 18.18.2**
2. **npm version 9.8.1**

View file

@ -11,12 +11,12 @@ Open the terminal and run the commands below.
### 1. Set up the environment
1. Install Node.js ( version: v18.3.0 ) and npm (version: v8.11.0)
1. Install Node.js ( version: v18.18.2 ) and npm (version: v9.8.1)
```
nvm install 18.3.0
nvm use 18.3.0
npm install -g npm@8.11.0
nvm install 18.18.2
nvm use 18.18.2
npm install -g npm@9.8.1
```
2. Install Postgres
@ -83,7 +83,7 @@ SERVE_CLIENT=true
### 3. Install and build dependencies
Make sure node version is set to 18.3.0 before running the below command:
Make sure node version is set to 18.18.2 before running the below command:
```
npm install
@ -97,7 +97,7 @@ npm run build:plugins
```
npm run --prefix server db:create
npm run --prefix server db:mirgate
npm run --prefix server db:migrate
```
If at any point you need to reset the database, use this command `npm run --prefix server db:reset`
@ -114,4 +114,4 @@ cd ./frontend && NODE=production npm run build
cd ./server && npm run start:prod
```
The client will start on the **port 3000**, you can access the client by visiting the url created by codespace - `https://<url>/apps/tooljet`
The client will start on the **port 3000**, you can access the client by visiting the url created by codespace - `https://<url>/apps/tooljet`

View file

@ -124,7 +124,7 @@ Example:
Let's say you need to install the `imagemagick` binary in your ToolJet server's container. You'd then need to make sure that `apt` installs `imagemagick` while building the image. The Dockerfile at `docker/server.Dockerfile.dev` for the server would then look something like this:
```
FROM node:18.3.0-buster AS builder
FROM node:18.18.2-buster AS builder
RUN apt update && apt install -y \
build-essential \

View file

@ -17,14 +17,14 @@ Follow these steps to setup and run ToolJet on macOS for development purposes. O
```bash
/bin/bash -c "(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
1.2 Install Node.js ( version: v18.3.0 ) and npm (version: v8.11.0)
1.2 Install Node.js ( version: v18.18.2 ) and npm (version: v9.8.2)
```bash
brew install nvm
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh
nvm install 18.3.0
nvm use 18.3.0
npm install -g npm@8.11.0
nvm install 18.18.2
nvm use 18.18.2
npm install -g npm@9.8.2
```
1.3 Install Postgres

View file

@ -20,12 +20,12 @@ Follow these steps to setup and run ToolJet on Ubuntu. Open terminal and run the
Close and reopen your terminal to start using nvm
```bash
nvm install 18.3.0
nvm install 18.18.2
```
Ensure you have the correct version of npm, or it will cause an error about fsevents.
```bash
npm i -g npm@8.11.0
npm i -g npm@9.8.1
```
1.2 Install Postgres

View file

@ -38,8 +38,8 @@ For VSCode users, you can set the formatter to `ESLint` in the [**settings.json*
## Requirements
1. **Node version 18.3.0**
2. **npm version 8.11.0**
1. **Node version 18.18.2**
2. **npm version 9.8.1**
:::tip
It is recommended to check the VSCode **Setting.json**(Press `ctrl/cmnd + P` and search `>Settings (JSON)`) file to ensure there are no overrides to the eslint config rules. Comment the following rules for eslint: **eslint.options: {...}**.

View file

@ -11,7 +11,7 @@ ToolJet can connect to Oracle databases to read and write data.
To establish a connection with the Oracle DB data source, click on the `+Add new` button located on the query panel or navigate to the [Data Sources](https://docs.tooljet.com/docs/data-sources/overview) page from the ToolJet dashboard.
A Oracle DB can be connected with the following credentails:
A Oracle DB can be connected with the following credentials:
- **Host**
- **Port**
- **SID / Service Name** ( Database name must be a SID / Service Name )

View file

@ -229,7 +229,7 @@ Let's follow the steps to authorize ToolJet to access your Google profile data:
Lets create a query to make a `GET` request to the URL, it will pop a new window and ask the user to authenticate against the API.
- Add a new query and select the REST API data source from the dropdown
- In the **Method** dropdown select `GET` and enabe the `Run query on application load?`
- In the **Method** dropdown select `GET` and enable the `Run query on application load?`
- Run the query.
- A new window will pop for authentication and once auth is successful, you can run the query again to get the user data like Name and Profile Picture.

View file

@ -3,7 +3,10 @@ id: gitsync
title: GitSync
---
GitSync feature allows users to synchronize the applications on their workspace with a git repository. GitSync feature simplifies the process of managing and version controlling your applications on ToolJet.
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
The GitSync feature enables synchronization of workspace applications with a git repository, streamlining application management and version control on ToolJet.
## Overview

View file

@ -1,115 +1,62 @@
---
id: access-cellvalue-rowdata
title: Change text color in columns of the table
title: Dynamically Change Cell Colors in Table
---
# Change text color in columns by accessing `cellValue` and `rowData` in the table
This guide shows how to change the text color and background color of certain cells in a Table component based on specific conditions.
In this how-to guide, we will build an app that will use a sample RestAPI to display the data in the table, and then we will change the text color of the columns according to the condition.
## 1. Start by Creating a New Application and Setting up the Data Source
- Create a new app and add a **[Table](/docs/widgets/table)** component to the canvas.
- Open the Query Panel at the bottom and click on the `+ Add` button.
- Select REST API as your data source - your query will be named as restapi1 by default.
- Choose GET method and enter the below URL:
```
https://fakestoreapi.com/products
```
- To view the data that your query will return, click on the **Preview** button. Click on the **Run** button to execute the query and retrieve the data.
- Let's start by creating a new application and then adding a table widget into the canvas.
## 2. Display Data on the Table
- Hide the Query Panel and click on the Table component to open its configuration panel on the right.
- Under Table Data, enter the below code:
```
{{queries.restapi1.data}}
```
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/newapp.gif)
<img style={{ border:'0' }} className="screenshot-full" src="/img/how-to/change-text-color/table-with-data.png" alt="Table Component With Data" />
</div>
- Now go to the **Query Panel** at the bottom of the app editor and click on the `+` button.
- Choose **RestAPI** data source
## 3. Change Text Color Based on Cell Value
- Select the Table component and go to Columns.
- For the `category` column, paste the below code under Text Color to dynamically change the text color based on the value of the cell:
```
{{cellValue == 'electronics' ? 'red' : 'green'}}
```
Now, if the cell value is `electronics`, the text color will be red; otherwise, it will be green.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/restapi.png)
<img style={{ border:'0', marginBottom:'15px' }} className="screenshot-full" src="/img/how-to/change-text-color/conditional-text-color.png" alt="Conditional Text Color" />
</div>
- Now we will use a sample RestAPI endpoint - I have used the API provided by **coinstats.app**, API-URL:
https://api.coinstats.app/public/v1/coins?skip=0&limit=100&currency=USD
- Choose `GET` method, enter the request URL (API URL in previous step), name the query - I have named it `crypto`, and then **Create** the query
<i>You can use also Hex color codes for more color options.</i>
## 4. Change Text Color Using Row Data
- Under Cell Background Color for the `symbol` column, paste the below code:
```
{{rowData.price < 100? 'yellow': 'white'}}
```
The rowData identifier can be utilized to reference values from any column within the Table component.
Now if the value in the price column is lesser than 100, the cell background color will be yellow or else it will be white.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/apiendpoint.png)
<img style={{ border:'0', marginBottom:'15px' }} className="screenshot-full" src="/img/how-to/change-text-color/conditional-background-color.png" alt="Conditional Background Color" />
</div>
- Now hit the **Run** button next to the query name to run the query.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/runquery.png)
</div>
- Once you run the query, you can check the data returned by the query in the **Inspector** on the left sidebar.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/inspectord.png)
</div>
- Now that we have got the data, we will display it on the table. To do this, click on the widget handle of the table to open its properties in the right sidebar.
- In the Table Data field, enter `{{queries.crypto.data.coins}}` - as you can see in the screenshot of the inspector the data is inside the `coins` array. You'll see the data in the Preview(green box) below the field.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/data.png)
</div>
- Let's add the columns that we want to display on the table. Go to the **Columns** section, Add columns, set their Names, and set **key** for each column. I have added 5 columns: **Rank**, **Name**, **Symbol**, **Price**, and **Market Cap**.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/columns.png)
</div>
- Once you've added the columns, you'll get the table like this:
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/table.png)
</div>
### Using cellValue to change column text color
Now that we have our data on the table, we will change the color of the text in the **Price** and **Market Cap** columns.
- Edit table properties, go to **Columns**, and click on the Price Column to open its properties.
- For **Price** column, we want to change color of those cells who have value which is greater than 1000 to red else to green if it is less than 1000. So to do this, we will set a condition in **Text Color** property of this column: `{{cellValue >= 1000 ? 'red' : 'green'}}`
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/price.png)
</div>
- Similarly, we will do for **Market Cap** column. We want to change the text color of those cells who have value which is greater than 60000000000 to red else to green if it is less than 60000000000. so the condition will be `{{cellValue >= 60000000000 ? 'red' : 'green'}}`
- Now the text color of cells in the columns will be updated.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/cellvalue.png)
</div>
:::info
You can also use Hex Color Code instead of mentioning color in plane text.
:::
### Using rowData to change column text color
- To change the color of the text using `rowData` variable it is required to mention the column name whose cell value we will be comparing in the condition. Let's take a look by changing the text color of **Symbol** column.
- We will add a condition to look in the row data and if the row has column called `name` which has value `Solana` then it should change the color to red else the color should be green.
- Edit the properties of the Symbol column, set the **Text Color** field value to `{{rowData.name === 'Solana' ? 'red' : 'green'}}`.
- You'll see that in the Symbols column all the values has become green except the one that has Solana in Name column.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/rowData.png)
</div>
You can use the above methods to change the text and background colors of a cell dynamically.

View file

@ -1,54 +1,36 @@
---
id: access-currentuser
title: Enable/Disable a component using current user's property
title: Enable/Disable a Component Using Current User's Property
---
# Enable/Disable a component using current user's property
Let's take look at the exposed variables of the current user property:
Let's take a look at the exposed variables of the currentUser property by clicking on the **[inspector](/docs/app-builder/left-sidebar/#inspector)** icon on the left sidebar:
- **email** : The value can accessed using `{{globals.currentUser.email}}`
- **firstName** : The value can accessed using `{{globals.currentUser.firstName}}`
- **lastName** : The value can accessed using `{{globals.currentUser.lastName}}`
- **lastName** : The value can accessed using `{{globals.currentUser.lastName}}`
- **groups** : By default, the admin will be in the two groups `all_users` and `admin`, and any user who is not admin will always be in the `all_users` group by default. Since the **groups** is an array youll have to provide the index ([0], [1], and so on) to return the group name. The value can be accessed using `{{globals.currentUser.groups[1]}}`.
- **groups**: The `groups` attribute is an array representing the groups a user belongs to. By default, every user, including admins, is part of the `all_users` group. Additionally, admins are also part of the `admin` group. To access a specific group name, you need to specify the array index, such as `[0]` for the first group, `[1]` for the second, and so on. For example, you can retrieve the name of the second group a user belongs to with `{{globals.currentUser.groups[1]}}`.
<div style={{textAlign: 'center'}}>
### Example: Disable a Button if a User is Not Admin
<img className="screenshot-full" src="/img/how-to/access-currentuser/props.png" alt="Properties of current user" />
- Click on the **Button** handle to open its properties. On the **Styles** tab, go to the **Disable** property.
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/button.png" alt="Properties of button" />
</div>
### Example: Disable a button if a user is not admin
- Configure the Disable field with a condition that checks the user's group membership. If the user is not an admin, as determined by the absence of the admin value in the first position (index [1]) of the groups array, the field should be disabled. Use the following JavaScript condition for this purpose:
- Click on the **Button** handle to open its properties, on the **Styles** tab go to the **Disable** property.
```javascript
{{globals.currentUser.groups[1] !== "admin" ? true : false}}
```
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" width="100%" src="/img/how-to/access-currentuser/disable.png" alt="Disable Property of button" />
</div>
<img className="screenshot-full" src="/img/how-to/access-currentuser/button.png" alt="Properties of button" />
- Now, when you **release** the app, if the user is not a part of the **admin** group, the button will be disabled.
</div>
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" width="100%" src="/img/how-to/access-currentuser/released.png" alt="Released button disabled when user is not admin" />
</div>
- Set a condition on the Disable field so that if the the user who is using the app does not have **admin** value in the first index of **groups** array return **true**. The condition can be:
```javascript
{{globals.currentUser.groups[1] !== "admin" ? true : false}}
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/disable.png" alt="Disable Property of button" />
</div>
- Now, when you'll **release** the app, if the user is not is not admin the button will be disabled.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/released.png" alt="Released button disabled when user is not admin" />
</div>
:::info
In this how-to we have used the **Groups** property of the **Current User**. You can use any of the exposed variables mentioned above according to your use.
:::

View file

@ -8,8 +8,8 @@ title: Build a new plugin for marketplace
ToolJet marketplace is a place where you can find custom plugins and install them in your ToolJet instance. This document will help you to build a new plugin for ToolJet marketplace.
## Prerequisites
- [Node.js](https://nodejs.org/en/download/) (v18.3.0)
- [npm](https://www.npmjs.com/get-npm) (v8.11.0)
- [Node.js](https://nodejs.org/en/download/) (v18.18.2)
- [npm](https://www.npmjs.com/get-npm) (v9.8.1)
## Getting started
### 1. Enabling the marketplace for your instance

View file

@ -1,45 +1,113 @@
---
id: loading-image-pdf-from-db
title: Loading image/PDF from base64 string
title: Upload And View Images and PDFs Using Base64 String
---
In this how-to guide we will see how we can load an image or PDF file using the base64 string available on the database. In this how-to, we have used the postgres database which already has the base64 strings for the image or the PDF files available.
This guide shows how to upload and view images and PDFs using the base64 string format.
- Let's drag a **filepicker** component onto the canvas, and pick one image and one pdf file
<div style={{textAlign: 'center'}}>
## 1. Start by Creating a New Table In ToolJet Database
<img className="screenshot-full" src="/img/how-to/load-base64/filepicker.png" alt="Loading image from base64 string" width="700" />
- Create a new table named *testDB*.
- The `id` field will be present by default to create a unique identifier for each record in our database table.
- Click on **Add more columns** button and add two more columns: `pdf` and `image`.
- Select `varchar` as datatype for the pdf and image columns.
</div>
<i>While we are using the ToolJet Database for this guide; feel free to use other databases while applying the same principles.</i>
- Now, create a query for inserting an image from the filepicker. As you can see in the screenshot below, we are using the **exposed variable** of the filepicker component to retrieve the **base64** data of the uploaded files.
<div style={{textAlign: 'center'}}>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/create-new-table.png" alt="New Table" />
</div>
<img className="screenshot-full" src="/img/how-to/load-base64/insert.png" alt="Loading image from base64 string" width="500"/>
## 2. Upload Files To The Database
</div>
- Create a new application and name it *Load PDF And Images Example*.
- Drag and drop two **[Filepicker](/docs/widgets/file-picker)** components on the canvas from the components library on the right.
- Rename the first Filepicker component to *imagePicker* and second Filepicker to *pdfPicker*.
- Create another query for returning the data from the database and we will use this base64 data returned in this query to display on the image and pdf components.
<div style={{textAlign: 'center'}}>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/filepickers-rename.png" alt="Rename Filepickers" />
</div>
<img className="screenshot-full" src="/img/how-to/load-base64/get.png" alt="Loading image from base64 string" width="500"/>
- For *pdfPicker*, change the **Accept file types** property to `{{"pdf/*"}}` - this ensures that the Filepicker only accepts PDF files.
</div>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-accepted-file-type.png" alt="Accepted File Type Settings" />
</div>
- Drag the image and a PDF component on the canvas. Edit the property of the PDF component and in the **file URL** enter:
```js
{{'data:image/png;base64,' + queries.get.data[7].pdf}}
```
Similarly for the image component:
```js
{{'data:image/jpeg;base64,' + queries.get.data[7].image}}
```
<div style={{textAlign: 'center'}}>
- Retain the default `{{"image/*"}}` setting for the Accept file types property in the *imagePicker* component, as it's intended for image uploads.
- Click on the *imagePicker* component and select an image to upload. Similarly, upload a PDF using the *pdfPicker* component.
<img className="screenshot-full" src="/img/how-to/load-base64/pdf.png" alt="Loading image from base64 string" />
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/filepickers-with-uploaded-files.png" alt="Uploaded Files" />
</div>
</div>
- After uploading, you will see the filenames displayed on their respective Filepicker components.
- Click on the **+ Add** button in the query panel to create a new query, choose Tooljet Database as the data source, select `testDB` as Table name, and `Create Row` as Operations. Name this query *uploadFiles*.
- Under the Columns section, add two columns - `pdf` and `image`.
- Set the below value for the `pdf` column:
```js
{{components.pdfPicker.file[0].base64Data}}
```
- Similarly, for the `image` column:
```js
{{components.imagePicker.file[0].base64Data}}
```
:::info
<i>In the above query, we are using the <b>exposed variables</b> of both Filepicker components to get the base64 strings of the files we had uploaded earlier.</i>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/add-files-query.png" alt="Add Files Query" />
</div>
- Add a **[Button](/docs/widgets/button)** component below the Filepickers and rename it to *upload*.
- Set the Button's text to *Upload* and create a **New event handler** with the following settings: Event - `On click`, Action - `Run Query` and Query - `uploadFiles`.
- Click on the *upload* button to upload the files that we had selected in the Filepicker components earlier.
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/upload-button-properties.png" alt="Upload Button Properties" />
</div>
The upload process is now complete. Whenever files are selected in the Filepicker components and the *upload* button is clicked, the base64 strings of these files will be automatically written to the database.
## 3. View Image and PDF Files
- Create a query named *getFiles* to retrieve base64 strings from testDB: Click on **+ Add** button in the query panel, select Tooljet as Database, `testDB` as Table name, and `List rows` as Operations.
- Enable **Run this query on application load?** and click on the **Run** button to run the getFiles query.
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/fetch-files-query.png" alt="Fetch Files Query" />
</div>
- Drag an **[Image](/docs/widgets/image)** and a **[PDF](/docs/widgets/pdf)** component on the canvas from the components library. Rename the **Image** component to *displayImage* and the **PDF** component to *displayPDF*.
- In the **URL** property of the **displayImage** component, enter:
```js
{{'data:image;base64,' + queries.getFiles.data[0].image}}
```
- Let's apply the same logic for the **displayPDF** component and enter the below value in the **File URL** property:
```js
{{'data:pdf;base64,' + queries.getFiles.data[0].pdf}}
```
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-with-fileURL.png" alt="PDF Component With File URL" />
</div>
<i>The provided code constructs a Data URL to display the base64-encoded data as an image or PDF.</i>
<br/>
<br/>
Here's what our final interface will look like:
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-image-view.png" alt="Final Preview" />
</div>
<i>
You can also use transformations in the query response and concat `data:image/jpeg;base64,` to the base64 data.
:::
</i>
<br/>
<br/>
Using the above logic, you can upload and view files in ToolJet using the base64 data.

View file

@ -0,0 +1,277 @@
---
id: use-events-on-chart
title: Use Events on Chart
---
Currently, the chart component does not support events. However, you can use the Custom Component to create a chart using a third-party library that supports events. Plotly is one of the libraries that supports events. In this tutorial, we will build a chart using Plotly and add events to it.
<div style={{textAlign: 'center'}}>
<img style={{ border:'0'}} className="screenshot-full" src="/img/how-to/events-chart/plotly-chart.png" alt="Plotly Chart" />
</div>
## Step 1: Add a Custom Component
Open the App Builder and add a Custom Component to the page. Then, click on the Custom Component to open the Properties panel.
Note: If you are not familiar with the Custom Component, please read the [Custom Component](/docs/widgets/custom-component/) doc.
## Step 2: Add the code to the Custom Component
```js
import React from 'https://cdn.skypack.dev/react';
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core';
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min';
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory';
const MyCustomComponent = ({data, updateData, runQuery}) => {
const Plot = createPlotlyComponent(Plotly);
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
return (
<Container>
<Plot data={[
{
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick}
/>
</Container>
)}
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent);
ReactDOM.render(<ConnectedComponent />, document.body);
```
Let's understand the code above in detail. First, we imported the required libraries.
```js
import React from 'https://cdn.skypack.dev/react'; // React library
import ReactDOM from 'https://cdn.skypack.dev/react-dom'; // React DOM library
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core'; // Material UI library
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min'; // Plotly library
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory'; // Plotly React library
```
Then, we created a function component called `MyCustomComponent`. This component will render the chart. We use the `createPlotlyComponent` function to create a Plotly component. Then, we create a function called `barOnClick` that will be called when the user clicks on the bar. This function will display an alert message.
```js
const MyCustomComponent = ({data, updateData, runQuery}) => { // function component
const Plot = createPlotlyComponent(Plotly); // create a Plotly component
const barOnClick = ({points}) => { // function that will be called when the user clicks on the bar
alert('A bar is clicked') // display an alert message
}
```
Next, we render the chart using the `Plot` component. We pass the data and layout to the `Plot` component. We also pass the `barOnClick` function to the `onClick` prop of the `Plot` component.
```js
return ( // return the Plot component
<Container> // Material UI Container component
<Plot data={[ // Plot component
{ // data for the first bar
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{ // data for the second bar
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{ // layout for the chart
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick} // pass the barOnClick function to the onClick prop
/>
</Container>
)}
```
Finally, we render the `MyCustomComponent` component using the `ReactDOM.render` function.
```js
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent); // connect the component to the Tooljet store
ReactDOM.render(<ConnectedComponent />, document.body); // render the component
```
## Step 3: Using events from the Custom Component
In the code above, we created a function called `barOnClick` that will be called when the user clicks on the bar. This function holds the code that will be executed when the user clicks on the bar.
```js
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
```
Instead of displaying an alert message, you can use the `runQuery` function to run a query.
```js
const barOnClick = ({points}) => {
runQuery('queryName')
}
```
`runQuery` is a function which accepts a query name as a string used to run the query from the custom component. Learn more about the custom component [here](/docs/widgets/custom-component/).

View file

@ -1,90 +1,83 @@
---
id: use-form-component
title: Use form component
title: Use Form Component
---
In this how-to guide, we will be building a simple application that will leverage the form component for adding a record into the database. For this guide, we will be using Google Sheet datasource to read and write data.
In this guide, we'll create a simple app that uses a **[Form](/docs/widgets/form)** component to add records to a database. We'll use **[ToolJet Database](/docs/tooljet-database)** as our data source.
## 1. Create a Table in ToolJet Database
- Create a table named *products* in ToolJet Database.
- Create three columns - `name`, `quantity` and `price`.
- Add some sample data to the table.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/final.png" alt="how-to use form" />
<img className="screenshot-full" src="/img/how-to/use-form/database-table.png" alt="Database Table" width="100%" />
</div>
- Let's connect to the datasource i.e. Google Sheets and give the `Read and Write` permission.
<div style={{textAlign: 'center'}}>
## 2. Create the UI
- Create a new app and drag and drop a **[Table](/docs/widgets/table)** component on the canvas.
- Drop a **[Form](/docs/widgets/form)** next to it.
- Since we have three columns in the database, let's update the Form with one **[Text Input](/docs/widgets/text-input)** for `name` and two **[Number Inputs](/docs/widgets/text-input)** for `quantity` and `price`.
- Name the three input fields on the form as - *nameInput*, *quantityInput* and *priceInput*. Name the button as *submitButton*.
<img className="screenshot-full" src="/img/how-to/use-form/read.png" alt="how-to use form" />
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/user-interface.png" alt="User Interface" width="100%" />
</div>
<i>Naming the components can help in easily identifying or referring individual components when there are a large number of components in the app</i>.
</div>
- Now, drag a table on the canvas and add the form component next to it.
<div style={{textAlign: 'center'}}>
## 3. Load the Table Component With Data
<img className="screenshot-full" src="/img/how-to/use-form/table1.png" alt="how-to use form" />
- Click on the Add button in the **[Query Panel](/docs/app-builder/query-panel/)**, select ToolJet Database
- Rename the query to *getProducts*
- Choose *products* as Table name, List rows as Operations
- Enable `Run this query on application load?` to automatically run the query when the app starts
- Click on Run to fetch data
- Click on the Table component to open its configuration panel on the right. Under the `Data` property, paste the below code:
```js
{{queries.getProducts.data}}
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/load-data.png" alt="Table with Data" width="100%" />
</div>
</div>
## 4. Write Data Using the Form Component
- Click on the Add button in the Query Panel, select ToolJet Database
- Select *products* as Table name, Create row as Operations
- Rename the query to *addProduct*
- Click on Add Column and add three columns - **name**, **quantity** and **price**
- Enter code below for **name**, **quantity** and **price** column keys:
- Currently, the table component is populated with the sample data that it has by default. Let's create a **new query** from the query panel and choose the **Google Sheet** datasource.
<div style={{textAlign: 'center'}}>
```js
{{components.form.data.nameInput.value}}
{{components.form.data.quantityInput.value}}
{{components.form.data.priceInput.value}}
```
<img className="screenshot-full" src="/img/how-to/use-form/query.png" alt="how-to use form" />
To ensure the Table component updates with new data after adding products, trigger the *getProducts* query following each *addProduct* query execution. Here's how:
</div>
- Click on **New event handler** in the *addProduct* query to add a new event.
- For the new event, leave the event as Query Success, set Run Query as the Action and choose *getProducts* as the Query.
- The query will read the data from the database and we will use the returned data to populate the table. Go to the **table** property and in the table data value enter **{{queries.queryname.data}}** where queryname is the name of the query that we created in previous step.
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/refresh-table.png" alt="Refresh Table" width="100%" />
</div>
<img className="screenshot-full" src="/img/how-to/use-form/populate.png" alt="how-to use form" />
<i>This process refreshes the Table component with the latest data from the database.</i>
<br/>
<br/>
</div>
- Next, click on the Form component and set `Button To Submit Form` as *submitButton*.
- Add a **New event handler** to the Form component. Keep On submit as Event, Run Query as Action and select *addProduct* as the Query.
- let's go to the form and add the components inside it required for adding a record into the database.
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center', marginBottom: '15px'}}>
<img className="screenshot-full" src="/img/how-to/use-form/write-data-query.png" alt="Table with Data" width="100%" />
</div>
<img className="screenshot-full" src="/img/how-to/use-form/form1.png" alt="how-to use form" />
Now if you enter the product data on the form and click on Submit. The `addProduct` query will run and the entered data will be written to the `products` table in the ToolJet Database.
</div>
<div style={{textAlign: 'center', marginBotton: '15px', marginTop: '15px'}}>
<img className="screenshot-full" src="/img/how-to/use-form/final-preview.png" alt="Final Preview" width="100%" />
</div>
<br/>
- Since our database record has five fields **Id**, **Title**, **Price**, **Category** and **Image** we will add the components in the form for the same. The form already comes with a Submit button so we don't have to add that. For Id, Title, and Image we will use text-input, for Price we will use number-input and for category we can use dropdown components.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/form2.png" alt="how-to use form" />
</div>
- Before editing the form properties, let's make a few changes in the components that we have added inside it. First edit the property of the **number input** and set the default value, maximum and minimum value, and then edit the **dropdown** component and set the option values and option labels.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/categ.png" alt="how-to use form" />
</div>
- Now, we can edit the properties of the form component. Go to its properties, in **Button To Submit Form** select the button1 that was already there on the form. Go to event handler, and for **On submit** event we will **run the query** that will get the data from the form and will store into the database.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/event.png" alt="how-to use form" />
</div>
- Let's create a query that will get the data from the form and add a record in the sheet. Create a new google sheet query and from the operation choose **Append data to a spreadsheet**
```js
[
{
"id":"{{components.form1.data.textinput1.value}}",
"title":"{{components.form1.data.textinput2.value}}",
"price":"{{components.form1.data.numberinput1.value}}",
"category":"{{components.form1.data.dropdown1.value}}",
"image":"{{components.form1.data.textinput4.value}}"
}
]
```
- Once done, save the query and add it to the Form's event handler.
- Now, this application can be used to load the data from the Google Sheet and the form can be used to append more records to the sheet.
:::tip
- Make sure to enable **Run query on page load?** option of the **read** query to populate the table everytime the app is loaded
- You can also add a event handler on the **append** query to run the **read** query when **append** is successful, this will update the table data when the append is done
- Learn more about the connecting Google sheet datasource and the CRUD **operations** available [here](/docs/data-sources/google.sheets).
:::
In this how-to guide, we have explored a practical application of the Form component in ToolJet. You can apply the same principles for a variety of use cases that requires data input from the end-user.

View file

@ -1,124 +1,63 @@
---
id: use-inspector
title: Use Inspector
title: Use Inspector in App-Builder
---
In this how-to guide, we will take a look at **Inspector** of the app-builder and see how it can be helpful in building applications.
The Inspector can be used to inspect the data of the queries, properties and values of the components that are there on the canvas, ToolJet's global variables and the variables that have been set by the user.
This guide introduces **Inspector** in the app-builder, a feature that lets you view data related to queries, components, global variables, page-related variables, user-set variables and constants.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/inspector.png" alt="How to - Use Inspector" width="500" />
<img className="screenshot-full" src="/img/how-to/use-inspector/use-inspector-preview.png" alt="Preview of Use Inspector" width="100%" />
</div>
## Layout
Let's take a look at the layout of the Inspector panel:
- On the top-right, we have a **Pin** button to pin and unpin the inspector panel. This button can be useful when you want to see the live changes on inspector while triggering a query or performing some event/action on any component.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/pin.png" alt="How to - Use Inspector" width="500" />
</div>
- At the bottom right, you can click and hold to resize the inspector.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/resize.png" alt="How to - Use Inspector" width="500" />
</div>
- On hovering an item on the inspector, the **copy path** and **copy value** buttons will appear on the right of the item. Copying the path and pasting it onto the component property or query parameter will always get the dynamic value but using `Copy value` option will copy the current value of the item and will be static when pasted in a component property or query parameter.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/path.png" alt="How to - Use Inspector" width="500" />
</div>
## Sections
The Inspector panel has the following 4 main sections:
The Inspector panel has 6 main sections:
- **[queries](#queries)**
- **[components](#components)**
- **[globals](#globals)**
- **[variables](#variables)**
- **[Queries](#queries)**
- **[Components](#components)**
- **[Globals](#globals)**
- **[Variables](#variables)**
- **[Page](#page)**
- **[Constants](#constants)**
### queries
The queries section can be used to inspect the query details but the data of the query will only be available if query has been run/triggered.
### Queries
:::tip
You can click on the Preview button of the button on the query manager to check the response(data) of the query without triggering it.
:::
Queries allow you to inspect the specifics of your queries. However, the data related to these queries will only be visible after they have been executed or triggered.
#### Example
- Let's create a new query using a mock REST API endpoint (`https://fakestoreapi.com/products`).
- Now go to the Inspector and expand the **queries** section, you'll see an entry inside queries with the query name that we created in the previous step i.e. `restapi1` but if you notice the `data` and `rawData` object is empty i.e. 0 entry. The reason is the data won't show up on the inspector unless query is run.
<div style={{textAlign: 'center'}}>
### Components
<img className="screenshot-full" src="/img/how-to/use-inspector/data0.png" alt="How to - Use Inspector" />
Under Components, you can view and analyze the properties and values of the components you've added to the canvas, providing insights into how each component functions within your app.
</div>
### Globals
- Let's pin the inspector and then trigger the query from the query manager. You'll see that as soon as the query is triggered the `rawData` and `data` object in the query has 20 entries and the query has more properties like `request`, `response`, and `responseHeaders` data.
<div style={{textAlign: 'center'}}>
Globals give you access to global information related to the app.
<img className="screenshot-full" src="/img/how-to/use-inspector/data1.png" alt="How to - Use Inspector" />
The globals selection consists of the following data:
</div>
### components
components section can be used to inspect the properties and values of the components that are added onto the canvas.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/components.png" alt="How to - Use Inspector" width="500" />
</div>
### globals
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/globals.png" alt="How to - Use Inspector" width="500" />
</div>
The globals section consists of the following sub-sections:
- **currentUser:** The currentUser object contains information about the currently logged-in user, such as their **email**, **firstName**, and **lastName**.
- **groups:** The groups array contains the names of the groups to which the currently logged-in user belongs. Note: The `all_users` group is a default group for everyone.
- **theme:** The theme object contains the name of the currently active theme.
- **urlparams:** The urlparams contain information about the URL parameters of the application.
- **environment:** This variable holds two keys: **id** and **name**. The **id** is a unique identifier generated automatically, and the **name** holds the name of the currently opened environment of the app version.
- **modes:** This variable holds one of three values: **edit**, **preview**, or **view**, depending on the current state of the app. If the app is opened in editing mode, the mode will be set to **edit**. If the app is opened by clicking the preview button on the app builder, the variable will be set to **preview**. If the app is opened using the URL from the **Share** modal, the mode will be set to **view**.
:::tip
The **environment** and **mode** variables are only available in **ToolJet Enterprise Edition v2.2.3** and above.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/env.png" alt="How to - Use Inspector" width="500" />
</div>
:::
- **currentUser:** Contains details about the user who is currently logged in, like their **email**, **firstName**, and **lastName**.
- **groups:** A list of group names that the logged-in user is part of. Note: The `all_users` group is a default group for everyone.
- **theme:** Shows the name of the theme that is currently being used.
- **urlparams:** Details about the URL parameters of the app.
- **environment:** Has two parts: **id**, a unique auto-generated identifier, and **name**, the name of the current environment of the app version.
- **modes:** Indicates whether the app is in **edit**, **preview**, or **view** mode. **Edit** is for editing the app, **preview** is used when the preview button in the app builder is clicked, and **view** is for when the app is opened through a shared URL.
:::info
All the global variables can be accessed anywhere within ToolJet applications. Here's an **[example use-case](/docs/how-to/access-currentuser)** that demonstrates the usage of these variables.
:::
### variables
### Variables
variables section include all the variables set by the user in the application. These variables can be set from the event handlers from the components or from the queries. The variables will be in the **key-value** pair and can be accessed throughout the application.
Variables shows user-defined variables in a key-value format. These variables, set through event handlers or queries, are accessible across the entire application. You can set variables from the [event handler](/docs/actions/set-variable) or using [JavaScript code](/docs/how-to/run-actions-from-runjs#set-variable).
### Page
Page lets you view page-specific properties like page name, handle and variables. Page variables are restricted to their respective pages and are not accessible application-wide.
### Constants
Under **[Constants](/docs/org-management/workspaces/workspace_constants/)**, you can find the predefined values (usually tokens/secret keys/API keys) that can be used across your application to maintain consistency and facilitate easy updates.
:::info
- Setting variables from the [event handler](/docs/actions/set-variable)
- Setting variables from the [Run JavaScript code](/docs/how-to/run-actions-from-runjs#set-variable)
:::
The **environment** and **mode** variables are only available in **ToolJet Enterprise Edition v2.2.3** and above.
:::

View file

@ -120,6 +120,10 @@ You can refer to the [JSON Chart Schema](https://plotly.com/chart-studio-help/js
</div>
:::tip Using events on chart
Currently, the chart component does not support events. However, you can use the Custom Component using Plotly and add events to it. Check out the [How to use events on chart](/docs/how-to/use-events-on-chart) to learn more.
:::
### Bar Mode
The **Bar Mode** option allows you to customize the layout and display style specifically for bar charts. This option becomes available when the **Plotly JSON chart schema** toggle is enabled and a JSON schema specific to bar charts is provided. This option provide different modes for organizing and presenting bars within the chart.

View file

@ -102,7 +102,8 @@ module.exports = {
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} ToolJet Solutions, Inc.`,
copyright: `Copyright © ${new Date().getFullYear()} ToolJet Solutions, Inc.
<img referrerpolicy="no-referrer-when-downgrade" src="https://static.scarf.sh/a.png?x-pxid=4f00afac-ae1f-4cf6-8c53-8a2c7b3ca206" />`,
},
algolia: {
appId: 'O8HQRLI0WA',
@ -121,12 +122,14 @@ module.exports = {
// Please change this to your repo.
editUrl: 'https://github.com/ToolJet/Tooljet/blob/develop/docs/',
includeCurrentVersion: false,
lastVersion: '2.25.0',
lastVersion: '2.27.0',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
sitemap: {},
sitemap: {
ignorePatterns: ['/1.x.x/', '/docs/1.x.x/'],
},
googleTagManager: isProd
? {
containerId: process.env.GTM,

View file

@ -385,6 +385,7 @@ const sidebars = {
'how-to/upload-files-aws',
'how-to/upload-files-gcs',
'how-to/loading-image-pdf-from-db',
'how-to/use-events-on-chart',
],
},
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 KiB

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 KiB

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

38
docs/static/robot.txt vendored Normal file
View file

@ -0,0 +1,38 @@
User-agent: *
Disallow: /1.x.x/
Disallow: /docs/1.x.x/
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ###################################################/,,,,########################
# ############################################ ########################
# ########################################* ########################
# ###################################### ,##( (########################
# ############################## #### ##########################
# ########################### ###########################
# ########################## #############################
# #################################, ###############################
# #################################### #################################
# ############################# /######. #################################
# ###########################* ##### ##################################
# ########################### ######## (###################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################
# ################################################################################

View file

@ -157,4 +157,4 @@ Any property having `Fx` button next to its field can be **programmatically conf
| Actions | Description |
| -------- | ----------- |
| selectOption | You can set an option on the dropdown component via a component-specific action within any event handler. Additionally, you have the option to employ a RunJS query to execute component-specific actions such as `await components.dropdown1.setOption(1)` |
| selectOption | You can set an option on the dropdown component via a component-specific action within any event handler. Additionally, you have the option to employ a RunJS query to execute component-specific actions such as `await components.dropdown1.selectOption(1)` |

View file

@ -76,7 +76,7 @@ The maximum accepted number of files The default value is `2`.
### Accept file types
By providing types, you can make the dropzone accept specific file types and reject the others.
By providing types, you can make the dropzone accept specific file types and reject the others. Example: `{{"image/*,application/pdf,application/msword"}}`
### Max size limit

View file

@ -0,0 +1,277 @@
---
id: use-events-on-chart
title: Use Events on Chart
---
Currently, the chart component does not support events. However, you can use the Custom Component to create a chart using a third-party library that supports events. Plotly is one of the libraries that supports events. In this tutorial, we will build a chart using Plotly and add events to it.
<div style={{textAlign: 'center'}}>
<img style={{ border:'0'}} className="screenshot-full" src="/img/how-to/events-chart/plotly-chart.png" alt="Plotly Chart" />
</div>
## Step 1: Add a Custom Component
Open the App Builder and add a Custom Component to the page. Then, click on the Custom Component to open the Properties panel.
Note: If you are not familiar with the Custom Component, please read the [Custom Component](/docs/widgets/custom-component/) doc.
## Step 2: Add the code to the Custom Component
```js
import React from 'https://cdn.skypack.dev/react';
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core';
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min';
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory';
const MyCustomComponent = ({data, updateData, runQuery}) => {
const Plot = createPlotlyComponent(Plotly);
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
return (
<Container>
<Plot data={[
{
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick}
/>
</Container>
)}
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent);
ReactDOM.render(<ConnectedComponent />, document.body);
```
Let's understand the code above in detail. First, we imported the required libraries.
```js
import React from 'https://cdn.skypack.dev/react'; // React library
import ReactDOM from 'https://cdn.skypack.dev/react-dom'; // React DOM library
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core'; // Material UI library
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min'; // Plotly library
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory'; // Plotly React library
```
Then, we created a function component called `MyCustomComponent`. This component will render the chart. We use the `createPlotlyComponent` function to create a Plotly component. Then, we create a function called `barOnClick` that will be called when the user clicks on the bar. This function will display an alert message.
```js
const MyCustomComponent = ({data, updateData, runQuery}) => { // function component
const Plot = createPlotlyComponent(Plotly); // create a Plotly component
const barOnClick = ({points}) => { // function that will be called when the user clicks on the bar
alert('A bar is clicked') // display an alert message
}
```
Next, we render the chart using the `Plot` component. We pass the data and layout to the `Plot` component. We also pass the `barOnClick` function to the `onClick` prop of the `Plot` component.
```js
return ( // return the Plot component
<Container> // Material UI Container component
<Plot data={[ // Plot component
{ // data for the first bar
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{ // data for the second bar
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{ // layout for the chart
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick} // pass the barOnClick function to the onClick prop
/>
</Container>
)}
```
Finally, we render the `MyCustomComponent` component using the `ReactDOM.render` function.
```js
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent); // connect the component to the Tooljet store
ReactDOM.render(<ConnectedComponent />, document.body); // render the component
```
## Step 3: Using events from the Custom Component
In the code above, we created a function called `barOnClick` that will be called when the user clicks on the bar. This function holds the code that will be executed when the user clicks on the bar.
```js
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
```
Instead of displaying an alert message, you can use the `runQuery` function to run a query.
```js
const barOnClick = ({points}) => {
runQuery('queryName')
}
```
`runQuery` is a function which accepts a query name as a string used to run the query from the custom component. Learn more about the custom component [here](/docs/widgets/custom-component/).

View file

@ -120,6 +120,10 @@ You can refer to the [JSON Chart Schema](https://plotly.com/chart-studio-help/js
</div>
:::tip Using events on chart
Currently, the chart component does not support events. However, you can use the Custom Component using Plotly and add events to it. Check out the [How to use events on chart](/docs/how-to/use-events-on-chart) to learn more.
:::
### Bar Mode
The **Bar Mode** option allows you to customize the layout and display style specifically for bar charts. This option becomes available when the **Plotly JSON chart schema** toggle is enabled and a JSON schema specific to bar charts is provided. This option provide different modes for organizing and presenting bars within the chart.

View file

@ -3,7 +3,9 @@ id: gitsync
title: GitSync
---
GitSync feature allows users to synchronize the applications on their workspace with a git repository. GitSync feature simplifies the process of managing and version controlling your applications on ToolJet.
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
The GitSync feature enables synchronization of workspace applications with a git repository, streamlining application management and version control on ToolJet.
## Overview

View file

@ -0,0 +1,277 @@
---
id: use-events-on-chart
title: Use Events on Chart
---
Currently, the chart component does not support events. However, you can use the Custom Component to create a chart using a third-party library that supports events. Plotly is one of the libraries that supports events. In this tutorial, we will build a chart using Plotly and add events to it.
<div style={{textAlign: 'center'}}>
<img style={{ border:'0'}} className="screenshot-full" src="/img/how-to/events-chart/plotly-chart.png" alt="Plotly Chart" />
</div>
## Step 1: Add a Custom Component
Open the App Builder and add a Custom Component to the page. Then, click on the Custom Component to open the Properties panel.
Note: If you are not familiar with the Custom Component, please read the [Custom Component](/docs/widgets/custom-component/) doc.
## Step 2: Add the code to the Custom Component
```js
import React from 'https://cdn.skypack.dev/react';
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core';
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min';
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory';
const MyCustomComponent = ({data, updateData, runQuery}) => {
const Plot = createPlotlyComponent(Plotly);
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
return (
<Container>
<Plot data={[
{
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick}
/>
</Container>
)}
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent);
ReactDOM.render(<ConnectedComponent />, document.body);
```
Let's understand the code above in detail. First, we imported the required libraries.
```js
import React from 'https://cdn.skypack.dev/react'; // React library
import ReactDOM from 'https://cdn.skypack.dev/react-dom'; // React DOM library
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core'; // Material UI library
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min'; // Plotly library
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory'; // Plotly React library
```
Then, we created a function component called `MyCustomComponent`. This component will render the chart. We use the `createPlotlyComponent` function to create a Plotly component. Then, we create a function called `barOnClick` that will be called when the user clicks on the bar. This function will display an alert message.
```js
const MyCustomComponent = ({data, updateData, runQuery}) => { // function component
const Plot = createPlotlyComponent(Plotly); // create a Plotly component
const barOnClick = ({points}) => { // function that will be called when the user clicks on the bar
alert('A bar is clicked') // display an alert message
}
```
Next, we render the chart using the `Plot` component. We pass the data and layout to the `Plot` component. We also pass the `barOnClick` function to the `onClick` prop of the `Plot` component.
```js
return ( // return the Plot component
<Container> // Material UI Container component
<Plot data={[ // Plot component
{ // data for the first bar
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{ // data for the second bar
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{ // layout for the chart
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick} // pass the barOnClick function to the onClick prop
/>
</Container>
)}
```
Finally, we render the `MyCustomComponent` component using the `ReactDOM.render` function.
```js
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent); // connect the component to the Tooljet store
ReactDOM.render(<ConnectedComponent />, document.body); // render the component
```
## Step 3: Using events from the Custom Component
In the code above, we created a function called `barOnClick` that will be called when the user clicks on the bar. This function holds the code that will be executed when the user clicks on the bar.
```js
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
```
Instead of displaying an alert message, you can use the `runQuery` function to run a query.
```js
const barOnClick = ({points}) => {
runQuery('queryName')
}
```
`runQuery` is a function which accepts a query name as a string used to run the query from the custom component. Learn more about the custom component [here](/docs/widgets/custom-component/).

View file

@ -120,6 +120,10 @@ You can refer to the [JSON Chart Schema](https://plotly.com/chart-studio-help/js
</div>
:::tip Using events on chart
Currently, the chart component does not support events. However, you can use the Custom Component using Plotly and add events to it. Check out the [How to use events on chart](/docs/how-to/use-events-on-chart) to learn more.
:::
### Bar Mode
The **Bar Mode** option allows you to customize the layout and display style specifically for bar charts. This option becomes available when the **Plotly JSON chart schema** toggle is enabled and a JSON schema specific to bar charts is provided. This option provide different modes for organizing and presenting bars within the chart.

View file

@ -97,7 +97,7 @@ npm run build:plugins
```
npm run --prefix server db:create
npm run --prefix server db:mirgate
npm run --prefix server db:migrate
```
If at any point you need to reset the database, use this command `npm run --prefix server db:reset`
@ -114,4 +114,4 @@ cd ./frontend && NODE=production npm run build
cd ./server && npm run start:prod
```
The client will start on the **port 3000**, you can access the client by visiting the url created by codespace - `https://<url>/apps/tooljet`
The client will start on the **port 3000**, you can access the client by visiting the url created by codespace - `https://<url>/apps/tooljet`

View file

@ -3,7 +3,10 @@ id: gitsync
title: GitSync
---
GitSync feature allows users to synchronize the applications on their workspace with a git repository. GitSync feature simplifies the process of managing and version controlling your applications on ToolJet.
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
The GitSync feature enables synchronization of workspace applications with a git repository, streamlining application management and version control on ToolJet.
## Overview

View file

@ -1,115 +1,62 @@
---
id: access-cellvalue-rowdata
title: Change text color in columns of the table
title: Dynamically Change Cell Colors in Table
---
# Change text color in columns by accessing `cellValue` and `rowData` in the table
This guide shows how to change the text color and background color of certain cells in a Table component based on specific conditions.
In this how-to guide, we will build an app that will use a sample RestAPI to display the data in the table, and then we will change the text color of the columns according to the condition.
## 1. Start by Creating a New Application and Setting up the Data Source
- Create a new app and add a **[Table](/docs/widgets/table)** component to the canvas.
- Open the Query Panel at the bottom and click on the `+ Add` button.
- Select REST API as your data source - your query will be named as restapi1 by default.
- Choose GET method and enter the below URL:
```
https://fakestoreapi.com/products
```
- To view the data that your query will return, click on the **Preview** button. Click on the **Run** button to execute the query and retrieve the data.
- Let's start by creating a new application and then adding a table widget into the canvas.
## 2. Display Data on the Table
- Hide the Query Panel and click on the Table component to open its configuration panel on the right.
- Under Table Data, enter the below code:
```
{{queries.restapi1.data}}
```
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/newapp.gif)
<img style={{ border:'0' }} className="screenshot-full" src="/img/how-to/change-text-color/table-with-data.png" alt="Table Component With Data" />
</div>
- Now go to the **Query Panel** at the bottom of the app editor and click on the `+` button.
- Choose **RestAPI** data source
## 3. Change Text Color Based on Cell Value
- Select the Table component and go to Columns.
- For the `category` column, paste the below code under Text Color to dynamically change the text color based on the value of the cell:
```
{{cellValue == 'electronics' ? 'red' : 'green'}}
```
Now, if the cell value is `electronics`, the text color will be red; otherwise, it will be green.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/restapi.png)
<img style={{ border:'0', marginBottom:'15px' }} className="screenshot-full" src="/img/how-to/change-text-color/conditional-text-color.png" alt="Conditional Text Color" />
</div>
- Now we will use a sample RestAPI endpoint - I have used the API provided by **coinstats.app**, API-URL:
https://api.coinstats.app/public/v1/coins?skip=0&limit=100&currency=USD
- Choose `GET` method, enter the request URL (API URL in previous step), name the query - I have named it `crypto`, and then **Create** the query
<i>You can use also Hex color codes for more color options.</i>
## 4. Change Text Color Using Row Data
- Under Cell Background Color for the `symbol` column, paste the below code:
```
{{rowData.price < 100? 'yellow': 'white'}}
```
The rowData identifier can be utilized to reference values from any column within the Table component.
Now if the value in the price column is lesser than 100, the cell background color will be yellow or else it will be white.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/apiendpoint.png)
<img style={{ border:'0', marginBottom:'15px' }} className="screenshot-full" src="/img/how-to/change-text-color/conditional-background-color.png" alt="Conditional Background Color" />
</div>
- Now hit the **Run** button next to the query name to run the query.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/runquery.png)
</div>
- Once you run the query, you can check the data returned by the query in the **Inspector** on the left sidebar.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/inspectord.png)
</div>
- Now that we have got the data, we will display it on the table. To do this, click on the widget handle of the table to open its properties in the right sidebar.
- In the Table Data field, enter `{{queries.crypto.data.coins}}` - as you can see in the screenshot of the inspector the data is inside the `coins` array. You'll see the data in the Preview(green box) below the field.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/data.png)
</div>
- Let's add the columns that we want to display on the table. Go to the **Columns** section, Add columns, set their Names, and set **key** for each column. I have added 5 columns: **Rank**, **Name**, **Symbol**, **Price**, and **Market Cap**.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/columns.png)
</div>
- Once you've added the columns, you'll get the table like this:
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/table.png)
</div>
### Using cellValue to change column text color
Now that we have our data on the table, we will change the color of the text in the **Price** and **Market Cap** columns.
- Edit table properties, go to **Columns**, and click on the Price Column to open its properties.
- For **Price** column, we want to change color of those cells who have value which is greater than 1000 to red else to green if it is less than 1000. So to do this, we will set a condition in **Text Color** property of this column: `{{cellValue >= 1000 ? 'red' : 'green'}}`
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/price.png)
</div>
- Similarly, we will do for **Market Cap** column. We want to change the text color of those cells who have value which is greater than 60000000000 to red else to green if it is less than 60000000000. so the condition will be `{{cellValue >= 60000000000 ? 'red' : 'green'}}`
- Now the text color of cells in the columns will be updated.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/cellvalue.png)
</div>
:::info
You can also use Hex Color Code instead of mentioning color in plane text.
:::
### Using rowData to change column text color
- To change the color of the text using `rowData` variable it is required to mention the column name whose cell value we will be comparing in the condition. Let's take a look by changing the text color of **Symbol** column.
- We will add a condition to look in the row data and if the row has column called `name` which has value `Solana` then it should change the color to red else the color should be green.
- Edit the properties of the Symbol column, set the **Text Color** field value to `{{rowData.name === 'Solana' ? 'red' : 'green'}}`.
- You'll see that in the Symbols column all the values has become green except the one that has Solana in Name column.
<div style={{textAlign: 'center'}}>
![ToolJet - How To - Change text color in columns of the table](/img/how-to/change-text-color/rowData.png)
</div>
You can use the above methods to change the text and background colors of a cell dynamically.

View file

@ -1,54 +1,36 @@
---
id: access-currentuser
title: Enable/Disable a component using current user's property
title: Enable/Disable a Component Using Current User's Property
---
# Enable/Disable a component using current user's property
Let's take look at the exposed variables of the current user property:
Let's take a look at the exposed variables of the currentUser property by clicking on the **[inspector](/docs/app-builder/left-sidebar/#inspector)** icon on the left sidebar:
- **email** : The value can accessed using `{{globals.currentUser.email}}`
- **firstName** : The value can accessed using `{{globals.currentUser.firstName}}`
- **lastName** : The value can accessed using `{{globals.currentUser.lastName}}`
- **lastName** : The value can accessed using `{{globals.currentUser.lastName}}`
- **groups** : By default, the admin will be in the two groups `all_users` and `admin`, and any user who is not admin will always be in the `all_users` group by default. Since the **groups** is an array youll have to provide the index ([0], [1], and so on) to return the group name. The value can be accessed using `{{globals.currentUser.groups[1]}}`.
- **groups**: The `groups` attribute is an array representing the groups a user belongs to. By default, every user, including admins, is part of the `all_users` group. Additionally, admins are also part of the `admin` group. To access a specific group name, you need to specify the array index, such as `[0]` for the first group, `[1]` for the second, and so on. For example, you can retrieve the name of the second group a user belongs to with `{{globals.currentUser.groups[1]}}`.
<div style={{textAlign: 'center'}}>
### Example: Disable a Button if a User is Not Admin
<img className="screenshot-full" src="/img/how-to/access-currentuser/props.png" alt="Properties of current user" />
- Click on the **Button** handle to open its properties. On the **Styles** tab, go to the **Disable** property.
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/button.png" alt="Properties of button" />
</div>
### Example: Disable a button if a user is not admin
- Configure the Disable field with a condition that checks the user's group membership. If the user is not an admin, as determined by the absence of the admin value in the first position (index [1]) of the groups array, the field should be disabled. Use the following JavaScript condition for this purpose:
- Click on the **Button** handle to open its properties, on the **Styles** tab go to the **Disable** property.
```javascript
{{globals.currentUser.groups[1] !== "admin" ? true : false}}
```
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" width="100%" src="/img/how-to/access-currentuser/disable.png" alt="Disable Property of button" />
</div>
<img className="screenshot-full" src="/img/how-to/access-currentuser/button.png" alt="Properties of button" />
- Now, when you **release** the app, if the user is not a part of the **admin** group, the button will be disabled.
</div>
<div style={{textAlign: 'left', width: '100%', marginTop:'15px', marginBottom:'15px'}}>
<img className="screenshot-full" width="100%" src="/img/how-to/access-currentuser/released.png" alt="Released button disabled when user is not admin" />
</div>
- Set a condition on the Disable field so that if the the user who is using the app does not have **admin** value in the first index of **groups** array return **true**. The condition can be:
```javascript
{{globals.currentUser.groups[1] !== "admin" ? true : false}}
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/disable.png" alt="Disable Property of button" />
</div>
- Now, when you'll **release** the app, if the user is not is not admin the button will be disabled.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/access-currentuser/released.png" alt="Released button disabled when user is not admin" />
</div>
:::info
In this how-to we have used the **Groups** property of the **Current User**. You can use any of the exposed variables mentioned above according to your use.
:::

View file

@ -1,45 +1,113 @@
---
id: loading-image-pdf-from-db
title: Loading image/PDF from base64 string
title: Upload And View Images and PDFs Using Base64 String
---
In this how-to guide we will see how we can load an image or PDF file using the base64 string available on the database. In this how-to, we have used the postgres database which already has the base64 strings for the image or the PDF files available.
This guide shows how to upload and view images and PDFs using the base64 string format.
- Let's drag a **filepicker** component onto the canvas, and pick one image and one pdf file
<div style={{textAlign: 'center'}}>
## 1. Start by Creating a New Table In ToolJet Database
<img className="screenshot-full" src="/img/how-to/load-base64/filepicker.png" alt="Loading image from base64 string" width="700" />
- Create a new table named *testDB*.
- The `id` field will be present by default to create a unique identifier for each record in our database table.
- Click on **Add more columns** button and add two more columns: `pdf` and `image`.
- Select `varchar` as datatype for the pdf and image columns.
</div>
<i>While we are using the ToolJet Database for this guide; feel free to use other databases while applying the same principles.</i>
- Now, create a query for inserting an image from the filepicker. As you can see in the screenshot below, we are using the **exposed variable** of the filepicker component to retrieve the **base64** data of the uploaded files.
<div style={{textAlign: 'center'}}>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/create-new-table.png" alt="New Table" />
</div>
<img className="screenshot-full" src="/img/how-to/load-base64/insert.png" alt="Loading image from base64 string" width="500"/>
## 2. Upload Files To The Database
</div>
- Create a new application and name it *Load PDF And Images Example*.
- Drag and drop two **[Filepicker](/docs/widgets/file-picker)** components on the canvas from the components library on the right.
- Rename the first Filepicker component to *imagePicker* and second Filepicker to *pdfPicker*.
- Create another query for returning the data from the database and we will use this base64 data returned in this query to display on the image and pdf components.
<div style={{textAlign: 'center'}}>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/filepickers-rename.png" alt="Rename Filepickers" />
</div>
<img className="screenshot-full" src="/img/how-to/load-base64/get.png" alt="Loading image from base64 string" width="500"/>
- For *pdfPicker*, change the **Accept file types** property to `{{"pdf/*"}}` - this ensures that the Filepicker only accepts PDF files.
</div>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-accepted-file-type.png" alt="Accepted File Type Settings" />
</div>
- Drag the image and a PDF component on the canvas. Edit the property of the PDF component and in the **file URL** enter:
```js
{{'data:image/png;base64,' + queries.get.data[7].pdf}}
```
Similarly for the image component:
```js
{{'data:image/jpeg;base64,' + queries.get.data[7].image}}
```
<div style={{textAlign: 'center'}}>
- Retain the default `{{"image/*"}}` setting for the Accept file types property in the *imagePicker* component, as it's intended for image uploads.
- Click on the *imagePicker* component and select an image to upload. Similarly, upload a PDF using the *pdfPicker* component.
<img className="screenshot-full" src="/img/how-to/load-base64/pdf.png" alt="Loading image from base64 string" />
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/filepickers-with-uploaded-files.png" alt="Uploaded Files" />
</div>
</div>
- After uploading, you will see the filenames displayed on their respective Filepicker components.
- Click on the **+ Add** button in the query panel to create a new query, choose Tooljet Database as the data source, select `testDB` as Table name, and `Create Row` as Operations. Name this query *uploadFiles*.
- Under the Columns section, add two columns - `pdf` and `image`.
- Set the below value for the `pdf` column:
```js
{{components.pdfPicker.file[0].base64Data}}
```
- Similarly, for the `image` column:
```js
{{components.imagePicker.file[0].base64Data}}
```
:::info
<i>In the above query, we are using the <b>exposed variables</b> of both Filepicker components to get the base64 strings of the files we had uploaded earlier.</i>
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/add-files-query.png" alt="Add Files Query" />
</div>
- Add a **[Button](/docs/widgets/button)** component below the Filepickers and rename it to *upload*.
- Set the Button's text to *Upload* and create a **New event handler** with the following settings: Event - `On click`, Action - `Run Query` and Query - `uploadFiles`.
- Click on the *upload* button to upload the files that we had selected in the Filepicker components earlier.
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/upload-button-properties.png" alt="Upload Button Properties" />
</div>
The upload process is now complete. Whenever files are selected in the Filepicker components and the *upload* button is clicked, the base64 strings of these files will be automatically written to the database.
## 3. View Image and PDF Files
- Create a query named *getFiles* to retrieve base64 strings from testDB: Click on **+ Add** button in the query panel, select Tooljet as Database, `testDB` as Table name, and `List rows` as Operations.
- Enable **Run this query on application load?** and click on the **Run** button to run the getFiles query.
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/fetch-files-query.png" alt="Fetch Files Query" />
</div>
- Drag an **[Image](/docs/widgets/image)** and a **[PDF](/docs/widgets/pdf)** component on the canvas from the components library. Rename the **Image** component to *displayImage* and the **PDF** component to *displayPDF*.
- In the **URL** property of the **displayImage** component, enter:
```js
{{'data:image;base64,' + queries.getFiles.data[0].image}}
```
- Let's apply the same logic for the **displayPDF** component and enter the below value in the **File URL** property:
```js
{{'data:pdf;base64,' + queries.getFiles.data[0].pdf}}
```
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-with-fileURL.png" alt="PDF Component With File URL" />
</div>
<i>The provided code constructs a Data URL to display the base64-encoded data as an image or PDF.</i>
<br/>
<br/>
Here's what our final interface will look like:
<div style={{ width: '100%', marginBottom:'15px', marginTop:'15px'}}>
<img className="screenshot-full" src="/img/how-to/load-base64/pdf-image-view.png" alt="Final Preview" />
</div>
<i>
You can also use transformations in the query response and concat `data:image/jpeg;base64,` to the base64 data.
:::
</i>
<br/>
<br/>
Using the above logic, you can upload and view files in ToolJet using the base64 data.

View file

@ -0,0 +1,277 @@
---
id: use-events-on-chart
title: Use Events on Chart
---
Currently, the chart component does not support events. However, you can use the Custom Component to create a chart using a third-party library that supports events. Plotly is one of the libraries that supports events. In this tutorial, we will build a chart using Plotly and add events to it.
<div style={{textAlign: 'center'}}>
<img style={{ border:'0'}} className="screenshot-full" src="/img/how-to/events-chart/plotly-chart.png" alt="Plotly Chart" />
</div>
## Step 1: Add a Custom Component
Open the App Builder and add a Custom Component to the page. Then, click on the Custom Component to open the Properties panel.
Note: If you are not familiar with the Custom Component, please read the [Custom Component](/docs/widgets/custom-component/) doc.
## Step 2: Add the code to the Custom Component
```js
import React from 'https://cdn.skypack.dev/react';
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core';
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min';
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory';
const MyCustomComponent = ({data, updateData, runQuery}) => {
const Plot = createPlotlyComponent(Plotly);
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
return (
<Container>
<Plot data={[
{
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick}
/>
</Container>
)}
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent);
ReactDOM.render(<ConnectedComponent />, document.body);
```
Let's understand the code above in detail. First, we imported the required libraries.
```js
import React from 'https://cdn.skypack.dev/react'; // React library
import ReactDOM from 'https://cdn.skypack.dev/react-dom'; // React DOM library
import { Button, Container } from 'https://cdn.skypack.dev/@material-ui/core'; // Material UI library
import Plotly from 'https://cdn.skypack.dev/plotly.js-basic-dist-min'; // Plotly library
import createPlotlyComponent from 'https://cdn.skypack.dev/react-plotly.js/factory'; // Plotly React library
```
Then, we created a function component called `MyCustomComponent`. This component will render the chart. We use the `createPlotlyComponent` function to create a Plotly component. Then, we create a function called `barOnClick` that will be called when the user clicks on the bar. This function will display an alert message.
```js
const MyCustomComponent = ({data, updateData, runQuery}) => { // function component
const Plot = createPlotlyComponent(Plotly); // create a Plotly component
const barOnClick = ({points}) => { // function that will be called when the user clicks on the bar
alert('A bar is clicked') // display an alert message
}
```
Next, we render the chart using the `Plot` component. We pass the data and layout to the `Plot` component. We also pass the `barOnClick` function to the `onClick` prop of the `Plot` component.
```js
return ( // return the Plot component
<Container> // Material UI Container component
<Plot data={[ // Plot component
{ // data for the first bar
"name": "Inbound",
"type": "bar",
"x": [
20,
14,
23,
22,
30,
12,
15,
26,
31,
16,
18,
29
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(55, 128, 191, 1.0)",
"width": 1
},
"color": "rgba(55, 128, 191, 0.6)"
},
"orientation": "h"
},
{ // data for the second bar
"name": "Outbound",
"type": "bar",
"x": [
12,
18,
29,
22,
14,
23,
15,
23,
26,
13,
27,
12
],
"y": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"marker": {
"line": {
"color": "rgba(255, 153, 51, 1.0)",
"width": 1
},
"color": "rgba(255, 153, 51, 0.6)"
},
"orientation": "h"
}
]}
layout={{ // layout for the chart
width: 840,
height: 800,
title: "Tickets Resolved: Inbound & Outbound",
showlegend: false,
}}
onClick={barOnClick} // pass the barOnClick function to the onClick prop
/>
</Container>
)}
```
Finally, we render the `MyCustomComponent` component using the `ReactDOM.render` function.
```js
const ConnectedComponent = Tooljet.connectComponent(MyCustomComponent); // connect the component to the Tooljet store
ReactDOM.render(<ConnectedComponent />, document.body); // render the component
```
## Step 3: Using events from the Custom Component
In the code above, we created a function called `barOnClick` that will be called when the user clicks on the bar. This function holds the code that will be executed when the user clicks on the bar.
```js
const barOnClick = ({points}) => {
alert('A bar is clicked')
}
```
Instead of displaying an alert message, you can use the `runQuery` function to run a query.
```js
const barOnClick = ({points}) => {
runQuery('queryName')
}
```
`runQuery` is a function which accepts a query name as a string used to run the query from the custom component. Learn more about the custom component [here](/docs/widgets/custom-component/).

View file

@ -1,90 +1,89 @@
---
id: use-form-component
title: Use form component
title: Use Form Component
---
In this how-to guide, we will be building a simple application that will leverage the form component for adding a record into the database. For this guide, we will be using Google Sheet datasource to read and write data.
In this guide, we'll create a simple app that uses a **[Form](/docs/widgets/form)** component to add records to a database. We'll use **[ToolJet Database](/docs/tooljet-database)** as our data source.
<div style={{textAlign: 'center'}}>
<!-- <div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/final.png" alt="how-to use form" />
</div> -->
## 1. Create a Table in ToolJet Database
- Create a table named *products* in ToolJet Database.
- Create three columns - `name`, `quantity` and `price`.
- Add some sample data to the table.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/database-table.png" alt="Database Table" width="100%" />
</div>
- Let's connect to the datasource i.e. Google Sheets and give the `Read and Write` permission.
<div style={{textAlign: 'center'}}>
## 2. Create the UI
- Create a new app and drag and drop a **[Table](/docs/widgets/table)** component on the canvas.
- Drop a **[Form](/docs/widgets/form)** next to it.
- Since we have three columns in the database, let's update the Form with one **[Text Input](/docs/widgets/text-input)** for `name` and two **[Number Inputs](/docs/widgets/text-input)** for `quantity` and `price`.
- Name the three input fields on the form as - *nameInput*, *quantityInput* and *priceInput*. Name the button as *submitButton*.
<img className="screenshot-full" src="/img/how-to/use-form/read.png" alt="how-to use form" />
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/user-interface.png" alt="User Interface" width="100%" />
</div>
<i>Naming the components can help in easily identifying or referring individual components when there are a large number of components in the app</i>.
</div>
- Now, drag a table on the canvas and add the form component next to it.
<div style={{textAlign: 'center'}}>
## 3. Load the Table Component With Data
<img className="screenshot-full" src="/img/how-to/use-form/table1.png" alt="how-to use form" />
- Click on the Add button in the **[Query Panel](/docs/app-builder/query-panel/)**, select ToolJet Database
- Rename the query to *getProducts*
- Choose *products* as Table name, List rows as Operations
- Enable `Run this query on application load?` to automatically run the query when the app starts
- Click on Run to fetch data
- Click on the Table component to open its configuration panel on the right. Under the `Data` property, paste the below code:
```js
{{queries.getProducts.data}}
```
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/load-data.png" alt="Table with Data" width="100%" />
</div>
</div>
## 4. Write Data Using the Form Component
- Click on the Add button in the Query Panel, select ToolJet Database
- Select *products* as Table name, Create row as Operations
- Rename the query to *addProduct*
- Click on Add Column and add three columns - **name**, **quantity** and **price**
- Enter code below for **name**, **quantity** and **price** column keys:
- Currently, the table component is populated with the sample data that it has by default. Let's create a **new query** from the query panel and choose the **Google Sheet** datasource.
<div style={{textAlign: 'center'}}>
```js
{{components.form.data.nameInput.value}}
{{components.form.data.quantityInput.value}}
{{components.form.data.priceInput.value}}
```
<img className="screenshot-full" src="/img/how-to/use-form/query.png" alt="how-to use form" />
To ensure the Table component updates with new data after adding products, trigger the *getProducts* query following each *addProduct* query execution. Here's how:
</div>
- Click on **New event handler** in the *addProduct* query to add a new event.
- For the new event, leave the event as Query Success, set Run Query as the Action and choose *getProducts* as the Query.
- The query will read the data from the database and we will use the returned data to populate the table. Go to the **table** property and in the table data value enter **{{queries.queryname.data}}** where queryname is the name of the query that we created in previous step.
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/refresh-table.png" alt="Refresh Table" width="100%" />
</div>
<img className="screenshot-full" src="/img/how-to/use-form/populate.png" alt="how-to use form" />
<i>This process refreshes the Table component with the latest data from the database.</i>
<br/>
<br/>
</div>
- Next, click on the Form component and set `Button To Submit Form` as *submitButton*.
- Add a **New event handler** to the Form component. Keep On submit as Event, Run Query as Action and select *addProduct* as the Query.
- let's go to the form and add the components inside it required for adding a record into the database.
<div style={{textAlign: 'center'}}>
<div style={{textAlign: 'center', marginBottom: '15px'}}>
<img className="screenshot-full" src="/img/how-to/use-form/write-data-query.png" alt="Table with Data" width="100%" />
</div>
<img className="screenshot-full" src="/img/how-to/use-form/form1.png" alt="how-to use form" />
Now if you enter the product data on the form and click on Submit. The `addProduct` query will run and the entered data will be written to the `products` table in the ToolJet Database.
</div>
<div style={{textAlign: 'center', marginBotton: '15px', marginTop: '15px'}}>
<img className="screenshot-full" src="/img/how-to/use-form/final-preview.png" alt="Final Preview" width="100%" />
</div>
<br/>
- Since our database record has five fields **Id**, **Title**, **Price**, **Category** and **Image** we will add the components in the form for the same. The form already comes with a Submit button so we don't have to add that. For Id, Title, and Image we will use text-input, for Price we will use number-input and for category we can use dropdown components.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/form2.png" alt="how-to use form" />
</div>
- Before editing the form properties, let's make a few changes in the components that we have added inside it. First edit the property of the **number input** and set the default value, maximum and minimum value, and then edit the **dropdown** component and set the option values and option labels.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/categ.png" alt="how-to use form" />
</div>
- Now, we can edit the properties of the form component. Go to its properties, in **Button To Submit Form** select the button1 that was already there on the form. Go to event handler, and for **On submit** event we will **run the query** that will get the data from the form and will store into the database.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-form/event.png" alt="how-to use form" />
</div>
- Let's create a query that will get the data from the form and add a record in the sheet. Create a new google sheet query and from the operation choose **Append data to a spreadsheet**
```js
[
{
"id":"{{components.form1.data.textinput1.value}}",
"title":"{{components.form1.data.textinput2.value}}",
"price":"{{components.form1.data.numberinput1.value}}",
"category":"{{components.form1.data.dropdown1.value}}",
"image":"{{components.form1.data.textinput4.value}}"
}
]
```
- Once done, save the query and add it to the Form's event handler.
- Now, this application can be used to load the data from the Google Sheet and the form can be used to append more records to the sheet.
:::tip
- Make sure to enable **Run query on page load?** option of the **read** query to populate the table everytime the app is loaded
- You can also add a event handler on the **append** query to run the **read** query when **append** is successful, this will update the table data when the append is done
- Learn more about the connecting Google sheet datasource and the CRUD **operations** available [here](/docs/data-sources/google.sheets).
:::
In this how-to guide, we have explored a practical application of the Form component in ToolJet. You can apply the same principles for a variety of use cases that requires data input from the end-user.

View file

@ -1,124 +1,63 @@
---
id: use-inspector
title: Use Inspector
title: Use Inspector in App-Builder
---
In this how-to guide, we will take a look at **Inspector** of the app-builder and see how it can be helpful in building applications.
The Inspector can be used to inspect the data of the queries, properties and values of the components that are there on the canvas, ToolJet's global variables and the variables that have been set by the user.
This guide introduces **Inspector** in the app-builder, a feature that lets you view data related to queries, components, global variables, page-related variables, user-set variables and constants.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/inspector.png" alt="How to - Use Inspector" width="500" />
<img className="screenshot-full" src="/img/how-to/use-inspector/use-inspector-preview.png" alt="Preview of Use Inspector" width="100%" />
</div>
## Layout
Let's take a look at the layout of the Inspector panel:
- On the top-right, we have a **Pin** button to pin and unpin the inspector panel. This button can be useful when you want to see the live changes on inspector while triggering a query or performing some event/action on any component.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/pin.png" alt="How to - Use Inspector" width="500" />
</div>
- At the bottom right, you can click and hold to resize the inspector.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/resize.png" alt="How to - Use Inspector" width="500" />
</div>
- On hovering an item on the inspector, the **copy path** and **copy value** buttons will appear on the right of the item. Copying the path and pasting it onto the component property or query parameter will always get the dynamic value but using `Copy value` option will copy the current value of the item and will be static when pasted in a component property or query parameter.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/path.png" alt="How to - Use Inspector" width="500" />
</div>
## Sections
The Inspector panel has the following 4 main sections:
The Inspector panel has 6 main sections:
- **[queries](#queries)**
- **[components](#components)**
- **[globals](#globals)**
- **[variables](#variables)**
- **[Queries](#queries)**
- **[Components](#components)**
- **[Globals](#globals)**
- **[Variables](#variables)**
- **[Page](#page)**
- **[Constants](#constants)**
### queries
The queries section can be used to inspect the query details but the data of the query will only be available if query has been run/triggered.
### Queries
:::tip
You can click on the Preview button of the button on the query manager to check the response(data) of the query without triggering it.
:::
Queries allow you to inspect the specifics of your queries. However, the data related to these queries will only be visible after they have been executed or triggered.
#### Example
- Let's create a new query using a mock REST API endpoint (`https://fakestoreapi.com/products`).
- Now go to the Inspector and expand the **queries** section, you'll see an entry inside queries with the query name that we created in the previous step i.e. `restapi1` but if you notice the `data` and `rawData` object is empty i.e. 0 entry. The reason is the data won't show up on the inspector unless query is run.
<div style={{textAlign: 'center'}}>
### Components
<img className="screenshot-full" src="/img/how-to/use-inspector/data0.png" alt="How to - Use Inspector" />
Under Components, you can view and analyze the properties and values of the components you've added to the canvas, providing insights into how each component functions within your app.
</div>
### Globals
- Let's pin the inspector and then trigger the query from the query manager. You'll see that as soon as the query is triggered the `rawData` and `data` object in the query has 20 entries and the query has more properties like `request`, `response`, and `responseHeaders` data.
<div style={{textAlign: 'center'}}>
Globals give you access to global information related to the app.
<img className="screenshot-full" src="/img/how-to/use-inspector/data1.png" alt="How to - Use Inspector" />
The globals selection consists of the following data:
</div>
### components
components section can be used to inspect the properties and values of the components that are added onto the canvas.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/components.png" alt="How to - Use Inspector" width="500" />
</div>
### globals
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/globals.png" alt="How to - Use Inspector" width="500" />
</div>
The globals section consists of the following sub-sections:
- **currentUser:** The currentUser object contains information about the currently logged-in user, such as their **email**, **firstName**, and **lastName**.
- **groups:** The groups array contains the names of the groups to which the currently logged-in user belongs. Note: The `all_users` group is a default group for everyone.
- **theme:** The theme object contains the name of the currently active theme.
- **urlparams:** The urlparams contain information about the URL parameters of the application.
- **environment:** This variable holds two keys: **id** and **name**. The **id** is a unique identifier generated automatically, and the **name** holds the name of the currently opened environment of the app version.
- **modes:** This variable holds one of three values: **edit**, **preview**, or **view**, depending on the current state of the app. If the app is opened in editing mode, the mode will be set to **edit**. If the app is opened by clicking the preview button on the app builder, the variable will be set to **preview**. If the app is opened using the URL from the **Share** modal, the mode will be set to **view**.
:::tip
The **environment** and **mode** variables are only available in **ToolJet Enterprise Edition v2.2.3** and above.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/how-to/use-inspector/env.png" alt="How to - Use Inspector" width="500" />
</div>
:::
- **currentUser:** Contains details about the user who is currently logged in, like their **email**, **firstName**, and **lastName**.
- **groups:** A list of group names that the logged-in user is part of. Note: The `all_users` group is a default group for everyone.
- **theme:** Shows the name of the theme that is currently being used.
- **urlparams:** Details about the URL parameters of the app.
- **environment:** Has two parts: **id**, a unique auto-generated identifier, and **name**, the name of the current environment of the app version.
- **modes:** Indicates whether the app is in **edit**, **preview**, or **view** mode. **Edit** is for editing the app, **preview** is used when the preview button in the app builder is clicked, and **view** is for when the app is opened through a shared URL.
:::info
All the global variables can be accessed anywhere within ToolJet applications. Here's an **[example use-case](/docs/how-to/access-currentuser)** that demonstrates the usage of these variables.
:::
### variables
### Variables
variables section include all the variables set by the user in the application. These variables can be set from the event handlers from the components or from the queries. The variables will be in the **key-value** pair and can be accessed throughout the application.
Variables shows user-defined variables in a key-value format. These variables, set through event handlers or queries, are accessible across the entire application. You can set variables from the [event handler](/docs/actions/set-variable) or using [JavaScript code](/docs/how-to/run-actions-from-runjs#set-variable).
### Page
Page lets you view page-specific properties like page name, handle and variables. Page variables are restricted to their respective pages and are not accessible application-wide.
### Constants
Under **[Constants](/docs/org-management/workspaces/workspace_constants/)**, you can find the predefined values (usually tokens/secret keys/API keys) that can be used across your application to maintain consistency and facilitate easy updates.
:::info
- Setting variables from the [event handler](/docs/actions/set-variable)
- Setting variables from the [Run JavaScript code](/docs/how-to/run-actions-from-runjs#set-variable)
:::
The **environment** and **mode** variables are only available in **ToolJet Enterprise Edition v2.2.3** and above.
:::

View file

@ -120,6 +120,10 @@ You can refer to the [JSON Chart Schema](https://plotly.com/chart-studio-help/js
</div>
:::tip Using events on chart
Currently, the chart component does not support events. However, you can use the Custom Component using Plotly and add events to it. Check out the [How to use events on chart](/docs/how-to/use-events-on-chart) to learn more.
:::
### Bar Mode
The **Bar Mode** option allows you to customize the layout and display style specifically for bar charts. This option becomes available when the **Plotly JSON chart schema** toggle is enabled and a JSON schema specific to bar charts is provided. This option provide different modes for organizing and presenting bars within the chart.

View file

@ -0,0 +1,5 @@
{
"label": "Enterprise",
"position": 9,
"collapsed": true
}

View file

@ -0,0 +1,141 @@
---
id: audit_logs
title: Audit logs
---
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
The audit log is the report of all the activities done in your ToolJet account. It will capture and display events automatically by recording who performed an activity, what when, and where the activity was performed, along with other information such as IP address.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/audit_logs/logsnew.png" alt="Audit logs" />
</div>
### Date Range
Retrieve the log of events that occurred within the specified date and time range using the range picker. By default, the system loads 24-hour logs for the initial view. The maximum duration that can be specified for the "from" and "to" dates is 30 days.
:::info
Pagination at the bottom allows navigation through the pages, with each page displaying a maximum of 7 logs.
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/audit_logs/filtersnew.png" alt="Audit logs" />
</div>
### Filter Audit Logs
You can apply filters to the audited events based on the following criteria.
#### Select Users
Choose a specific user from the dropdown list to view all their activities.
#### Select Apps
The dropdown will display all the apps associated with your account. Select an app to filter the logs related to that particular app.
#### Select Resources
| Resources | description |
| ----------- | ----------- |
| User | Filter all the User events like `USER_LOGIN`, `USER_SIGNUP`, `USER_INVITE`, AND `USER_INVITE_REDEEM`. |
| App | Filter all the App events like `APP_CREATE`, `APP_UPDATE`,`APP_VIEW`,`APP_DELETE`,`APP_IMPORT`,`APP_EXPORT`,`APP_CLONE`. |
| Data Query | Filters the events associated with Data Query like `DATA_QUERY_RUN`. |
| Group Permission | All the events associated with Group Permissions will be filtered. Group Permissions include `GROUP_CREATE`, `GROUP_UPDATE`, `GROUP_DELETE`. |
| App Group Permission | Within each group, you can set apps for read or edit privileges. These events get recorded as App Group Permissions. |
#### Select Actions
| Actions | description |
| ----------- | ----------- |
| USER_LOGIN | This event is recorded everytime a user logins. |
| USER_SIGNUP | This event is recorded everytime a new signup is made. |
| USER_INVITE | You can invite users to your account from `Manage Users` section and an event is audited everytime an invite is sent. |
| USER_INVITE_REDEEM | This event is recorded whenever an invite is redeemed. |
| APP_CREATE | This event is recorded when a user creates a new app. |
| APP_UPDATE | This event is recorded whenever actions like renaming the app, making the app public, editing shareable link, or deploying the app are made. |
| APP_VIEW | This event is logged when someone views the launched app. (public apps aren't accounted for) |
| APP_DELETE | This event is recorded whenever a user deletes an app from the dashboard. |
| APP_IMPORT | This event is recorded whenever a user imports an app. |
| APP_EXPORT | This event is recorded whenever an app is exported. |
| APP_CLONE | This event is recorded whenever a clone of the existing app is created. |
| DATA_QUERY_RUN | This event is logged whenever a data source is added, a query is created, or whenever a query is run either from the query editor or from the launched app. |
| GROUP_PERMISSION_CREATE | This event is recorded whenever a group is created. |
| GROUP_PERMISSION_UPDATE | This event is recorded whenever an app or user is added to or removed from a group, or the permissions for a group are updated. |
| GROUP_PERMISSION_DELETE | This event is recorded whenever a user group is deleted from an account. |
| APP_GROUP_PERMISSION_UPDATE | For every app added in to user group, you can set privileges like `View` or `Edit` and whenever these privileges are updated this event is recorded. By default, the permission of an app for a user group is set to `View`. |
### Understanding Log Information
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/audit_logs/readinglogv2.png" alt="Audit logs" />
</div>
| Property | Description |
| ----------- | ----------- |
| action_type | This indicates the type of action that was logged in the event. Refer to [this](#select-actions) for more information on actions. |
| created_at | Shows the date and time when the event was logged. |
| id | Each logged event is assigned a unique event ID. |
| ip_address | Displays the IP address from which the event was logged. |
| metadata | The metadata includes two sub-properties: `tooljet_version` and `user_agent`. `tooljet_version` shows the version of ToolJet used for the event, while `user_agent` contains information about the device and browser used. |
| organization_id | Every organization in ToolJet has a unique ID associated with it, which is recorded when an event occurs. |
| resource_id | Different [resources](#select-resources) have their respective IDs associated with them. These IDs are assigned when the resources are created. |
| resource_name | Shows the name of the [resources](#select-resources) that were involved in the logged event. For example, if an app was created or deleted, it will display the name of that app. |
| resource_type | Indicates the type of the [resources](#select-resources) involved in the logged event. |
| user_id | Each user account in ToolJet has a unique ID associated with it, which is recorded when an event occurs. |
### Log file
The file will contain all the data from audit logs. The log file can be created by specifying the path in the [environment variables](/docs/setup/env-vars). The log file is rotated on a daily basis and is updated dynamically every time a new audit log is generated.
#### Log Rotation
The log file is configured to rotate on a daily basis. This means that a new log file will be created every day, ensuring efficient management and organization of audit data.
#### Log File Path
The path for the log file is defined using the `LOG_FILE_PATH` variable in the environment. It's important to understand that this path is relative to the home directory of the machine. For instance, if `LOG_FILE_PATH` is set to `hsbc/dashboard/log`, the resulting log file path will be structured as follows:
```
homepath/hsbc/dashboard/log/tooljet_log/{process_id}-{date}/audit.log
```
Here, `{process_id}` is a placeholder for the unique process identifier, and `{date}` represents the current date. This structured path ensures that audit logs are organized by both process and date, facilitating easy traceability and analysis.
| Variable | Description |
| -------- | --------------------------------------------------------------------------- |
| LOG_FILE_PATH | the path where the log file will be created ( eg: tooljet/log/tooljet-audit.log) |
<details>
<summary>Example Log file data</summary>
```bash
{
level: 'info',
message: 'PERFORM APP_CREATE OF awdasdawdwd APP',
timestamp: '2023-11-02 17:12:40',
auditLog: {
userId: '0ad48e21-e7a2-4597-9568-c4535aedf687',
organizationId: 'cf8e132f-a68a-4c81-a0d4-3617b79e7b17',
resourceId: 'eac02f79-b8e2-495a-bffe-82633416c829',
resourceType: 'APP',
actionType: 'APP_CREATE',
resourceName: 'awdasdawdwd',
ipAddress: '::1',
metadata: {
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
tooljetVersion: '2.22.2-ee2.8.3'
}
},
label: 'APP'
}
```
</details>

View file

@ -0,0 +1,158 @@
---
id: superadmin
title: Super Admin
---
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
A Super Admin is the user who has full access to all the Workspaces, Users, and Groups of an instance. An instance can have more than one Super Admin. A Super Admin has full control over other users' workspaces and can create users, groups, and other super admins.
The user details entered while setting up ToolJet will have Super Admin privileges.
## How is Super Admin different from Admin
| Privilege | Admin | Super Admin |
| --------- | ----- | ----------- |
| Manage Users in their workspace (Invite/Archive/Unarchive) | ✅ | ✅ |
| Manage Groups in their workspace (Create Group/Add or Delete Users from groups/ Modify Group Permissions) | ✅ | ✅ |
| Manage SSO in their workspace | ✅ | ✅ |
| Manage Workspace Variables in their workspace | ✅ | ✅ |
| Manage Workspace Constants in their workspace | ✅ | ✅ |
| [Manage data sources for the user group in their workspace](/docs/data-sources/overview#permissions) | ✅ | ✅ |
| [Access any user's personal workspace (create, edit or delete apps)](#access-any-workspace) | ❌ | ✅ |
| [Archive Admin or any user of any workspace](#archiveunarchive-users) | ❌ | ✅ |
| [Access any user's ToolJet database (create, edit or delete database)](#access-tooljet-db-in-any-workspace) | ❌ | ✅ |
| [Manage any workspace's setting (Groups/SSO/Workspace constants)](#manage-workspace-setting-groupsssoworkspace-constants) | ❌ | ✅ |
| [Manage all users from all the workspaces in the instance](#manage-all-users-in-the-instance) | ❌ | ✅ |
| [Make any user Super Admin](#make-the-user-super-admin) | ❌ | ✅ |
| [Restrict creation of personal workspace of users](#restrict-creation-of-personal-workspace-of-users) | ❌ | ✅ |
| [Enable Multiplayer editing](#enable-multiplayer-editing) | ❌ | ✅ |
| [Implement White Labelling](#white-labelling) | ❌ | ✅ |
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/instanceset.png" alt="Super Admin: Enterprise" />
</div>
## Super Admin features
### Access any workspace
If a user has Super Admin privileges, they can switch to any workspace created by any user within the instance using the Workspace Switcher located in the bottom left corner of the screen.
The dropdown will display all workspaces, including those created by both Super Admins and any other users.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/workspaceswitcher.png" alt="Super Admin: Enterprise" />
</div>
### Create, Edit or Delete apps from any user's personal workspace
Once the Super Admin accesses the workspace of any other user, they can create, edit or delete app on the workspace.
This also includes - modifying folders and importing, exporting, or cloning apps to any user's workspace.
### Archive/Unarchive Users
Super Admin can not only archive/unarchive users/admins on their workspace but also from the workspaces of any other user.
If a user is Super Admin, they just need to open the workspace in which they want to archive or unarchive a user. Then go to the **Workspace Settings** from the sidebar -> **Manage Users** -> **Archive/Unarchive** any user/admin
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/unarchivesa.png" alt="Super Admin: Enterprise" />
</div>
### Access ToolJet DB in any workspace
Super Admins have access to the database of any user's workspace - just like Super Admins can access any application in any workspace. They have full access to modify or create any table in the ToolJet DB of any workspace.
### Manage Workspace Settings (Groups/SSO/Workspace constants)
Super Admins have all the privileges that an Admin of a workspace have, Super Admins can:
- **✅ Manage Groups**: Creating/Deleting/Updating a Group in any workspace
- **✅ Manage SSO**: Full control over General Settings, Password login and other SSO options
- **✅ Workspace Variables**: Adding, updating or deleting workspace variables
- **✅ Workspace Constants**: Adding, updating or deleting workspace constants
- **✅ Copilot**: Enabling or disabling Copilot
- **✅ Custom Styles**: Adding or modifying custom styles
## Settings
Only Super Admins can access the Settings:
- **All Users**
- **Manage Settings**
- **License**
- **White labelling**
## All Users
### Manage all users in the instance
**All Users** page can be used to check the list of all the users in the instance. Super Admins can also promote/demote any user to/from Super Admin from this page. They can also archive/unarchive any user from this page.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/allusersa.png" alt="Super Admin: Enterprise" />
</div>
### Archiving a user from workspace
Super Admins have the privilege to remove any user from any workspace to which they belong.
Super Admins can go to **All Users** page, Under the **Workspaces** column they'll see the number of workspaces a user belongs to. Click on the **`View(n)`**, a modal will pop up that will have the list of **`n`** number the workspaces, click on the **Archive/Unarchive** button next to the workspace name to remove the user from the workspace.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/archivesa.png" alt="Super Admin: Enterprise" />
</div>
### Make the user super admin
Super Admins can make any user as Super Admin or remove any Super Admin from the **Manage All Users** in the Settings page.
Click on the **Edit** button next to any user, **Enable** the **Make the user Super Admin** option, and then **Save** it.
The user will become Super Admin and the Type column will update from **`workspace`** to **`instance`**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/saset.png" alt="Super Admin: Enterprise" />
</div>
## Manage Settings
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/superadmin/instancesett.png" alt="Super Admin: Enterprise" />
</div>
### Restrict creation of personal workspace of users
When a user joins a workspace, they are provided with their own personal workspace and option to create new workspaces.
Super Admins can **control** this behavior from the Manage Settings page, they can **toggle off** the option to **Allow personal workspace**. Now whenever a user joins a workspace they won't be provided a personal workspace nor they will be able to create a new workspace in the instance.
### Enable multiplayer editing
Super Admins can enable multiplayer editing from the Manage Settings page. Once enabled, users will be able to edit the same app simultaneously resulting in real-time collaboration.
## License
Manage the instance license via the **Settings** page. Super Admins have the capability to update the instance's license key from this page.
Check out the [License](/docs/licensing) page for more details.
## White labelling
This feature allows you to customize the ToolJet instance with your own branding. You can change the logo, favicon, and the name of the instance.
Check out the [White labelling](/docs/enterprise/white-label/) page for more details.

View file

@ -0,0 +1,48 @@
---
id: white-label
title: White Label
---
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
The White Label feature allows you to completely remove ToolJet's branding from the ToolJet platform, allowing you to replace it with your own customized logo, favicon and page title. This feature grants you full control over the visual identity of your ToolJet-powered application, ensuring a seamless and personalized user experience.
With this feature, you gain the ability to rebrand the following key elements:
- **Application Logo**: This includes the logo displayed on the login screen, dashboard, and app-editor.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/white-label/newdash.png" alt="ToolJet - Enterprise - White label"/>
</div>
- **Favicon**: The small icon associated with your application.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/white-label/newfav.png" alt="ToolJet - Enterprise - White label"/>
</div>
- **Page Title**: This is the text displayed next to the Favicon.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/white-label/title.png" alt="ToolJet - Enterprise - White label" />
</div>
## Configuration
To enable white labelling, you'll need to go to the **Settings** from the Dashboard and click on the `White labelling` tab. On the White labelling page, you'll be able to configure the following:
- **Application Logo**: Add the URL of the image you want to use as your application logo. Preferred dimensions of the logo are: width `130px` and height `26px`.
- **Favicon**: Enter the URL of the image you want to use as your application's favicon. Preferred dimensions of the favicon are: width `32px` and height `32px` or `16px` and height `16px`.
- **Page Title**: Enter the text you want to display as your application's title. Preferred title length are 50-60 characters.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/enterprise/white-label/whitelabelsettings.png" alt="ToolJet - Enterprise - White label" />
</div>

View file

@ -0,0 +1,5 @@
{
"label": "Actions Reference",
"position": 7,
"collapsed": true
}

View file

@ -0,0 +1,19 @@
---
id: close-modal
title: Close modal
---
Use this action to close the modal that is already shown.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/closemodal/closemodal2.png" alt="ToolJet - Action reference - Close modal" width="700" />
</div>

View file

@ -0,0 +1,102 @@
---
id: control-component
title: Control component (Component Specific Actions)
---
Control component action invokes the component specific actions. Component specific actions are the actions that are exclusive actions for a particular component. Component specific actions can be triggered either through the event handlers or from the Run JavaScript code query.
You can find the component specific actions for the specific component in their respective documentation. For example, you can find the component specific actions for the **Bounded Box** component in the [Bounded Box](/docs/widgets/bounded-box) documentation.
<details>
<summary>Currently, Component specific actions are supported only by the below listed components.</summary>
<div>
<ul>
<li><a href="/docs/widgets/button#component-specific-actions-csa">Button</a></li>
<li><a href="/docs/widgets/checkbox#component-specific-actions-csa">Checkbox</a></li>
<li><a href="/docs/widgets/color-picker#component-specific-actions-csa">Color Picker</a></li>
<li><a href="/docs/widgets/dropdown#component-specific-actions-csa">Dropdown</a></li>
<li><a href="/docs/widgets/file-picker#component-specific-actions-csa">File Picker</a></li>
<li><a href="/docs/widgets/form#component-specific-actions-csa">Form</a></li>
<li><a href="/docs/widgets/icon#component-specific-actions-csa">Icon</a></li>
<li><a href="/docs/widgets/kanban#component-specific-actions-csa">Kanban</a></li>
<li><a href="/docs/widgets/link#component-specific-actions-csa">Link</a></li>
<li><a href="/docs/widgets/map#component-specific-actions-csa">Map</a></li>
<li><a href="/docs/widgets/modal#component-specific-actions-csa">Modal</a></li>
<li><a href="/docs/widgets/multiselect#component-specific-actions-csa">Multiselect</a></li>
<li><a href="/docs/widgets/radio-button#component-specific-actions-csa">Radio button</a></li>
<li><a href="/docs/widgets/table#component-specific-actions-csa">Table</a></li>
<li><a href="/docs/widgets/tabs#component-specific-actions-csa">Tabs</a></li>
<li><a href="/docs/widgets/text-input#component-specific-actions-csa">Text Input</a></li>
<li><a href="/docs/widgets/text#component-specific-actions-csa">Text</a></li>
<li><a href="/docs/widgets/textarea#component-specific-actions-csa">Text Area</a></li>
</ul>
</div>
</details>
:::info
Check out the **[demo](https://youtu.be/JIhSH3YeM3E)** of Component specific actions demonstrated in one of our community call.
:::
## Using Component Specific Actions
### Set a value for text input component using button's event handler
- Drag a **Text Input** and a **Button** component onto the canvas.
- Go to the **Inspector** on the left sidebar to check the exposed variables available for the `textinput1` component under the `components`. You'll see that the variable `value` is an empty string because the field value of the text input component is empty right now.
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/inspector.png)
</div>
- Now enter some value in the text input component and you'll see that the `value` in inspector has been updated.
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/updated.png)
</div>
- Now, click on the button's component handler to open up its properties in the right sidebar and then add a event handler for **On Click** event to trigger **Control Component** action. Select `textinput1` in component dropdown, `Set text` as Action, and in `Text` field enter the text that you want to update in the field value.
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/button.png)
</div>
- Now when you'll click on the button you'll see that the field value of the text input component has been updated with value that you set.
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/set.png)
</div>
### Clear value of text input component using JavaScript query
- Let's clear the value that we set in the previous section, using Run JavaScript code. Create a new Run JavaScript Code query and call the component and the CSA that component provides.
**Syntax:**
```js
await components.textinput1.clear()
```
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/jsoption.png)
</div>
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference - Control Component](/img/actions/controlcomponent/clear.png)
</div>
- Finally, hit the **save and run** query button to fire up the query, and you'll see that the field value of the text input component has been cleared.

View file

@ -0,0 +1,18 @@
---
id: copy-to-clipboard
title: Copy to clipboard
---
Use this action to copy the text to the clipboard.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/copytoclipboard/copy2.png" alt="ToolJet - Action reference - Copy to clipboard" width="700" />
</div>

View file

@ -0,0 +1,56 @@
---
id: generate-file
title: Generate file
---
# Generate file
This action allows you to construct files on the fly and let users download it.
## Options
| Option | Description |
|--------|-------------|
| Type | Type of file to be generated. Types: `CSV`, `Text` and `PDF` |
| File name | Name of the file to be generated |
| Data | Data that will be used to construct the file. Its format will depend on the file type, as specified in the following section |
| Debounce | Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300` |
:::tip
Check how to run **[generate file action using RunJS](/docs/how-to/run-actions-from-runjs/#generate-file)**.
:::
### CSV Data Format
To use the `CSV` file format, the data field should contain an array of objects. ToolJet assumes that the keys in each object are the same and represent the column headers of the CSV file.
Example:
```javascript
{{
[
{ name: 'John', email: 'john@tooljet.com' },
{ name: 'Sarah', email: 'sarah@tooljet.com' },
]
}}
```
Using the above code snippet will generate a CSV file with the following content:
```csv
name,email
John,john@tooljet.com
Sarah,sarah@tooljet.com
```
### Text Data Format
To use the `Text` file format, the data field should contain a string.
If you want to generate a text file based on an array of objects, you need to stringify the data before providing it.
For example, if you are using the table component to provide the data, you can enter **`{{JSON.stringify(components.table1.currentPageData)}}`** in the Data field.
### PDF data format
The PDF data format supports two types of input: either a `string` or an `array of objects`. When using an array of objects, the resulting PDF will display the data in a tabular format with columns and rows. On the other hand, if a string is provided, the generated PDF will consist of plain text.

View file

@ -0,0 +1,18 @@
---
id: go-to-app
title: Go to app
---
This action allows you to open any released ToolJet application when an event occurs. Only the apps that are released can be opened using this action.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/gotoapp/gotoapp3.png" alt="ToolJet - Action reference - Open webpage" width="700" />
</div>

View file

@ -0,0 +1,18 @@
---
id: logout
title: Logout
---
This action allows you to log out of the application (ToolJet).
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/logout/logout2.png" alt="ToolJet - Action reference - Logout" width="700" />
</div>

View file

@ -0,0 +1,18 @@
---
id: open-webpage
title: Open webpage
---
You can use this action to open a webpage(on a new tab) for any event.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/open-webpage/open2.png" alt="ToolJet - Action reference - Open webpage" width="700" />
</div>

View file

@ -0,0 +1,18 @@
---
id: run-query
title: Run Query
---
This action allows you to fire queries when an event occurs.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/run-query/run-query2.png" alt="ToolJet - Action reference - Run Query" width="700" />
</div>

View file

@ -0,0 +1,59 @@
---
id: set-localstorage
title: Set localStorage
---
# Set localStorage
This action allows you to specify a `key` and its corresponding `value` to be stored in localStorage.
## Example: App that stores a name in localStorage and displays it on reload
1. Add an input field, button and a text as shown
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference -Set local storage sample app](/img/actions/localstorage/1.png)
</div>
2. Select the button and add a `Set localStorage` action with `key` set to `name` and value pointing at the value of the text field
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference -Set local storage sample app](/img/actions/localstorage/2.png)
</div>
3. Select the text label we've added and set its value to the name item from localStorage.
:::info
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference -Set local storage sample app](/img/actions/localstorage/debounce.png)
</div>
4. Now save the application, this is important as we're about to reload the page.
5. Type in anything you wish on the input box and click on the button
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference -Set local storage sample app](/img/actions/localstorage/5.png)
</div>
6. Reload the page, you'll see that the value stored in local storage is persisted and it is displayed on screen!
<div style={{textAlign: 'center'}}>
![ToolJet - Action reference -Set local storage sample app](/img/actions/localstorage/6.png)
</div>

View file

@ -0,0 +1,36 @@
---
id: set-page-variable
title: Set page variable
---
Page variables are restricted to the page where they are created and cannot be accessed throughout the entire application like regular variables.
Use this action to establish a variable and assign a value to it within the [Multipage Apps](/docs/tutorial/pages).
By default, the debounce field is left empty. However, you can input a numeric value to indicate the time in milliseconds before the action is executed. For example, `300`.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/setpagevar2.png" alt="ToolJet - Action reference - Switch page" width="600"/>
</div>
## Using RunJS query to set page variable
Alternatively, the set page variable action can be triggered via a RunJS query using the following syntax:
```js
await actions.setPageVariable('<variablekey>',<variablevalue>)
```
`variablekey` must be provided as a string (enclosed in quotes), while the `variablevalue` does not require quotation marks if it is a numerical value.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/setpagevar33.png" alt="ToolJet - Action reference - Switch page" />
</div>
:::info
For instructions on how to run actions from a RunJS query, refer to the how-to guide [Running Actions from RunJS Query](/docs/how-to/run-actions-from-runjs).
:::

View file

@ -0,0 +1,24 @@
---
id: set-table-page
title: Set Table Page
---
Use this action to change the page index in the table widget.
## Options
| Option | Description |
|--------|-------------|
| Table | Select table from the dropdown |
| Page Index | Numerical value for the page index. ex: `{{2}}` |
| Debounce | Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300` |
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/settablepage/page2.png" alt="ToolJet - Action reference - Open webpage" width="700" />
</div>

View file

@ -0,0 +1,24 @@
---
id: set-variable
title: Set variable
---
This action allows you to create a variable and assign a `value` to it.
## Options
| Option | Description |
|--------|-------------|
| Key | Name(String) of the variable through which you can access the value |
| Value | A value can be a string, number, boolean expression, array, or object |
| Debounce | Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300` |
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/setvar/setvar2.png" alt="ToolJet - Action reference -Set variable" width="700" />
</div>

View file

@ -0,0 +1,23 @@
---
id: show-alert
title: Show alert
---
This action allows you to display an alert message.
You can set a custom **message** for the alert and choose a particular alert type.
There are 4 types of alert messages - **Info**, **Success**, **Warning**, and **Error**.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/show-alert/alert2.png" alt="ToolJet - Action reference - Show Alert" width="700" />
</div>

View file

@ -0,0 +1,18 @@
---
id: show-modal
title: Show modal
---
Use this action to show the modal for an event.
Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300`
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/showmodal/showmodal2.png" alt="ToolJet - Action reference - Show modal" width="700" />
</div>

View file

@ -0,0 +1,55 @@
---
id: switch-page
title: Switch Page
---
Utilize this action with various event handler to transition to a different page within the [Multipage App](/docs/tutorial/pages).
By default, the debounce field is left empty. However, you can input a numeric value to indicate the time in milliseconds before the action is executed. For example, `300`.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/switchpage2.png" alt="ToolJet - Action Reference - Page Switching" width="500"/>
</div>
## Query Params
Query parameters can be passed through action such as `Switch Page`. The parameters are appended to the end of the application URL and are preceded by a question mark (`?`).
Query parameters are composed of key-value pairs, where the `key` and `value` are separated by an equals sign (`=`). Multiple query parameters can be included by clicking on the `+` button.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/queryparam1.png" alt="ToolJet - Action Reference - Page Switching"/>
</div>
In the above screenshot, we have provided the `username` as the key and the value is `{{globals.currentUser.email}}` which gets the email of the signed in user dynamically. When the button is clicked to trigger the `Switch Page` event handler attached to it then the URL on the switched page will have the parameters.
They are commonly used to provide additional information to the server or to modify the behavior of a web page. They can be used for filtering search results, pagination, sorting, and various other purposes.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/queryparam2.png" alt="ToolJet - Action Reference - Page Switching"/>
</div>
## Using RunJS query to switch page
Alternatively, the switch page action can be activated via a RunJS query using the following syntax:
```js
await actions.switchPage('<page-handle>')
```
:::info
For instructions on how to run actions from a RunJS query, refer to the how-to guide [Running Actions from RunJS Query](/docs/how-to/run-actions-from-runjs).
:::
### Switch page with query params
The switch page action can also be triggered along with query parameters using the following syntax:
```js
actions.switchPage('<pageHandle>', [['param1', 'value1'], ['param2', 'value2']])
```

View file

@ -0,0 +1,27 @@
---
id: unset-page-variable
title: Unset page variable
---
Utilize this action to clear a variable that was established using the [set page variable action](/docs/actions/set-page-variable).
By default, the debounce field is left empty. However, you can input a numeric value to indicate the time in milliseconds before the action is executed. For example, `300`.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/page/unsetpagevar2.png" alt="ToolJet - Action reference - Switch page" width="600"/>
</div>
## Using RunJS query to unset variable
Alternatively, the unset page variable action can be triggered via a RunJS query using the following syntax:
```js
await actions.unsetPageVariable('<variablename>')
```
`variablename` is the key of the variable that was provided while creating the variable.
:::info
For instructions on how to run actions from a RunJS query, refer to the how-to guide [Running Actions from RunJS Query](/docs/how-to/run-actions-from-runjs).
:::

View file

@ -0,0 +1,23 @@
---
id: unset-variable
title: Unset variable
---
This action allows you to remove the variable variable that was created using the set variable action.
## Options
| Option | Description |
|--------|-------------|
| Key | Name(String) of the variable through which you can access the value |
| Debounce | Debounce field is empty by default, you can enter a numerical value to specify the time in milliseconds after which the action will be performed. ex: `300` |
:::info
You can also trigger actions from the **JavaScript code**. Check it out [here](/docs/how-to/run-actions-from-runjs).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/actions/unsetvar/unsetvar2.png" alt="ToolJet - Action reference -Unset variable" width="700" />
</div>

View file

@ -0,0 +1,67 @@
---
id: canvas
title: Canvas
---
Canvas is the center area of the ToolJet app builder where the application is built. You arrange the **components** by dragging them from the Components library(right-sidebar).
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/canvas/canvasnew.png" alt="App Builder: Canvas"/>
</div>
<br/>
:::info
- The Canvas height and width can be adjusted from the [Global Settings](/docs/app-builder/left-sidebar#global-settings).
- When the [Pages drawer](/docs/tutorial/pages) on the left is opened or pinned, the canvas becomes horizontally scrollable.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/canvas/scrollnew.gif" alt="App Builder: Canvas"/>
</div>
:::
### Arrange Components
All the components are fully interactive in editor mode - to prevent interaction you can **click and hold** the **Component Handle** to change component's position.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/canvas/handlenew.png" alt="App Builder: Canvas"/>
</div>
### Resize Components
Components on the canvas can be resized from the edges.
You can precisely set the position of selected components using keyboard arrow keys after clicking the component handle.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/canvas/resize.gif" alt="App Builder: Canvas"/>
</div>
### Group Components
ToolJet comes with flexible components to group other components together, such as **[Container](/docs/widgets/container/)** and **[Form](/docs/widgets/form/)**. When you drag and drop components in containers/forms they create a group of nested components. All components can be nested in this way.
### Hide or Disable Components
Hide or Disable a component by setting its **Visibility** or **Disabled** property to `true`. Click on the component handle to open **config inspector** on right side. These values can also evaluate to true based on a truthy value. For example, you can use the property of one component to toggle the Visibility property of another component dynamically, you just need to write a conditional statement.
For example: We want to disable a button when a checkbox is checked so we can simple use `{{components.checkbox1.value}}` in **Disable** property of the button. `{{components.checkbox1.value}}` evaluates to `true` when the checkbox is checked, and false when unchecked.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/canvas/hide.gif" alt="App Builder: Canvas"/>
</div>
### Clone Components
You can clone existing components on the canvas by **cmd/ctrl + d**. Check other **[Keyboard Shortcuts](/docs/tutorial/keyboard-shortcuts)**.

View file

@ -0,0 +1,56 @@
---
id: customstyles
title: Custom Styles
---
<div className='badge badge--primary heading-badge'>Available on: Paid plans</div>
Custom Styles feature enables the implementation of theming on ToolJet apps, allowing users to inject their own CSS styling to override the default app styling. This feature fulfills the requirement of allowing users to easily customize the appearance of their apps.
Custom Styles helps in maintaining consistent themes across the ToolJet apps, alleviating the repetitive burden of styling components whenever a new app is created. By enabling users to apply standardized styles, this feature ensures that each app adheres to a unified theme without the need to manually restyle the components from scratch. As a result, the ToolJet app development process becomes more efficient, and the visual coherence of the apps is preserved, providing users with a seamless experience across all applications.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/customcss/customcss.gif" alt="Custom CSS" />
</div>
## Applying Custom Styles
To add Custom Styles to ToolJet apps, users should follow these steps:
1. Go to the **Custom Styles** Page, accessible under **Workspace Settings** from the ToolJet dashboard.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/customcss/settings.png" alt="Custom CSS" />
</div>
2. When creating a new app on ToolJet, the default button color is **blue**. If you wish to change the default button color to **red**, you must identify the class of the button component, which follows the format `_tooljet-<component>`.
- The browser's inspector can also help you find the class of the component. Classes are added for both **pages** and **components**, and there are two types of selectors for classes: **Common** (`_tooljet-<component>`) and **Individual** (`_tooljet-<defaultComponentName>`).
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/customcss/selectors.png" alt="Custom CSS" />
</div>
3. Once the class (**`_tooljet-Button`**) is identified, navigate to the Custom Styles page and apply the desired CSS changes for that class, as shown in the following CSS code:
```css
._tooljet-Button button {
background: red !important;
}
._tooljet-Button button:hover {
background: green !important;
}
```
4. By applying this custom styles, all future instances of the app will have buttons with a red default color, and they will turn green on hover. This eliminates the need for users to individually edit button properties, streamlining the customization process.
:::info
Custom Styles are injected at the workspace level, ensuring consistent theming across all apps within the workspace.
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/customcss/styledapp.gif" alt="Custom CSS" />
</div>

View file

@ -0,0 +1,101 @@
---
id: left-sidebar
title: Left-sidebar
---
Left-sidebar has the following options:
- **[Pages](#pages)**
- **[Inspector](#inspector)**
- **[Debugger](#debugger)**
- **[Global Settings](#global-settings)**
- **[Comments](#comments)**
- **[Theme switch](#theme-switch)**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/leftnew.png" alt="App Builder: Left-sidebar"/>
</div>
## Pages
Pages allows you to have multiple pages in a single application, making your ToolJet applications more robust and user-friendly.
Check the detailed documentation for **[Pages](/docs/tutorial/pages)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/pagesnew.png" alt="App Builder: Left-sidebar"/>
</div>
## Inspector
The Inspector can be used to inspect the data of the **queries**, properties and values of the **components** that are there on the canvas, ToolJet's global variables and the variables that have been set by the user.
Check the detailed guide on **[using Inspector](/docs/how-to/use-inspector)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/inspectornew.png" alt="App Builder: Left-sidebar"/>
</div>
## Debugger
Debugger records any errors that occur during the execution of queries. For instance, if a database query fails because the database is unavailable or if a REST API query fails due to an incorrect URL, the errors will be captured and shown in the debugger. Additionally, the debugger provides pertinent information associated with the error alongside the error message.
If you wish to prevent the debugger from closing, you can simply click on the pin icon located in the top-right corner. By doing so, the debugger will stay open until you decide to unpin it.
Debugger consists of two main sections:
1. **All Log:** In this section, you can view a comprehensive list of all the logs generated during the execution of the application. These logs may include various types of messages, such as success messages, warning, and error messages.
2. **Errors:** This section specifically focuses on displaying the error messages that occurred during the program's execution. These error messages indicate issues or problems that need attention, as they may lead to unexpected behaviors of the application.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/newdebugger.gif" alt="App Builder: Left-sidebar"/>
</div>
## Global Settings
To configure the app's global settings, click on the kebab menu(three vertical dots) on the left of the app name. Global settings include:
- **Unique app slug**: The unique slug of the application. This slug is used in the URL of the application. By default, the slug is the `app id` of the application. You can change the slug to a custom value. For example, if the slug is `7b56293b-be5a-401f-8806-b71625f8ee0d` you can change it to `<unique-name>` then the new URL of the application will be `https://app.tooljet.com/<workspace-name>/apps/<unique-name>/`
- **App link**: The link to the application. This link can be used to share the application with other users of the workspace. If you want to share the application with users outside the workspace, you can make the application public from the **[Share](/docs/app-builder/share)** modal.
- **Hide header for launched apps**: Toggle this on to the hide the tooljet's header when the applications are launched
- **Maintenance mode**: Toggle this on to put the application in maintenance mode. When in **maintenance mode**, on launching the app, the user will get an error message that **the app is under maintenance**.
- **Max width of canvas**: Modify the width of the canvas in **px** or **%**. The default width is `1292` px.
- **Background color of canvas**: Enter the hex color code or choose a color from the picker to change the background color of the canvas. You can also click on the **Fx** to programmatically set the value.
- **Export app**: Click on the [Export app](/docs/dashboard/#export-app) button to export the application as a JSON file. You can import this JSON file in any other workspace to use the application.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/globalsettings.png" alt="App Builder: Left-sidebar"/>
</div>
## Comments
Comment anywhere on the canvas and collaborate with other users in the workspace. Click on the comments button to enable it and then drop comment anywhere on the canvas.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/commentnew.png" alt="App Builder: Left-sidebar"/>
</div>
## Theme Switch
Use the theme switch button to toggle ToolJet between light and dark modes.
While developers can access the current theme's value through global variables using `{{globals.theme.name}}`, it is not currently feasible to change the theme programmatically.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/leftsidebar/theme.png" alt="App Builder: Left-sidebar"/>
</div>

View file

@ -0,0 +1,20 @@
---
id: overview
title: Overview
---
# App-Builder: Overview
ToolJet's App Builder allows you to build applications. ToolJet's app builder has the following major components:
- **[Topbar](/docs/app-builder/topbar)**: configure app settings
- **[Canvas](/docs/app-builder/canvas)**: Arrange the components to build the interface of app
- **[Left-sidebar](/docs/app-builder/left-sidebar)**: Add **[pages](/docs/tutorial/pages)**, **[inspect](/docs/how-to/use-inspector)** the components, queries or variables, and **[debug](#debugger)** the errors.
- **[Components library](/docs/app-builder/components-library)**(right sidebar): Drag any component or modify the property or styling
- **[Query Panel](/docs/app-builder/query-panel)**: Create, edit or manage the queries from the **[datasources](/docs/data-sources/overview)**
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/appbuilderui2.png" alt="App Builder: Overview"/>
</div>

View file

@ -0,0 +1,218 @@
---
id: query-panel
title: Query Panel
---
The Query Panel, located at the bottom of the app-builder, allows you to create and manage queries for interacting with connected **Default** and **Global** datasources. It provides the capability to perform API requests, query **[databases](/docs/data-sources/overview)**, and apply **[transformations](/docs/tutorial/transformations)** or data manipulation using **[JavaScript](/docs/data-sources/run-js)** and **[Python](/docs/data-sources/run-py)**.
The Query Panel consists of two sections:
- The **[Query Manager](#query-manager)** on the right side, which displays a list of all the created queries.
- The **[Query Editor](#query-editor)**, used to configure the selected query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/querypanel.png" alt="App Builder: Query Panel"/>
</div>
## Query Manager
Query Manager will list all the queries that has been created in the application. Query Manager helps in managing the queries that have been created, you can **add**, **edit**, **delete**, **duplicate**, **search**, **sort** and **filter** through them.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/querymanager.png" alt="App Builder: Query Panel"/>
</div>
### Add
Add button is used to add new query in the application. When Add button is clicked, a menu will open with a list of options for creating a query from **Default** datasources such as **Rest API**, **ToolJet Database**, **JavaScript Code**, **Python Code** or from connected **Global Datasources**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/addquery.gif" alt="App Builder: Query Panel"/>
</div>
### Sort/Filter
On the top of Query Manager, there is button to Sort or Filter queries. The following options are there:
**Filter:**
- By Datasource
**Sort:**
- Name: A-Z
- Name: Z-A
- Type: A-Z
- Type: Z-A
- Last modified: oldest first
- Last modified: newest First
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/sortfilter.gif" alt="App Builder: Query Panel"/>
</div>
### Search
On the top of the query manager is search box that can be used to search for a specific query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/search.gif" alt="App Builder: Query Panel"/>
</div>
### Delete
Delete button will delete the selected query, the button will only show up when you hover over the query name. When you click on the delete button, a confirmation dialog will open to confirm the deletion of the query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/delete.png" alt="App Builder: Query Panel"/>
</div>
### Duplicate
Duplicate button will duplicate the selected query, the button will only show up when you hover over the query name. The duplicate query will be named as `<query name>_copy`.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/duplicate.png" alt="App Builder: Query Panel"/>
</div>
### Rename
Rename button is used to rename the selected query, the button will only show up when you hover over the query name. When you click on the rename button, the query name becomes editable and you can change the name of the query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/rename.png" alt="App Builder: Query Panel"/>
</div>
## Query Editor
Query editor used to configure the query parameters, preview or transform the data return by the query.
:::info
The changes made in the query panel will be saved automatically.
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/editor.png" alt="App Builder: Query Panel"/>
</div>
### Topbar
On the top of the query panel there are a few options:
#### Query Name
The name of query is displayed on the top of the query panel. You can click on it to make it editable and change the name of the query.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/renameeditor.gif" alt="App Builder: Query Panel"/>
</div>
#### Preview
Preview button is used to preview the data returned by the query. The data will be displayed on the preview section present at the bottom of the query panel. This helps in debugging the query and see the data returned by the query without triggering the query in the app.
The Preview of data is returned in two different formats: **Raw** & **JSON**. You can click on the clear button to clear the preview data.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/preview.gif" alt="App Builder: Query Panel"/>
</div>
#### Run
Run is used to trigger the query, running the query will interact with the application unlike `Preview`.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/run.gif" alt="App Builder: Query Panel"/>
</div>
### Query Parameters
Query Parameters are essential values that must be provided in a query for the server to generate a response. These parameters encompass **endpoints**, **methods**, or **operations**. It's important to note that the specific set of Query Parameters varies for each datasource.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/params.png" alt="App Builder: Query Panel"/>
</div>
#### Datasource
The primary and default parameter found in all queries is **Datasource**. This option allows you to choose the appropriate datasource for your query.
In cases where multiple datasources of the same type are connected, you can easily switch the query's datasource using the dropdown menu.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/switch.png" alt="App Builder: Query Panel"/>
</div>
### Transformation
Transformations can be enabled on queries to transform the query results. ToolJet allows you to transform the query results using two programming languages JavaScript & Python. Check the detailed documentation on **[Transformations](/docs/tutorial/transformations)**.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/transform.gif" alt="App Builder: Query Panel"/>
</div>
### Settings
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/settings.png" alt="App Builder: Query Panel"/>
</div>
#### Run this query on application load?
Enabling this option will execute the query every time the app is loaded.
#### Request confirmation before running the query?
Enabling this option show a confirmation modal to confirm `Yes` or `No` if you want to fire that query.
#### Show notification on success?
Enabling this option show a success toast notification when the query is successfully triggered.
You can provide a custom **success message** and **notification duration** in milliseconds.
### Events
Event handlers can be added to queries for the following events:
- **Query Success**
- **Query Failure**
:::info
Learn more about [Event Handlers and Actions](/docs/widgets/overview#component-event-handlers).
:::
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/querypanel/newui2/events.png" alt="App Builder: Query Panel"/>
</div>

View file

@ -0,0 +1,29 @@
---
id: components-library
title: Components Library
---
The **Components Library** on the right sidebar contains all of the available components. Use this to drag-and-drop a component from the library to the canvas. It organizes components into sections and you can enter a search term to quickly find a component you need.
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/rightsidebar/librarynew.png" alt="App Builder: Component library- right sidebar"/>
</div>
:::tip
Check the **[Components Catalog](/docs/widgets/overview)** to know more about specific component.
:::
## Component Config Inspector
The Component Config Inspector is also called as component inspector. It contains all the available settings for the selected component and is where you **set values**, **update component names**, and **create event handlers**. The Component Inspector organizes settings into different sections, such as **Property** and **Styles**.
To open the Component Config Inspector, click on the **[component handle](/docs/app-builder/canvas#arrange-components)** that is present on the top of the component including **⚙️ + Component Name** and the component inspector will open up on the right side:
<div style={{textAlign: 'center'}}>
<img className="screenshot-full" src="/img/v2-beta/app-builder/rightsidebar/configinspector.gif" alt="App Builder: Component library- right sidebar"/>
</div>

Some files were not shown because too many files have changed in this diff Show more