@@ -13,30 +17,115 @@ Datasources pull in and push data to any source including databases, external AP
-## Connecting datasources
+## Connecting global datasources
-1. After logging in to ToolJet, create a new app from the dashboard
+1. From the ToolJet dashboard, go to the **global datasources page** from the left sidebar.
+
-2. There are two ways for connecting a datasource. You can connect from:
- 1. **Left-sidebar**: On the left sidebar, click on the `datasource` icon and then click on the `+ add datasource` button
+
-
+
-
+2. Click on the **Add new datasource** button, a modal will pop-up with all the available global datasources.
+
-
+
- 2. **Query Panel**: Go to the query panel at the bottom, click on the `+Add` button and then click `Add datasource` button
+
-
+3. Select the datasource, enter the **Credentials** and **Save** the datasource.
+
-
+
-
+
-3. Follow the steps in the **[Datasource Library](/docs/data-sources/airtable)** specific to the desired datasource
+4. Now, go back to the dashboard, create a new app, and the datasource will be available on the query panel under **Global Datasources**. Added datasources will be available on any of the **existing** or the **new applications**.
+
+
+
+
+
+
+5. You can now create queries of the connected global datasource. From the queries, you'll be able to switch to **different connections** of the same datasource if there are more than one connections created.
+
+
+
+
+
+
+## Changing scope of datasources of an app created on older versions of ToolJet
+
+On ToolJet versions below 2.3.0, the datasource connection was made from within the individual apps. To make it backward compatible, we added an option to change the scope of the datasources and make it global datasource.
+
+1. If you open an app created on previos versions of ToolJet, you'll find the datasource manager on the left sidebar of the App Builder.
+
+
+
+
+
+
+2. Click on the kebab menu next to the connected datasource, select the **change scope** option.
+
+
+
+
+
+
+3. Once you change the scope of the datasource and make it global, you'll see that the **datasource manager** is removed from the left sidebar and now you'll find the datasource on the **query panel** under Global Datasources. You can now configure the datasource fromt the Global Datasource page on the **dashboard**.
+
+
+
+
+
+
+
+## Default datasources
+
+By default, 4 datasources will be available on every app on ToolJet:
+- **[ToolJet Database](/docs/tooljet-database/)**
+- **[RestAPI](/docs/data-sources/restapi/)**
+- **[Run JavaScript Query](/docs/data-sources/run-js/)**
+- **[Run Python Query](/docs/data-sources/run-py/)**
+
+
+
+
+
+
+
+## Permissions
+
+Only **Admins** and **[Super Admins](/docs/Enterprise/superadmin)** of the workspace can change the **[Permissions](/docs/tutorial/manage-users-groups#group-properties)** for Global Datasource.
+
+From **Workspace Settings** -> **Groups Settings**, Admins and Super Admins can set the permission for a user group to:
+
+- **Create** and **Delete** datasources onto that workspace. If **Create** permission is enabled then the users can add new global datasources and **edit** the datasources as well but cannot **delete** it, and if only **Delete** permission is set then the users of the group will only be able to delete the connected datasources on the workspace.
+
+
+
+
+
+
+ - If any of the permission(Create or Delete) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
+
+- **View** or **Edit** allowed global datasources from the **Datasources** tab. If only **View** permission is set then the users of the group will only be able to connect to the allowed datasource, and if only **Edit** permission is set then the users of the group will be able to update the credentials of the allowed datasources.
+
+
+
+
+
+
+ - If any of the permission(View or Edit) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
-:::info
-ToolJet allows you to transform the data returned by datasources using **[Transformations](/docs/tutorial/transformations)**
-:::
diff --git a/docs/docs/data-sources/smtp.md b/docs/docs/data-sources/smtp.md
index 120f2b1d08..9f09a14ac4 100644
--- a/docs/docs/data-sources/smtp.md
+++ b/docs/docs/data-sources/smtp.md
@@ -5,18 +5,24 @@ title: SMTP
# SMTP
-SMTP plugin can connect ToolJet applications to **SMTP servers** for sending emails.
+The SMTP datasource facilitates the connection between ToolJet applications and email servers, enabling the apps to send emails.
## Connection
-A SMTP server can be connected with the following credentails:
-- **Host**
-- **Port**
-- **User**
+To connect to an SMTP server, the following credentials are typically required:
+
+- **Host**
+- **Port**
+- **Username**
- **Password**
-:::info
-You can also test your connection before saving the configuration by clicking on `Test Connection` button.
+:::tip Finding configuration details:
+The SMTP configuration details like host and port can usually be obtained from your email service provider. Here are some general settings for the most commonly used email providers:
+- **Gmail**: `Host`: smtp.gmail.com; `Port`: 587 or 465 (SSL); `Username`: your full Gmail email address; `Password`: your Gmail password.
+- **Yahoo Mail**: `Host`: smtp.mail.yahoo.com; `Port`: 465 (SSL); `Username`: your Yahoo Mail email address; `Password`: your Yahoo Mail password.
+- **Outlook.com/Hotmail**: `Host`: smtp.office365.com; `Port`: 587 or 465 (SSL); `Username`: your Outlook.com/Hotmail email address; `Password`: your Outlook.com/Hotmail password.
+
+Before saving the configuration, it's possible to test the connection by clicking the "Test Connection" button.
:::
@@ -27,22 +33,25 @@ You can also test your connection before saving the configuration by clicking on
## Querying SMTP
-Go to the query manager at the bottom panel of the editor and click on the `+` button on the left to create a new query. Select `SMTP` from the datasource dropdown.
+To create a query for sending an email, follow these steps:
-To create a query for sending email, you will need to provide the following properties:
- - **From** `required` : Email address of the sender
- - **From Name** : Name of the sender
- - **To** `required` : Recipient's email address
- - **Subject** : Subject of the email
+1. Open the query panel located at the bottom panel of the editor.
+2. Click the `+Add` button on the left to create a new query.
+3. Select `SMTP` from the global datasource.
+4. Provide the following properties:
+ - **From** `required` : Email address of the sender
+ - **From Name** : Name of the sender
+ - **To** `required` : Recipient's email address
+ - **CC mail to** : Email address of the recipients that will receive a copy of the email, and their email addresses will be visible to other recipients.
+ - **BCC mail to** : Email address of the recipients that will receive a copy of the email but the email addressed will be hidden to other recipients.
+ - **Subject** : Subject of the email.
+ - **Body** : You can enter the body text of the email in either raw text or html format, in their respective fields.
+ - **Attachments** : You can add attachments to an SMTP query by referencing the file from the File Picker component in the attachments field.
+For instance, you can set the `Attachments` field value to `{{ components.filepicker1.file }}` or pass an array of `{{ name: 'filename.jpg', dataURL: '......' }}` objects to include attachments.
-
+
+
- - **Body** : You can enter the body text either in the form of `raw text` or `html` in their respective fields.
- - **Attachments** : Attachments can be added to a SMTP query by referencing the file from the `File Picker` component in the attachments field.
-
- For example, you can set the `Attachments` field value to `{{ components.filepicker1.file }}` or you can pass an array of `{{ name: 'filename.jpg', dataURL: '......' }}` object to accomplish this.
-
-
-
+
\ No newline at end of file
diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md
index 3d944f62c9..42699a3b53 100644
--- a/docs/docs/getting-started.md
+++ b/docs/docs/getting-started.md
@@ -143,7 +143,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
:::info
-ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **Components Catalog** to learn more.
+ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **[Components Catalog](/docs/widgets/overview)** to learn more.
:::
### Build queries and bind data to UI
@@ -156,7 +156,7 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
- ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
+ ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **[Datasource Catalog](/docs/data-sources/overview)** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
@@ -199,8 +199,8 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
-- You can manipulate the data returned by the queries using **Transformations**
-- You can also **Run JS query** or **Python query** to perform custom behavior inside ToolJet
+- You can manipulate the data returned by the queries using **[Transformations](/docs/tutorial/transformations)**
+- You can also **[Run JavaScript code](/docs/data-sources/run-js)** or **[Run Python code](/docs/data-sources/run-py)** to perform custom behavior inside ToolJet
:::
### Preview, Release and Share app
@@ -210,7 +210,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. **Share** option allows you to share the **released version** of the application with other users or you can also make the app **public** and anyone with the URL will be able to use the app.
:::tip
-You can control how much access to users have to your ToolJet apps and resources using **Org Management**.
+You can control how much access to users have to your ToolJet apps and resources using **[Org Management](/docs/tutorial/manage-users-groups)**.
:::
## What Can I Do With ToolJet
diff --git a/docs/docs/how-to/intentionally-fail-js-query.md b/docs/docs/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/docs/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/docs/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/docs/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/docs/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/docs/org-management/permissions.md b/docs/docs/org-management/permissions.md
index 5e33f5cb2c..b13433e0ef 100644
--- a/docs/docs/org-management/permissions.md
+++ b/docs/docs/org-management/permissions.md
@@ -8,7 +8,7 @@ Permissions allow you to create and share resources to easily ensure what level
Admins can invite **Users** to their workspaces and assign them to the **Groups** that have Permissions to access Apps, folders, or workspace variables.
:::info
-See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn how to invite users to ToolJet.
+See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to know more about managing users and groups on your workspace.
:::
## Role-Based Access Control (RBAC) Glossary
@@ -18,4 +18,4 @@ See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn h
- **All Users** - Contains all the users in your workspace. When **New Users** are invited they are added to this group by default.
- **Admins** - Contains all Admins in your workspace. Everyone added to this group will Permission to access all the ToolJet resources.
- **Apps, Folder, Workspace Variables -** Resources that Admins can set permissions on.
-- **Permissions -** Create, Update and Delete.
+- **Permissions -** Create, Update and Delete.
\ No newline at end of file
diff --git a/docs/docs/tutorial/manage-users-groups.md b/docs/docs/tutorial/manage-users-groups.md
index 95991fd7fa..185d078f60 100644
--- a/docs/docs/tutorial/manage-users-groups.md
+++ b/docs/docs/tutorial/manage-users-groups.md
@@ -77,7 +77,7 @@ Similar to archiving a user's access, you can enable it again by clicking on **U
## Managing Groups
-On ToolJet, Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
+On ToolJet, Admins and Super Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
@@ -87,11 +87,16 @@ On ToolJet, Admins can create groups for users added in a workspace and grant th
### Group properties
-Every group on ToolJet has three sections:
+Every group on ToolJet has **four** sections:
+
+- [Apps](#apps)
+- [Users](#users)
+- [Permissions](#permissions)
+- [Datasources](#datasources)
#### Apps:
-Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
+Admins and Super Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
@@ -101,7 +106,7 @@ Admins can add or remove any number of apps for a group of users. To add an app
#### Users:
-Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
+Admins and Super Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
@@ -111,16 +116,30 @@ Admins can add or remove any numbers of users in a group. Just select a user fro
#### Permissions:
-Admins can set granular permission like creating/deleting apps or creating folder for a group of users.
+Admins and Super Admins can set granular permission for the users added in that particular group, such as:
+- **Create** and **Delete** Apps
+- **Create**, **Update**, and **Delete** Folders
+- **Create**, **Update**, and **Delete** [Workspace Variables](/docs/tutorial/workspace-variables)
+- **Create** and **Delete** [Global Datasources](/docs/widgets/overview)
-
+
+
+
+
+#### Datasources:
+
+Only Admins and Super Admins can define what datasources can be **viewed** or **edited** by the users of that group.
+
+
+
+
:::tip
-All the activities performed by any Admin or any user in a workspace is logged in `Audit logs` - including any activity related with managing users and groups.
+All the activities performed by any Admin, Super Admin or any user in a workspace is logged in [Audit logs](/docs/Enterprise/audit_logs) - including any activity related with managing users and groups.
:::
### Predefined Groups
diff --git a/docs/docs/widgets/table.md b/docs/docs/widgets/table.md
index 15b05f6fbd..793b161916 100644
--- a/docs/docs/widgets/table.md
+++ b/docs/docs/widgets/table.md
@@ -8,11 +8,64 @@ Tables can be used for both displaying and editing data.
+## Table UI
+
+
+
+
+
+
+
+### Search
+
+At the top-left corner of the table component, there is a search box that allows users to input keywords and search for rows within the table data. You can also **[show/hide the search box](/docs/widgets/table#show-search-box)** from the table from the table properties.
+
+### Add new row
+
+When users click on this button, a popup modal appears which enables them to insert new rows. The modal will have a single row initially, and the columns will have the same column type as those on the table. If the user inputs data into the row, it will be stored on the **[`newRows` variable](/docs/widgets/table#exposed-variables)** of the table. If the user selects the **Discard** button, the data in the variable will be cleared. However, if the user closes the popup without taking any action (neither Save nor Discard), the data will still be retained, and a green indicator will appear on the **Add new row** button. The table has an **[Add new rows event handler](/docs//widgets/table#add-new-rows)** that can be utilized to execute queries that store the data into the datasource whenever the **Save** button is clicked.
+
+:::info
+At present, it is not possible to include columns of type Image when adding a new row to the table.
+:::
+
+### Filters
+
+The table data can be filtered by clicking on this button. You have the option to choose from various filters, such as:
+
+- **contains**
+- **does not contain**
+- **matches**
+- **does not match**
+- **equals**
+- **does not equal**
+- **is empty**
+- **is not empty**
+- **greater than**
+- **greater than or equal to**
+- **less than**
+- **less than or equal to**
+
+You have the option to **[hide the filter button](/docs/widgets/table#show-filter-button)** in the table properties.
+
+### Download
+
+The table data can be downloaded in various file formats, including:
+
+- **CSV**
+- **Excel**
+- **PDF**
+
+You have the option to **[hide the download button](/docs/widgets/table#show-download-button)** in the table properties.
+
+### Column selector button
+
+You can choose which columns to display or hide in the table by clicking on this button. You also have the option to **[hide the column selector button](/docs/widgets/table#show-column-selector-button)** in the table properties.
+
## Table data
-
+
@@ -197,28 +250,15 @@ If server-side search is enabled, `on search` event is fired after the content o
### Show download button
-Show or hide download button at the Table footer.
+The download button in the table header is visible by default. You can choose to hide it by disabling this option. You can dynamically set the value to {{true}} or {{false}} to show or hide the download button by clicking on the **Fx** button.
-### Hide/Show columns
+### Show column selector button
-Table header has an option(Eye icon) to show/hide one or many columns on the table.
+The column selector button on the table header is visible by default. You can choose to hide it by disabling this option. You can dynamically set the value to {{true}} or {{false}} to show or hide the column selector button by clicking on the **Fx** button.
### Show filter button
-Show or hide filter button at the Table header. The following filters are available:
-- **contains**
-- **does not contain**
-- **matches**
-- **does not match**
-- **equals**
-- **does not equal to**
-- **is empty**
-- **is not empty**
-- **greater than**
-- **greater than or equal to**
-- **less than**
-- **less than or equal to**
-
+The filter button in the table header is visible by default. You can choose to hide it by disabling this option. You can dynamically set the value to {{true}} or {{false}} to show or hide the filter button by clicking on the **Fx** button.
### Show update buttons
@@ -263,6 +303,7 @@ Loading state shows a loading skeleton for the table. This property can be used
- **[Sort applied](#sort-applied)**
- **[Cell value changed](#cell-value-changed)**
- **[Filter changed](#filter-changed)**
+- **[Add new rows](#add-new-rows)**
### Row hovered
@@ -300,6 +341,10 @@ If any cell of the table is edited, the `cell value changed` event is triggered.
This event is triggered when filter is added, removed, or updated from the filter section of the table. `filters` property of the table is updated to reflect the status of filters applied. The objects will have properties: `condition`, `value`, and `column`.
+### Add new rows
+
+This event is triggered when the **Save** button is clicked from the **Add new row** modal on the table.
+
## Exposed variables
| variable | description |
@@ -311,6 +356,7 @@ This event is triggered when filter is added, removed, or updated from the filte
| dataUpdates | Just like changeSet but includes the data of the entire row |
| selectedRow | The data of the row that was last clicked. `selectedRow` also changes when an action button is clicked |
| searchText | The value of the search field if server-side pagination is enabled |
+| newRows| The newRows variable stores an array of objects, each containing data for a row that was added to the table using the "Add new row" button. When the user clicks either the "Save" or "Discard" button in the modal, this data is cleared.|
## Styles
diff --git a/docs/sidebars.js b/docs/sidebars.js
index 7f2ae33f30..73f65d0182 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -303,8 +303,10 @@ const sidebars = {
'how-to/import-external-libraries-using-runpy',
'how-to/import-external-libraries-using-runjs',
'how-to/run-actions-from-runjs',
+ 'how-to/intentionally-fail-js-query',
'how-to/run-query-at-specified-intervals',
'how-to/access-users-location',
+ 'how-to/use-s3-signed-url-to-upload-docs',
'how-to/s3-custom-endpoints',
'how-to/oauth2-authorization',
'how-to/upload-files-aws',
diff --git a/docs/static/img/datasource-reference/overview/changescope.png b/docs/static/img/datasource-reference/overview/changescope.png
new file mode 100644
index 0000000000..95f0df6dbd
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/changescope.png differ
diff --git a/docs/static/img/datasource-reference/overview/connection.png b/docs/static/img/datasource-reference/overview/connection.png
new file mode 100644
index 0000000000..46f77abcdb
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/connection.png differ
diff --git a/docs/static/img/datasource-reference/overview/create.png b/docs/static/img/datasource-reference/overview/create.png
new file mode 100644
index 0000000000..093892dd6b
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/create.png differ
diff --git a/docs/static/img/datasource-reference/overview/default.png b/docs/static/img/datasource-reference/overview/default.png
new file mode 100644
index 0000000000..bb86b2c259
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/default.png differ
diff --git a/docs/static/img/datasource-reference/overview/edit.png b/docs/static/img/datasource-reference/overview/edit.png
new file mode 100644
index 0000000000..ed5a82134a
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/edit.png differ
diff --git a/docs/static/img/datasource-reference/overview/error.png b/docs/static/img/datasource-reference/overview/error.png
new file mode 100644
index 0000000000..eafe42cef0
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/error.png differ
diff --git a/docs/static/img/datasource-reference/overview/global.png b/docs/static/img/datasource-reference/overview/global.png
new file mode 100644
index 0000000000..746eacba93
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/global.png differ
diff --git a/docs/static/img/datasource-reference/overview/globalquery.png b/docs/static/img/datasource-reference/overview/globalquery.png
new file mode 100644
index 0000000000..f2273650fc
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/globalquery.png differ
diff --git a/docs/static/img/datasource-reference/overview/leftsidebar.png b/docs/static/img/datasource-reference/overview/leftsidebar.png
new file mode 100644
index 0000000000..1d6f717eab
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/leftsidebar.png differ
diff --git a/docs/static/img/datasource-reference/overview/popup.png b/docs/static/img/datasource-reference/overview/popup.png
new file mode 100644
index 0000000000..a3d945b374
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/popup.png differ
diff --git a/docs/static/img/datasource-reference/overview/queryadd.png b/docs/static/img/datasource-reference/overview/queryadd.png
new file mode 100644
index 0000000000..8caf9ff3dd
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/queryadd.png differ
diff --git a/docs/static/img/datasource-reference/overview/switch.png b/docs/static/img/datasource-reference/overview/switch.png
new file mode 100644
index 0000000000..817fe042d7
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/switch.png differ
diff --git a/docs/static/img/datasource-reference/overview/view.png b/docs/static/img/datasource-reference/overview/view.png
new file mode 100644
index 0000000000..f811c45dd9
Binary files /dev/null and b/docs/static/img/datasource-reference/overview/view.png differ
diff --git a/docs/static/img/datasource-reference/smtp/querysmtp.png b/docs/static/img/datasource-reference/smtp/querysmtp.png
new file mode 100644
index 0000000000..75a7a8ca82
Binary files /dev/null and b/docs/static/img/datasource-reference/smtp/querysmtp.png differ
diff --git a/docs/static/img/how-to/failjs/failjs.gif b/docs/static/img/how-to/failjs/failjs.gif
new file mode 100644
index 0000000000..c042f682d4
Binary files /dev/null and b/docs/static/img/how-to/failjs/failjs.gif differ
diff --git a/docs/static/img/how-to/uses3presignedurl/copysigned.png b/docs/static/img/how-to/uses3presignedurl/copysigned.png
new file mode 100644
index 0000000000..ffdd0793c0
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/copysigned.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/dropdown.png b/docs/static/img/how-to/uses3presignedurl/dropdown.png
new file mode 100644
index 0000000000..0c97c1c9a8
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/dropdown.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/eventhandlerrunjs2.png b/docs/static/img/how-to/uses3presignedurl/eventhandlerrunjs2.png
new file mode 100644
index 0000000000..21ebd55481
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/eventhandlerrunjs2.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/eventhandlerupload.png b/docs/static/img/how-to/uses3presignedurl/eventhandlerupload.png
new file mode 100644
index 0000000000..5670721423
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/eventhandlerupload.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/fetchfiles.png b/docs/static/img/how-to/uses3presignedurl/fetchfiles.png
new file mode 100644
index 0000000000..21e548b7af
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/fetchfiles.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/getbuckets.png b/docs/static/img/how-to/uses3presignedurl/getbuckets.png
new file mode 100644
index 0000000000..ba62cc882d
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/getbuckets.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/newversion.png b/docs/static/img/how-to/uses3presignedurl/newversion.png
new file mode 100644
index 0000000000..aac030e909
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/newversion.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/runjs1.png b/docs/static/img/how-to/uses3presignedurl/runjs1.png
new file mode 100644
index 0000000000..0313e21b49
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/runjs1.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/runjs2.png b/docs/static/img/how-to/uses3presignedurl/runjs2.png
new file mode 100644
index 0000000000..17a13c6d06
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/runjs2.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/s3connect.png b/docs/static/img/how-to/uses3presignedurl/s3connect.png
new file mode 100644
index 0000000000..7ade00fada
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/s3connect.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/template.png b/docs/static/img/how-to/uses3presignedurl/template.png
new file mode 100644
index 0000000000..761705dee4
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/template.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/upload.png b/docs/static/img/how-to/uses3presignedurl/upload.png
new file mode 100644
index 0000000000..93f1924c14
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/upload.png differ
diff --git a/docs/static/img/how-to/uses3presignedurl/uploadbutton.png b/docs/static/img/how-to/uses3presignedurl/uploadbutton.png
new file mode 100644
index 0000000000..f580239948
Binary files /dev/null and b/docs/static/img/how-to/uses3presignedurl/uploadbutton.png differ
diff --git a/docs/static/img/tutorial/manage-users-groups/dspermission.png b/docs/static/img/tutorial/manage-users-groups/dspermission.png
new file mode 100644
index 0000000000..69e1c57a2d
Binary files /dev/null and b/docs/static/img/tutorial/manage-users-groups/dspermission.png differ
diff --git a/docs/static/img/tutorial/manage-users-groups/gdspermission.png b/docs/static/img/tutorial/manage-users-groups/gdspermission.png
new file mode 100644
index 0000000000..35b8423a69
Binary files /dev/null and b/docs/static/img/tutorial/manage-users-groups/gdspermission.png differ
diff --git a/docs/static/img/widgets/table/ui.png b/docs/static/img/widgets/table/ui.png
new file mode 100644
index 0000000000..7a42690459
Binary files /dev/null and b/docs/static/img/widgets/table/ui.png differ
diff --git a/docs/versioned_docs/version-1.x.x/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-1.x.x/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-1.x.x/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-1.x.x/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-1.x.x/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-1.x.x/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.0.0/getting-started.md b/docs/versioned_docs/version-2.0.0/getting-started.md
index 3d944f62c9..42699a3b53 100644
--- a/docs/versioned_docs/version-2.0.0/getting-started.md
+++ b/docs/versioned_docs/version-2.0.0/getting-started.md
@@ -143,7 +143,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
:::info
-ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **Components Catalog** to learn more.
+ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **[Components Catalog](/docs/widgets/overview)** to learn more.
:::
### Build queries and bind data to UI
@@ -156,7 +156,7 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
- ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
+ ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **[Datasource Catalog](/docs/data-sources/overview)** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
@@ -199,8 +199,8 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
-- You can manipulate the data returned by the queries using **Transformations**
-- You can also **Run JS query** or **Python query** to perform custom behavior inside ToolJet
+- You can manipulate the data returned by the queries using **[Transformations](/docs/tutorial/transformations)**
+- You can also **[Run JavaScript code](/docs/data-sources/run-js)** or **[Run Python code](/docs/data-sources/run-py)** to perform custom behavior inside ToolJet
:::
### Preview, Release and Share app
@@ -210,7 +210,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. **Share** option allows you to share the **released version** of the application with other users or you can also make the app **public** and anyone with the URL will be able to use the app.
:::tip
-You can control how much access to users have to your ToolJet apps and resources using **Org Management**.
+You can control how much access to users have to your ToolJet apps and resources using **[Org Management](/docs/tutorial/manage-users-groups)**.
:::
## What Can I Do With ToolJet
diff --git a/docs/versioned_docs/version-2.0.0/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-2.0.0/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-2.0.0/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.0.0/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-2.0.0/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-2.0.0/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.1.0/getting-started.md b/docs/versioned_docs/version-2.1.0/getting-started.md
index 3d944f62c9..42699a3b53 100644
--- a/docs/versioned_docs/version-2.1.0/getting-started.md
+++ b/docs/versioned_docs/version-2.1.0/getting-started.md
@@ -143,7 +143,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
:::info
-ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **Components Catalog** to learn more.
+ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **[Components Catalog](/docs/widgets/overview)** to learn more.
:::
### Build queries and bind data to UI
@@ -156,7 +156,7 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
- ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
+ ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **[Datasource Catalog](/docs/data-sources/overview)** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
@@ -199,8 +199,8 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
-- You can manipulate the data returned by the queries using **Transformations**
-- You can also **Run JS query** or **Python query** to perform custom behavior inside ToolJet
+- You can manipulate the data returned by the queries using **[Transformations](/docs/tutorial/transformations)**
+- You can also **[Run JavaScript code](/docs/data-sources/run-js)** or **[Run Python code](/docs/data-sources/run-py)** to perform custom behavior inside ToolJet
:::
### Preview, Release and Share app
@@ -210,7 +210,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. **Share** option allows you to share the **released version** of the application with other users or you can also make the app **public** and anyone with the URL will be able to use the app.
:::tip
-You can control how much access to users have to your ToolJet apps and resources using **Org Management**.
+You can control how much access to users have to your ToolJet apps and resources using **[Org Management](/docs/tutorial/manage-users-groups)**.
:::
## What Can I Do With ToolJet
diff --git a/docs/versioned_docs/version-2.1.0/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-2.1.0/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-2.1.0/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.1.0/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-2.1.0/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-2.1.0/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.2.0/getting-started.md b/docs/versioned_docs/version-2.2.0/getting-started.md
index 3d944f62c9..42699a3b53 100644
--- a/docs/versioned_docs/version-2.2.0/getting-started.md
+++ b/docs/versioned_docs/version-2.2.0/getting-started.md
@@ -143,7 +143,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
:::info
-ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **Components Catalog** to learn more.
+ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **[Components Catalog](/docs/widgets/overview)** to learn more.
:::
### Build queries and bind data to UI
@@ -156,7 +156,7 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
- ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
+ ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **[Datasource Catalog](/docs/data-sources/overview)** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
@@ -199,8 +199,8 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
-- You can manipulate the data returned by the queries using **Transformations**
-- You can also **Run JS query** or **Python query** to perform custom behavior inside ToolJet
+- You can manipulate the data returned by the queries using **[Transformations](/docs/tutorial/transformations)**
+- You can also **[Run JavaScript code](/docs/data-sources/run-js)** or **[Run Python code](/docs/data-sources/run-py)** to perform custom behavior inside ToolJet
:::
### Preview, Release and Share app
@@ -210,7 +210,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. **Share** option allows you to share the **released version** of the application with other users or you can also make the app **public** and anyone with the URL will be able to use the app.
:::tip
-You can control how much access to users have to your ToolJet apps and resources using **Org Management**.
+You can control how much access to users have to your ToolJet apps and resources using **[Org Management](/docs/tutorial/manage-users-groups)**.
:::
## What Can I Do With ToolJet
diff --git a/docs/versioned_docs/version-2.2.0/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-2.2.0/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-2.2.0/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.2.0/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-2.2.0/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-2.2.0/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.3.0/Enterprise/superadmin.md b/docs/versioned_docs/version-2.3.0/Enterprise/superadmin.md
index 10ebe5551b..43332fd236 100644
--- a/docs/versioned_docs/version-2.3.0/Enterprise/superadmin.md
+++ b/docs/versioned_docs/version-2.3.0/Enterprise/superadmin.md
@@ -17,13 +17,14 @@ The user details entered while setting up ToolJet will have Super Admin privileg
| 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 Global datasources 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 Variables)](#manage-workspace-setting-groupsssoworkspace-variables) | ❌ | ✅ |
| [Manage all users from all the workspaces in the instance](#checking-all-the-users-in-the-instance) | ❌ | ✅ |
| [Make any user Super Admin](#make-the-user-super-admin) | ❌ | ✅ |
-| [Restrict personal workspace of invited users](#allow-users-to-create-personal-workspace) | ❌ | ✅ |
+| [Restrict creation of personal workspace of users](#restrict-creation-of-personal-workspace-of-users) | ❌ | ✅ |
@@ -117,11 +118,11 @@ The user will become Super Admin and the Type column will update from **`workspa
-### Allow users to create personal workspace
+### 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 Instance 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.
+Super Admins can **control** this behavior from the Manage Instance 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.
diff --git a/docs/versioned_docs/version-2.3.0/data-sources/overview.md b/docs/versioned_docs/version-2.3.0/data-sources/overview.md
index ec7527f8af..7e72107e61 100644
--- a/docs/versioned_docs/version-2.3.0/data-sources/overview.md
+++ b/docs/versioned_docs/version-2.3.0/data-sources/overview.md
@@ -3,9 +3,13 @@ id: overview
title: Overview
---
-# Datasources : Overview
+# Global Datasources : Overview
-Datasources pull in and push data to any source including databases, external APIs, or services.
+Global datasources pull in and push data to any source including databases, external APIs, or services. Once a global datasource is connected to a workspace, the connection can be shared with any app of that workspace.
+
+:::caution
+Global datasources are available only on **ToolJet version 2.3.0 and above**.
+:::
@@ -13,30 +17,115 @@ Datasources pull in and push data to any source including databases, external AP
-## Connecting datasources
+## Connecting global datasources
-1. After logging in to ToolJet, create a new app from the dashboard
+1. From the ToolJet dashboard, go to the **global datasources page** from the left sidebar.
+
-2. There are two ways for connecting a datasource. You can connect from:
- 1. **Left-sidebar**: On the left sidebar, click on the `datasource` icon and then click on the `+ add datasource` button
+
-
+
-
+2. Click on the **Add new datasource** button, a modal will pop-up with all the available global datasources.
+
-
+
- 2. **Query Panel**: Go to the query panel at the bottom, click on the `+Add` button and then click `Add datasource` button
+
-
+3. Select the datasource, enter the **Credentials** and **Save** the datasource.
+
-
+
-
+
-3. Follow the steps in the **[Datasource Library](/docs/data-sources/airtable)** specific to the desired datasource
+4. Now, go back to the dashboard, create a new app, and the datasource will be available on the query panel under **Global Datasources**. Added datasources will be available on any of the **existing** or the **new applications**.
+
+
+
+
+
+
+5. You can now create queries of the connected global datasource. From the queries, you'll be able to switch to **different connections** of the same datasource if there are more than one connections created.
+
+
+
+
+
+
+## Changing scope of datasources of an app created on older versions of ToolJet
+
+On ToolJet versions below 2.3.0, the datasource connection was made from within the individual apps. To make it backward compatible, we added an option to change the scope of the datasources and make it global datasource.
+
+1. If you open an app created on previos versions of ToolJet, you'll find the datasource manager on the left sidebar of the App Builder.
+
+
+
+
+
+
+2. Click on the kebab menu next to the connected datasource, select the **change scope** option.
+
+
+
+
+
+
+3. Once you change the scope of the datasource and make it global, you'll see that the **datasource manager** is removed from the left sidebar and now you'll find the datasource on the **query panel** under Global Datasources. You can now configure the datasource fromt the Global Datasource page on the **dashboard**.
+
+
+
+
+
+
+
+## Default datasources
+
+By default, 4 datasources will be available on every app on ToolJet:
+- **[ToolJet Database](/docs/tooljet-database/)**
+- **[RestAPI](/docs/data-sources/restapi/)**
+- **[Run JavaScript Query](/docs/data-sources/run-js/)**
+- **[Run Python Query](/docs/data-sources/run-py/)**
+
+
+
+
+
+
+
+## Permissions
+
+Only **Admins** and **[Super Admins](/docs/Enterprise/superadmin)** of the workspace can change the **[Permissions](/docs/tutorial/manage-users-groups#group-properties)** for Global Datasource.
+
+From **Workspace Settings** -> **Groups Settings**, Admins and Super Admins can set the permission for a user group to:
+
+- **Create** and **Delete** datasources onto that workspace. If only **Create** permission is set then the users of the group will only be able to add new datasources on the workspace, and if only **Delete** permission is set then the users of the group will only be able to delete the connected datasources on the workspace.
+
+
+
+
+
+
+ - If any of the permission(Create or Delete) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
+
+- **View** or **Edit** allowed global datasources from the **Datasources** tab. If only **View** permission is set then the users of the group will only be able to connect to the allowed datasource, and if only **Edit** permission is set then the users of the group will be able to update the credentials of the allowed datasources.
+
+
+
+
+
+
+ - If any of the permission(View or Edit) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
-:::info
-ToolJet allows you to transform the data returned by datasources using **[Transformations](/docs/tutorial/transformations)**
-:::
diff --git a/docs/versioned_docs/version-2.3.0/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-2.3.0/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-2.3.0/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.3.0/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-2.3.0/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-2.3.0/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.3.0/org-management/permissions.md b/docs/versioned_docs/version-2.3.0/org-management/permissions.md
index 5e33f5cb2c..b13433e0ef 100644
--- a/docs/versioned_docs/version-2.3.0/org-management/permissions.md
+++ b/docs/versioned_docs/version-2.3.0/org-management/permissions.md
@@ -8,7 +8,7 @@ Permissions allow you to create and share resources to easily ensure what level
Admins can invite **Users** to their workspaces and assign them to the **Groups** that have Permissions to access Apps, folders, or workspace variables.
:::info
-See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn how to invite users to ToolJet.
+See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to know more about managing users and groups on your workspace.
:::
## Role-Based Access Control (RBAC) Glossary
@@ -18,4 +18,4 @@ See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn h
- **All Users** - Contains all the users in your workspace. When **New Users** are invited they are added to this group by default.
- **Admins** - Contains all Admins in your workspace. Everyone added to this group will Permission to access all the ToolJet resources.
- **Apps, Folder, Workspace Variables -** Resources that Admins can set permissions on.
-- **Permissions -** Create, Update and Delete.
+- **Permissions -** Create, Update and Delete.
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.3.0/tutorial/manage-users-groups.md b/docs/versioned_docs/version-2.3.0/tutorial/manage-users-groups.md
index 95991fd7fa..5877d2f075 100644
--- a/docs/versioned_docs/version-2.3.0/tutorial/manage-users-groups.md
+++ b/docs/versioned_docs/version-2.3.0/tutorial/manage-users-groups.md
@@ -77,7 +77,7 @@ Similar to archiving a user's access, you can enable it again by clicking on **U
## Managing Groups
-On ToolJet, Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
+On ToolJet, Admins and Super Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
@@ -87,11 +87,16 @@ On ToolJet, Admins can create groups for users added in a workspace and grant th
### Group properties
-Every group on ToolJet has three sections:
+Every group on ToolJet has **four** sections:
+
+- [Apps](#apps)
+- [Users](#users)
+- [Permissions](#permissions)
+- [Datasources](#datasources)
#### Apps:
-Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
+Admins and Super Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
@@ -101,7 +106,7 @@ Admins can add or remove any number of apps for a group of users. To add an app
#### Users:
-Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
+Admins and Super Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
@@ -111,16 +116,30 @@ Admins can add or remove any numbers of users in a group. Just select a user fro
#### Permissions:
-Admins can set granular permission like creating/deleting apps or creating folder for a group of users.
+Admins and Super Admins can set granular permission for the users added in that particular group, such as:
+- **Create** and **Delete** Apps
+- **Create**, **Update**, and **Delete** Folders
+- **Create**, **Update**, and **Delete** [Workspace Variables](/docs/tutorial/workspace-variables)
+- **Create** and **Delete** [Global Datasources](/docs/data-sources/overview)
-
+
+
+
+
+#### Datasources:
+
+Only Admins and Super Admins can define what datasources can be **viewed** or **edited** by the users of that group.
+
+
+
+
:::tip
-All the activities performed by any Admin or any user in a workspace is logged in `Audit logs` - including any activity related with managing users and groups.
+All the activities performed by any Admin, Super Admin or any user in a workspace is logged in [Audit logs](/docs/Enterprise/audit_logs) - including any activity related with managing users and groups.
:::
### Predefined Groups
diff --git a/docs/versioned_docs/version-2.4.0/Enterprise/superadmin.md b/docs/versioned_docs/version-2.4.0/Enterprise/superadmin.md
index 63262b98e9..43332fd236 100644
--- a/docs/versioned_docs/version-2.4.0/Enterprise/superadmin.md
+++ b/docs/versioned_docs/version-2.4.0/Enterprise/superadmin.md
@@ -17,6 +17,7 @@ The user details entered while setting up ToolJet will have Super Admin privileg
| 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 Global datasources 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) | ❌ | ✅ |
diff --git a/docs/versioned_docs/version-2.4.0/contributing-guide/troubleshooting/eslint.md b/docs/versioned_docs/version-2.4.0/contributing-guide/troubleshooting/eslint.md
index 465ba553c3..efb8d897fe 100644
--- a/docs/versioned_docs/version-2.4.0/contributing-guide/troubleshooting/eslint.md
+++ b/docs/versioned_docs/version-2.4.0/contributing-guide/troubleshooting/eslint.md
@@ -41,3 +41,6 @@ For VSCode users, you can set the formatter to `ESLint` in the [**settings.json*
1. **Node version 18.3.0**
2. **npm version 8.11.0**
+:::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: {...}**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.4.0/data-sources/overview.md b/docs/versioned_docs/version-2.4.0/data-sources/overview.md
index ec7527f8af..64eefc507c 100644
--- a/docs/versioned_docs/version-2.4.0/data-sources/overview.md
+++ b/docs/versioned_docs/version-2.4.0/data-sources/overview.md
@@ -3,9 +3,13 @@ id: overview
title: Overview
---
-# Datasources : Overview
+# Global Datasources : Overview
-Datasources pull in and push data to any source including databases, external APIs, or services.
+Global datasources pull in and push data to any source including databases, external APIs, or services. Once a global datasource is connected to a workspace, the connection can be shared with any app of that workspace.
+
+:::caution
+Global datasources are available only on **ToolJet version 2.3.0 and above**.
+:::
@@ -13,30 +17,115 @@ Datasources pull in and push data to any source including databases, external AP
-## Connecting datasources
+## Connecting global datasources
-1. After logging in to ToolJet, create a new app from the dashboard
+1. From the ToolJet dashboard, go to the **global datasources page** from the left sidebar.
+
-2. There are two ways for connecting a datasource. You can connect from:
- 1. **Left-sidebar**: On the left sidebar, click on the `datasource` icon and then click on the `+ add datasource` button
+
-
+
-
+2. Click on the **Add new datasource** button, a modal will pop-up with all the available global datasources.
+
-
+
- 2. **Query Panel**: Go to the query panel at the bottom, click on the `+Add` button and then click `Add datasource` button
+
-
+3. Select the datasource, enter the **Credentials** and **Save** the datasource.
+
-
+
-
+
-3. Follow the steps in the **[Datasource Library](/docs/data-sources/airtable)** specific to the desired datasource
+4. Now, go back to the dashboard, create a new app, and the datasource will be available on the query panel under **Global Datasources**. Added datasources will be available on any of the **existing** or the **new applications**.
+
+
+
+
+
+
+5. You can now create queries of the connected global datasource. From the queries, you'll be able to switch to **different connections** of the same datasource if there are more than one connections created.
+
+
+
+
+
+
+## Changing scope of datasources of an app created on older versions of ToolJet
+
+On ToolJet versions below 2.3.0, the datasource connection was made from within the individual apps. To make it backward compatible, we added an option to change the scope of the datasources and make it global datasource.
+
+1. If you open an app created on previos versions of ToolJet, you'll find the datasource manager on the left sidebar of the App Builder.
+
+
+
+
+
+
+2. Click on the kebab menu next to the connected datasource, select the **change scope** option.
+
+
+
+
+
+
+3. Once you change the scope of the datasource and make it global, you'll see that the **datasource manager** is removed from the left sidebar and now you'll find the datasource on the **query panel** under Global Datasources. You can now configure the datasource fromt the Global Datasource page on the **dashboard**.
+
+
+
+
+
+
+
+## Default datasources
+
+By default, 4 datasources will be available on every app on ToolJet:
+- **[ToolJet Database](/docs/tooljet-database/)**
+- **[RestAPI](/docs/data-sources/restapi/)**
+- **[Run JavaScript Query](/docs/data-sources/run-js/)**
+- **[Run Python Query](/docs/data-sources/run-py/)**
+
+
+
+
+
+
+
+## Permissions
+
+Only **Admins** and **[Super Admins](/docs/Enterprise/superadmin)** of the workspace can change the **[Permissions](/docs/tutorial/manage-users-groups#group-properties)** for Global Datasource.
+
+From **Workspace Settings** -> **Groups Settings**, Admins and Super Admins can set the permission for a user group to:
+
+- **Create** and **Delete** datasources onto that workspace. If **Create** permission is enabled then the users can add new global datasources and **edit** the datasources as well but cannot **delete** it, and if only **Delete** permission is set then the users of the group will only be able to delete the connected datasources on the workspace.
+
+
+
+
+
+
+ - If any of the permission(Create or Delete) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
+
+- **View** or **Edit** allowed global datasources from the **Datasources** tab. If only **View** permission is set then the users of the group will only be able to connect to the allowed datasource, and if only **Edit** permission is set then the users of the group will be able to update the credentials of the allowed datasources.
+
+
+
+
+
+
+ - If any of the permission(View or Edit) is not enabled for a user group then the users of the group will get an error toast when they try to Add or Delete the global datasource.
+
+
+
+
+
-:::info
-ToolJet allows you to transform the data returned by datasources using **[Transformations](/docs/tutorial/transformations)**
-:::
diff --git a/docs/versioned_docs/version-2.4.0/getting-started.md b/docs/versioned_docs/version-2.4.0/getting-started.md
index 3d944f62c9..42699a3b53 100644
--- a/docs/versioned_docs/version-2.4.0/getting-started.md
+++ b/docs/versioned_docs/version-2.4.0/getting-started.md
@@ -143,7 +143,7 @@ Learn more about the **[ToolJet Database here](/docs/tooljet-database)**
:::info
-ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **Components Catalog** to learn more.
+ToolJet application's User interface is constructed using Components like Tables, Forms, Charts, or Buttons etc. Check **[Components Catalog](/docs/widgets/overview)** to learn more.
:::
### Build queries and bind data to UI
@@ -156,7 +156,7 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
- ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **Datasource Catalog** to learn more.
+ ToolJet can connect to several databases, APIs and external services to fetch and modify data. Check **[Datasource Catalog](/docs/data-sources/overview)** to learn more.
:::
2. Choose a **Table** from the dropdown, Select the **List rows** option from the **Operation** dropdown, You can leave other query parameters. Scroll down and enable **Run this query on application load** - this will trigger the query when the app is loaded.
@@ -199,8 +199,8 @@ ToolJet application's User interface is constructed using Components like Tables
:::info
-- You can manipulate the data returned by the queries using **Transformations**
-- You can also **Run JS query** or **Python query** to perform custom behavior inside ToolJet
+- You can manipulate the data returned by the queries using **[Transformations](/docs/tutorial/transformations)**
+- You can also **[Run JavaScript code](/docs/data-sources/run-js)** or **[Run Python code](/docs/data-sources/run-py)** to perform custom behavior inside ToolJet
:::
### Preview, Release and Share app
@@ -210,7 +210,7 @@ ToolJet application's User interface is constructed using Components like Tables
3. **Share** option allows you to share the **released version** of the application with other users or you can also make the app **public** and anyone with the URL will be able to use the app.
:::tip
-You can control how much access to users have to your ToolJet apps and resources using **Org Management**.
+You can control how much access to users have to your ToolJet apps and resources using **[Org Management](/docs/tutorial/manage-users-groups)**.
:::
## What Can I Do With ToolJet
diff --git a/docs/versioned_docs/version-2.4.0/how-to/intentionally-fail-js-query.md b/docs/versioned_docs/version-2.4.0/how-to/intentionally-fail-js-query.md
new file mode 100644
index 0000000000..bc7750ec4c
--- /dev/null
+++ b/docs/versioned_docs/version-2.4.0/how-to/intentionally-fail-js-query.md
@@ -0,0 +1,23 @@
+---
+id: intentionally-fail-js-query
+title: Intentionally fail a RunJS query
+---
+
+In this how-to guide, we will create a RunJS query that will throw an error.
+
+- Create a RunJS query and paste the code below. We will use the constructor `ReferenceError` since it is used to create a range error instance.
+ ```js
+ throw new ReferenceError('This is a reference error.');
+ ```
+
+- Now, add a event handler to show an alert when the query fails. **Save** the query and **Run** it.
+
+
+
+
+
+
+
+:::info
+Most common use-case for intentionally failing a query is **debugging**.
+:::
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.4.0/how-to/use-s3-presigned-url-to-upload-docs.md b/docs/versioned_docs/version-2.4.0/how-to/use-s3-presigned-url-to-upload-docs.md
new file mode 100644
index 0000000000..61dd6448d3
--- /dev/null
+++ b/docs/versioned_docs/version-2.4.0/how-to/use-s3-presigned-url-to-upload-docs.md
@@ -0,0 +1,173 @@
+---
+id: use-s3-signed-url-to-upload-docs
+title: Use S3 signed URL to upload documents
+---
+
+# Use S3 signed URL to upload documents
+
+In this how-to guide, you'll learn to upload documents to S3 buckets using the **S3 signed URL** from a ToolJet application.
+
+For this guide, We are going to use one of the existing templates on ToolJet: **S3 File explorer**
+
+:::info using Templates
+On ToolJet Dashboard, Click on the down arrow on the right of the **New App** button, from the dropdown choose the **Choose from template** option.
+:::
+
+
+
+
+
+
+
+- Once you've created a new app using the template, you'll be prompted to create a **new version** of the existing version. After creating a new version, you'll be able to make changes in the app.
+
+
+
+
+
+
+
+- Go to the **datasource manager** on the left-sidebar, you'll find that the **AWS S3 datasource** is already added. All you need to do is update the datasource **credentials**.
+
+ :::tip
+ Check the [AWS S3 datasource reference](/docs/data-sources/s3) to learn more about connnection and choosing your preferred authentication method.
+ :::
+
+
+
+
+
+
+
+- Once the datasource is connected successfully, go to the query manager and **Run** the **getBuckets** query. The operation selected in the getBuckets query is **List Buckets** which will fetch an array of all the buckets.
+
+
+
+
+
+
+
+- Running the **getBuckets** query will load all the buckets in the dropdown in the app.
+
+
+
+
+
+
+
+- Select a **bucket** from the dropdown and click on the **Fetch files** button to list all the files from the selected bucket on the table. The **Fetch files** button has the event handler added that triggers the **s32** query, the **s32** query uses the **List objects in a bucket** operation, and the bucket field in the query gets the value dynamically from the dropdown.
+
+
+
+
+
+
+
+- Let's go to the **uploadToS3** query and update the field values:
+ - **Operation**: Signed URL for upload
+ - **Bucket**: `{{components.dropdown1.value}}` this will fetch the dynamic value from the dropdown
+ - **Key**: `{{components.filepicker1.file[0].name}}` this will get the file name from the filepickers exposed variables
+ - **Expires in:** This sets an expiration time of URL, by default its `3600` seconds (1 hour)
+ - **Content Type**: `{{components.filepicker1.file[0].type}}` this will get the file type from the filepickers exposed variables
+
+
+
+
+
+
+
+- Create two **RunJS** queries:
+ - Create a **runjs1** query and copy-paste the code below. This query gets the **base64data** from the file picker and convert the file's `base64Data` to into `BLOB`, and returns the file object.
+ ```js
+ const base64String = components.filepicker1.file[0].base64Data
+ const decodedArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
+ const file = new Blob([decodedArray], { type: components.filepicker1.file[0].type });
+ const fileName = components.filepicker1.file[0].name;
+ const fileObj = new File([file], fileName);
+
+ return fileObj
+ ```
+
+
+
+
+
+
+
+ - Create another **runjs2** query and copy-paste the code below. This query gets the data(file object) returned by the first runjs query, the url returned by the **uploadToS3** query, and then makes PUT request.
+ ```js
+ const file = queries.runjs2.data
+ const url = queries.s31.data.url
+
+ fetch(url, {
+ method: 'PUT',
+ body: file,
+ mode: 'cors',
+ headers: {
+ 'Access-Control-Allow-Origin': '*',
+ 'Content-Type': 'application/json'
+ }
+ })
+ .then(response => console.log('Upload successful!'))
+ .catch(error => console.error('Error uploading file:', error));
+ ```
+ :::warning Enable Cross Origin Resource Sharing(CORS)
+ - For the file to be uploaded successfully, you will need to add the CORS policies from the **Permissions** tab of your **Bucket** settings. Here's a sample CORS:
+ ```json
+ [
+ {
+ "AllowedHeaders": [
+ "*"
+ ],
+ "AllowedMethods": [
+ "GET",
+ "PUT",
+ "POST"
+ ],
+ "AllowedOrigins": [
+ "*"
+ ],
+ "ExposeHeaders": []
+ }
+ ]
+ ```
+ :::
+
+
+
+
+
+
+
+- Go to the **uploadToS3**, scroll down and add an event handler to the **uploadToS3** query. Select the **Query Success** event, **Run Query** as the action, and **runjs1** as the query to be triggered. **Save** the query.
+
+
+
+
+
+
+- Let's go to the **runjs1** query and add the event handler to run a query on query success event, similar to how we did in the previous step. In the event handler, choose **runjs2** query. **Save** the query.
+
+
+
+
+
+
+- Now, let's go the final query **copySignedURL** that is connected to the table's action button. This query copy's the generated **Signed URL for download** onto the **clipboard**.
+
+
+
+
+
+
+- Now that we have updated all the queries, and connected them through the event handlers. We can go ahead and pick a file from the file picker. Click on the file picker, select a file and then hit the **Upload file to S3** button.
+
+
+
+
+
+
+- Once the button is clicked, the **uploadToS3** will triggered along with the **runjs1** and **runjs2** queries in sequence since we added them in the event handlers.
+
+- You can go to the table and click on the **Copy signed URL** action button on the table, this will trigger the **copySignedURL** query and will copy the URL on the clipboard. You can go to another tab and paste the URL to open the file on the browser.
+
diff --git a/docs/versioned_docs/version-2.4.0/org-management/permissions.md b/docs/versioned_docs/version-2.4.0/org-management/permissions.md
index 5e33f5cb2c..b13433e0ef 100644
--- a/docs/versioned_docs/version-2.4.0/org-management/permissions.md
+++ b/docs/versioned_docs/version-2.4.0/org-management/permissions.md
@@ -8,7 +8,7 @@ Permissions allow you to create and share resources to easily ensure what level
Admins can invite **Users** to their workspaces and assign them to the **Groups** that have Permissions to access Apps, folders, or workspace variables.
:::info
-See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn how to invite users to ToolJet.
+See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to know more about managing users and groups on your workspace.
:::
## Role-Based Access Control (RBAC) Glossary
@@ -18,4 +18,4 @@ See **[Manage Users and Groups](/docs/tutorial/manage-users-groups)** to learn h
- **All Users** - Contains all the users in your workspace. When **New Users** are invited they are added to this group by default.
- **Admins** - Contains all Admins in your workspace. Everyone added to this group will Permission to access all the ToolJet resources.
- **Apps, Folder, Workspace Variables -** Resources that Admins can set permissions on.
-- **Permissions -** Create, Update and Delete.
+- **Permissions -** Create, Update and Delete.
\ No newline at end of file
diff --git a/docs/versioned_docs/version-2.4.0/tutorial/manage-users-groups.md b/docs/versioned_docs/version-2.4.0/tutorial/manage-users-groups.md
index 95991fd7fa..5877d2f075 100644
--- a/docs/versioned_docs/version-2.4.0/tutorial/manage-users-groups.md
+++ b/docs/versioned_docs/version-2.4.0/tutorial/manage-users-groups.md
@@ -77,7 +77,7 @@ Similar to archiving a user's access, you can enable it again by clicking on **U
## Managing Groups
-On ToolJet, Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
+On ToolJet, Admins and Super Admins can create groups for users added in a workspace and grant them access to particular app(s) with specific permissions. To manage groups, just go to the **Workspace Settings** from the left-sidebar of the dashboard and click on the **Groups**.
@@ -87,11 +87,16 @@ On ToolJet, Admins can create groups for users added in a workspace and grant th
### Group properties
-Every group on ToolJet has three sections:
+Every group on ToolJet has **four** sections:
+
+- [Apps](#apps)
+- [Users](#users)
+- [Permissions](#permissions)
+- [Datasources](#datasources)
#### Apps:
-Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
+Admins and Super Admins can add or remove any number of apps for a group of users. To add an app to a group, select an app from the dropdown and click on `Add` button next to it. You can also set app permissions such as `View` or `Edit` for the group. You can set different permissions for different apps in a group.
@@ -101,7 +106,7 @@ Admins can add or remove any number of apps for a group of users. To add an app
#### Users:
-Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
+Admins and Super Admins can add or remove any numbers of users in a group. Just select a user from the dropdown and click on `Add` button to add it to a group. To delete a user from a group, click on `Delete` button next to it.
@@ -111,16 +116,30 @@ Admins can add or remove any numbers of users in a group. Just select a user fro
#### Permissions:
-Admins can set granular permission like creating/deleting apps or creating folder for a group of users.
+Admins and Super Admins can set granular permission for the users added in that particular group, such as:
+- **Create** and **Delete** Apps
+- **Create**, **Update**, and **Delete** Folders
+- **Create**, **Update**, and **Delete** [Workspace Variables](/docs/tutorial/workspace-variables)
+- **Create** and **Delete** [Global Datasources](/docs/data-sources/overview)
-
+
+
+
+
+#### Datasources:
+
+Only Admins and Super Admins can define what datasources can be **viewed** or **edited** by the users of that group.
+
+