diff --git a/.env.example b/.env.example
index 91c1b675db..ef48c3bc9d 100644
--- a/.env.example
+++ b/.env.example
@@ -56,3 +56,5 @@ APPSMITH_MAIL_SMTP_TLS_ENABLED=
#APPSMITH_SENTRY_DSN=
#APPSMITH_SENTRY_ENVIRONMENT=
+# Configure cloud services
+# APPSMITH_CLOUD_SERVICES_BASE_URL
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/---epic.md b/.github/ISSUE_TEMPLATE/---epic.md
index ec8e553d62..2a132b4026 100644
--- a/.github/ISSUE_TEMPLATE/---epic.md
+++ b/.github/ISSUE_TEMPLATE/---epic.md
@@ -6,24 +6,43 @@ labels: Epic, Product Note
assignees: Nikhil-Nandagopal
---
-## Problem statement
-
-Why is this needed?
-What does it hope to achieve?
+# Objective
+Here you fill in the objective of the feature/product that you are writing about.
## Related issues
-
[ ] #issue1
-## Success criteria
+# Success Metrics
+List of all metrics you are tracking and the desired goal.
+| Goal | Metric |
+| ------------- | ------------- |
+| e.g. Simplify user experience | Customer satisfaction score increases |
+| e.g. Simplify onboarding flow | Decrease churn rate down to 30% |
-How will we know the project succeeded?
+# Assumptions
+List any assumptions that you have about your users, technical constraints, or business goals (e.g., Most users will access this feature from tablet).
-## User story
+- Assumption 1
+- Assumption 2
+- Assumption 3
-How does a user use this feature? How does it relate to the problem?
+# Requirements
+| Requirement | User Story | Importance | Notes |
+| ------------- | ------------- | ------------- | ------------- |
+| e.g. Must be mobile responsive | e.g. as a user, I want to be able to access the platform via mobile phone | High, Low or Medium | Content Cell |
+| e.g. The user should be able to leave a comment | e.g as a user, I want to be able to communicate with the other members on the canvas | High, Low or Medium | Content Cell |
-## Details
+# Out of Scope
+List the things that are out of cope or might be revisited after the first release.
+- Item 1
+- Item 2
+- Item 3
-What are the specifications of the implementation?
-Product notes, designs etc.
+# Developer Handoff Document in Figma
+Link to the developer Handoff Document:
+
+# Questions
+| Question | Answer | Date Answered |
+| ------------- | ------------- | ------------- |
+| e.g. How might we ensure that the comments section doesn't cover the canvas | Content Cell | Content Cell |
+| Content Cell | Content Cell | Content Cell |
diff --git a/.github/config.json b/.github/config.json
index c16f3b48f2..48b03bac49 100644
--- a/.github/config.json
+++ b/.github/config.json
@@ -185,6 +185,11 @@
"color": "79e53b",
"description": "An unexpected or annoying bug"
},
+ "List Widget": {
+ "name": "List Widget",
+ "color": "79e53b",
+ "description": "Issues Related to the list widget"
+ },
"Map Widget": {
"name": "Map Widget",
"color": "7eef7a",
@@ -564,6 +569,11 @@
"type": "hasLabel",
"value": true
},
+ {
+ "label": "List Widget",
+ "type": "hasLabel",
+ "value": true
+ },
{
"label": "Map Widget",
"type": "hasLabel",
diff --git a/.github/workflows/client-build.yml b/.github/workflows/client-build.yml
index b9c79b1e5c..396b2be215 100644
--- a/.github/workflows/client-build.yml
+++ b/.github/workflows/client-build.yml
@@ -99,7 +99,7 @@ jobs:
- name: Run the jest tests
if: github.event_name == 'pull_request'
- uses: hetunandu/Jest-Coverage-Diff@fix/new-delete-file
+ uses: hetunandu/Jest-Coverage-Diff@feature/better-report-comments
with:
fullCoverageDiff: false
runCommand: cd app/client && REACT_APP_ENVIRONMENT=${{steps.vars.outputs.REACT_APP_ENVIRONMENT}} yarn run test:unit
diff --git a/.github/workflows/external-client-test.yml b/.github/workflows/external-client-test.yml
index 2b41a166fa..f83389788e 100644
--- a/.github/workflows/external-client-test.yml
+++ b/.github/workflows/external-client-test.yml
@@ -38,7 +38,7 @@ jobs:
- name: Set up JDK 1.11
uses: actions/setup-java@v1
with:
- java-version: 1.11
+ java-version: "11.0.10"
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
- name: Cache maven dependencies
diff --git a/.github/workflows/server.yml b/.github/workflows/server.yml
index d5a79b2dd9..3ac0df6d93 100644
--- a/.github/workflows/server.yml
+++ b/.github/workflows/server.yml
@@ -50,7 +50,7 @@ jobs:
- name: Set up JDK 1.11
uses: actions/setup-java@v1
with:
- java-version: 1.11
+ java-version: "11.0.10"
# Retrieve maven dependencies from cache. After a successful run, these dependencies are cached again
- name: Cache maven dependencies
diff --git a/.gitignore b/.gitignore
index e7782c5131..2d1d9bda93 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
.idea
*.iml
.env
+.vscode/*
# test coverage
-coverage-summary.json
\ No newline at end of file
+coverage-summary.json
diff --git a/README.md b/README.md
index 7488dc2567..2f0080c996 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
- Try Online Sandbox
+ Try Online Sandbox
Documentation
@@ -63,7 +63,7 @@ But if you’d rather check out some real applications that can be built with Ap
The following steps introduce you to building a simple user-list dashboard on Appsmith.
-1. [Sign up on Appsmith Cloud](https://bit.ly/appsmith-signup-github) or [Deploy Appsmith](https://docs.appsmith.com/setup).
+1. [Sign up on Appsmith Cloud](https://app.appsmith.com/signup?utm_source=github&utm_medium=social&utm_content=website&utm_campaign=null&utm_term=website) or [Deploy Appsmith](https://docs.appsmith.com/setup).
2. Create a new app within the organization that has already been created for you.
3. Click on the `+` icon next to the `Queries` section to add a new query in the mock database
1. Name the query `usersQuery`.
@@ -79,12 +79,12 @@ Connect your own data to build apps for your team. [Read more here.](https://doc
## 📚 Tutorials
1. [Building an Admin Panel on MongoDB using Appsmith](https://blog.appsmith.com/building-an-admin-panel-with-mongodb-using-appsmith) ([Video](https://www.youtube.com/watch?v=tisUaIgI86k))
-2. [Building a customer support dashboard in Appsmith](https://www.youtube.com/watch?v=-O_6OLREEzo&t=272s)
-3. [Running CI/CD jobs manually using Appsmith](https://blog.appsmith.com/how-to-run-manual-jobs-in-gitlab-cicd) ([Video](https://www.youtube.com/watch?v=CYdeJcD4I8A))
-4. [Building a calendly clone in Appsmith](https://blog.appsmith.com/how-to-build-a-calendly-clone-in-30-minutes)
-5. [Building Internal Tools with Appsmith](https://youtu.be/eYYYfuW-kEE) `Community`
-6. [Building an Issue Tracker with Appsmith](https://dev.to/pjmantoss/how-to-build-an-issue-tracker-with-appsmith-204e) `Community`
-
+2. [Building a Customer Support Dashboard in Appsmith](https://www.youtube.com/watch?v=-O_6OLREEzo&t=272s)
+3. [Building a Store Catalogue Management System using Appsmith and GraphQL](https://blog.appsmith.com/building-a-store-catalogue-management-system-using-appsmith-and-graphql)
+4. [Running CI/CD Jobs Manually using Appsmith](https://blog.appsmith.com/how-to-run-manual-jobs-in-gitlab-cicd) ([Video](https://www.youtube.com/watch?v=CYdeJcD4I8A))
+5. [Building a Calendly Clone in Appsmith](https://blog.appsmith.com/how-to-build-a-calendly-clone-in-30-minutes)
+6. [Building Internal Tools with Appsmith](https://youtu.be/eYYYfuW-kEE) `Community`
+7. [Building an Issue Tracker with Appsmith](https://dev.to/pjmantoss/how-to-build-an-issue-tracker-with-appsmith-204e) `Community`
## 📕 Support & Troubleshooting
diff --git a/app/client/.eslintrc.json b/app/client/.eslintrc.json
index 0e6d1239e1..fe0ab77466 100644
--- a/app/client/.eslintrc.json
+++ b/app/client/.eslintrc.json
@@ -28,7 +28,13 @@
"react/prop-types": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"cypress/no-unnecessary-waiting": 0,
- "cypress/no-assigning-return-values": 0
+ "cypress/no-assigning-return-values": 0,
+ "react/function-component-definition": "warn",
+ "react/jsx-boolean-value": "error",
+ "react/self-closing-comp": "error",
+ "react/jsx-sort-props": "error",
+ "react/jsx-fragments": "error",
+ "react/jsx-no-useless-fragment": "error"
},
"settings": {
"react": {
diff --git a/app/client/.gitignore b/app/client/.gitignore
index c5e430d2db..f801f7de68 100755
--- a/app/client/.gitignore
+++ b/app/client/.gitignore
@@ -43,3 +43,5 @@ storybook-static/*
build-storybook.log
.eslintcache
+.vscode
+TODO
\ No newline at end of file
diff --git a/app/client/README.md b/app/client/README.md
index 0ae785bd51..2a275ea504 100755
--- a/app/client/README.md
+++ b/app/client/README.md
@@ -7,4 +7,3 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
For details on setting up your development machine, please refer to the [Setup Guide](https://github.com/appsmithorg/appsmith/blob/release/contributions/ClientSetup.md)
-
diff --git a/app/client/cypress/.eslintrc.json b/app/client/cypress/.eslintrc.json
index cb810a1722..2772e19d62 100644
--- a/app/client/cypress/.eslintrc.json
+++ b/app/client/cypress/.eslintrc.json
@@ -2,6 +2,9 @@
"env": {
"cypress/globals": true
},
+ "rules": {
+ "cypress/no-unnecessary-waiting": 0
+ },
"extends": [
"plugin:cypress/recommended"
]
diff --git a/app/client/cypress/fixtures/ChartTextDsl.json b/app/client/cypress/fixtures/ChartTextDsl.json
index 12a7f6880d..ccaf55ba21 100644
--- a/app/client/cypress/fixtures/ChartTextDsl.json
+++ b/app/client/cypress/fixtures/ChartTextDsl.json
@@ -58,7 +58,9 @@
"chartType": "LINE_CHART",
"chartName": "Sales on working days",
"allowHorizontalScroll": false,
- "chartData": [{"seriesName":"Sales","data":""}],
+ "chartData": {
+ "some-random-id": {"seriesName":"Sales","data": []}
+ },
"xAxisName": "Last Week",
"yAxisName": "Total Order Revenue $",
"type": "CHART_WIDGET",
diff --git a/app/client/cypress/fixtures/example.json b/app/client/cypress/fixtures/example.json
index 3e446160e2..598a710a31 100644
--- a/app/client/cypress/fixtures/example.json
+++ b/app/client/cypress/fixtures/example.json
@@ -102,6 +102,7 @@
"AlertModalName": "Alert_Modal",
"FormModalName": "Form_Modal",
"TextLabelValue": "Test Text Label",
+ "TextLabelValueScrollable": "Test Text Label to check scroll feature",
"TextName": "TestTextBox",
"TextLabel": "Paragraph",
"TextBody": "Heading 2",
diff --git a/app/client/cypress/fixtures/executionParamsDsl.json b/app/client/cypress/fixtures/executionParamsDsl.json
index 32de9477c0..a98fadca24 100644
--- a/app/client/cypress/fixtures/executionParamsDsl.json
+++ b/app/client/cypress/fixtures/executionParamsDsl.json
@@ -114,7 +114,7 @@
"inputType": "TEXT",
"label": "Endpoint",
"widgetName": "EndpointInput",
- "defaultText": "todos",
+ "defaultText": "offers",
"type": "INPUT_WIDGET",
"isLoading": false,
"parentColumnSpace": 71.75,
diff --git a/app/client/cypress/fixtures/listdsl.json b/app/client/cypress/fixtures/listdsl.json
new file mode 100644
index 0000000000..25c0fb517a
--- /dev/null
+++ b/app/client/cypress/fixtures/listdsl.json
@@ -0,0 +1,161 @@
+{
+ "dsl": {
+ "widgetName": "MainContainer",
+ "backgroundColor": "none",
+ "rightColumn": 1224,
+ "snapColumns": 16,
+ "detachFromLayout": true,
+ "widgetId": "0",
+ "topRow": 0,
+ "bottomRow": 1280,
+ "containerStyle": "none",
+ "snapRows": 33,
+ "parentRowSpace": 1,
+ "type": "CANVAS_WIDGET",
+ "canExtend": true,
+ "version": 9,
+ "minHeight": 1292,
+ "parentColumnSpace": 1,
+ "dynamicBindingPathList": [],
+ "leftColumn": 0,
+ "children": [
+ {
+ "isVisible": true,
+ "enhancements": true,
+ "backgroundColor": "",
+ "gridType": "vertical",
+ "gridGap": 0,
+ "items": "[\n {\n \"id\": 1,\n \"email\": \"michael.lawson@reqres.in\",\n \"first_name\": \"Michael\",\n \"last_name\": \"Lawson\",\n \"avatar\": \"https://reqres.in/img/faces/7-image.jpg\"\n },\n {\n \"id\": 2,\n \"email\": \"lindsay.ferguson@reqres.in\",\n \"first_name\": \"Lindsay\",\n \"last_name\": \"Ferguson\",\n \"avatar\": \"https://reqres.in/img/faces/8-image.jpg\"\n },\n {\n \"id\": 3,\n \"email\": \"brock.lesnar@reqres.in\",\n \"first_name\": \"Brock\",\n \"last_name\": \"Lesnar\",\n \"avatar\": \"https://reqres.in/img/faces/8-image.jpg\"\n }\n]",
+ "widgetName": "List1",
+ "children": [
+ {
+ "isVisible": true,
+ "widgetName": "Canvas1",
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "dropDisabled": true,
+ "children": [
+ {
+ "isVisible": true,
+ "backgroundColor": "white",
+ "widgetName": "Container1",
+ "containerStyle": "card",
+ "children": [
+ {
+ "isVisible": true,
+ "widgetName": "Canvas2",
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "children": [
+ {
+ "isVisible": true,
+ "text": "Label",
+ "textStyle": "LABEL",
+ "textAlign": "LEFT",
+ "widgetName": "Text1",
+ "type": "TEXT_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 32,
+ "parentRowSpace": 40,
+ "leftColumn": 2,
+ "rightColumn": 6,
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentId": "dinv2tsatk",
+ "widgetId": "k6ct7dxg4w"
+ },
+ {
+ "isVisible":true,
+ "text":"Submit",
+ "buttonStyle":"PRIMARY_BUTTON",
+ "widgetName":"Button1",
+ "isDisabled":false,
+ "isDefaultClickDisabled":true,
+ "version":1,
+ "type":"BUTTON_WIDGET",
+ "isLoading":false,
+ "parentColumnSpace":29.25,
+ "parentRowSpace":40,
+ "leftColumn":6,
+ "rightColumn":8,
+ "topRow":1,
+ "bottomRow":2,
+ "parentId":"dinv2tsatk",
+ "widgetId":"fuw9p7cuek"
+ }
+ ],
+ "minHeight": null,
+ "type": "CANVAS_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "parentRowSpace": 1,
+ "leftColumn": 0,
+ "rightColumn": null,
+ "topRow": 0,
+ "bottomRow": null,
+ "parentId": "4ruj7xl5ri",
+ "widgetId": "dinv2tsatk"
+ }
+ ],
+ "dragDisabled": true,
+ "isDeletable": false,
+ "disablePropertyPane": true,
+ "type": "CONTAINER_WIDGET",
+ "isLoading": false,
+ "leftColumn": 0,
+ "rightColumn": 16,
+ "topRow": 0,
+ "bottomRow": 4,
+ "parentId": "0pvmmqr77m",
+ "widgetId": "4ruj7xl5ri"
+ }
+ ],
+ "minHeight": 400,
+ "type": "CANVAS_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "parentRowSpace": 1,
+ "leftColumn": 0,
+ "rightColumn": 592,
+ "topRow": 0,
+ "bottomRow": 400,
+ "parentId": "5bwz8xcvhj",
+ "widgetId": "0pvmmqr77m"
+ }
+ ],
+ "type": "LIST_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "parentRowSpace": 40,
+ "leftColumn": 0,
+ "rightColumn": 8,
+ "topRow": 0,
+ "bottomRow": 10,
+ "parentId": "0",
+ "widgetId": "5bwz8xcvhj",
+ "dynamicBindingPathList": [],
+ "template": {
+ "Text1": {
+ "isVisible": true,
+ "text": "Label",
+ "textStyle": "LABEL",
+ "textAlign": "LEFT",
+ "widgetName": "Text1",
+ "type": "TEXT_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 32,
+ "parentRowSpace": 40,
+ "leftColumn": 0,
+ "rightColumn": 4,
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentId": "dinv2tsatk",
+ "widgetId": "k6ct7dxg4w"
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/app/client/cypress/fixtures/testFile2.mov b/app/client/cypress/fixtures/testFile2.mov
new file mode 100644
index 0000000000..af5b36c705
Binary files /dev/null and b/app/client/cypress/fixtures/testFile2.mov differ
diff --git a/app/client/cypress/fixtures/textDsl.json b/app/client/cypress/fixtures/textDsl.json
new file mode 100644
index 0000000000..d9821d17da
--- /dev/null
+++ b/app/client/cypress/fixtures/textDsl.json
@@ -0,0 +1,45 @@
+{
+ "dsl": {
+ "widgetName": "MainContainer",
+ "backgroundColor": "none",
+ "rightColumn": 966,
+ "snapColumns": 16,
+ "detachFromLayout": true,
+ "widgetId": "0",
+ "topRow": 0,
+ "bottomRow": 240,
+ "containerStyle": "none",
+ "snapRows": 33,
+ "parentRowSpace": 1,
+ "type": "CANVAS_WIDGET",
+ "canExtend": true,
+ "version": 16,
+ "minHeight": 280,
+ "parentColumnSpace": 1,
+ "dynamicTriggerPathList": [],
+ "dynamicBindingPathList": [],
+ "leftColumn": 0,
+ "children": [
+ {
+ "isVisible": true,
+ "text": "Label",
+ "fontSize": "PARAGRAPH",
+ "fontStyle": "BOLD",
+ "textAlign": "LEFT",
+ "textColor": "#231F20",
+ "widgetName": "Text1",
+ "version": 1,
+ "type": "TEXT_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 57.875,
+ "parentRowSpace": 40,
+ "leftColumn": 4,
+ "rightColumn": 8,
+ "topRow": 1,
+ "bottomRow": 2,
+ "parentId": "0",
+ "widgetId": "266vj9u1mr"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ActionExecution/ExecutionParams_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ActionExecution/ExecutionParams_spec.js
index 32505c69b9..6e4a234a3b 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ActionExecution/ExecutionParams_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ActionExecution/ExecutionParams_spec.js
@@ -1,33 +1,56 @@
const dsl = require("../../../../fixtures/executionParamsDsl.json");
const publishPage = require("../../../../locators/publishWidgetspage.json");
const commonlocators = require("../../../../locators/commonlocators.json");
+const queryLocators = require("../../../../locators/QueryEditor.json");
+const datasource = require("../../../../locators/DatasourcesEditor.json");
describe("API Panel Test Functionality", function() {
+ let datasourceName;
before(() => {
cy.addDsl(dsl);
});
- it("Will pass execution params", function() {
- // Create the Api
- cy.NavigateToAPI_Panel();
- cy.CreateAPI("MultiApi");
- cy.enterDatasourceAndPath(
- "https://jsonplaceholder.typicode.com/",
- "{{this.params.endpoint || 'posts'}}",
- );
- cy.WaitAutoSave();
- // Run it
- cy.RunAPI();
+ beforeEach(() => {
+ cy.startRoutesForDatasource();
+ });
+ it("Create a postgres datasource", function() {
+ cy.NavigateToDatasourceEditor();
+ cy.get(datasource.PostgreSQL).click();
+ cy.getPluginFormsAndCreateDatasource();
+
+ cy.fillPostgresDatasourceForm();
+
+ cy.testSaveDatasource();
+
+ cy.get("@createDatasource").then((httpResponse) => {
+ datasourceName = httpResponse.response.body.data.name;
+ });
+ });
+ it("Create and runs query", () => {
+ cy.NavigateToQueryEditor();
+ cy.contains(".t--datasource-name", datasourceName)
+ .find(queryLocators.createQuery)
+ .click();
+
+ cy.get(queryLocators.templateMenu).click();
+ cy.get(".CodeMirror textarea")
+ .first()
+ .focus()
+ .type("select * from {{ this.params.tableName || 'users' }} limit 10", {
+ force: true,
+ parseSpecialCharSequences: false,
+ });
+ cy.WaitAutoSave();
+ cy.runQuery();
+ });
+ it("Will pass execution params", function() {
// Bind the table
cy.SearchEntityandOpen("Table1");
- cy.testJsontext("tabledata", "{{MultiApi.data", false);
+ cy.testJsontext("tabledata", "{{Query1.data}}");
// Assert 'posts' data (default)
- cy.readTabledataPublish("0", "2").then((cellData) => {
- expect(cellData).to.be.equal(
- "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
- );
+ cy.readTabledataPublish("0", "1").then((cellData) => {
+ expect(cellData).to.be.equal("Ximenez Kainz");
});
-
// Choose static button
cy.SearchEntityandOpen("StaticButton");
// toggle js of onClick
@@ -37,8 +60,7 @@ describe("API Panel Test Functionality", function() {
// Bind with MultiApi with static value
cy.testJsontext(
"onclick",
- "{{MultiApi.run(undefined, undefined, { endpoint: 'users",
- false,
+ "{{Query1.run(undefined, undefined, { tableName: 'orders' })}}",
);
cy.get(commonlocators.editPropCrossButton).click({ force: true });
@@ -51,8 +73,7 @@ describe("API Panel Test Functionality", function() {
// Bind with MultiApi with dynamicValue value
cy.testJsontext(
"onclick",
- "{{MultiApi.run(undefined, undefined, { endpoint: EndpointInput.text",
- false,
+ "{{Query1.run(undefined, undefined, { tableName: EndpointInput.text })}}",
);
// Publish the app
@@ -60,10 +81,8 @@ describe("API Panel Test Functionality", function() {
cy.wait("@postExecute");
// Assert on load data in table
- cy.readTabledataPublish("0", "2").then((cellData) => {
- expect(cellData).to.be.equal(
- "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
- );
+ cy.readTabledataPublish("0", "1").then((cellData) => {
+ expect(cellData).to.be.equal("Ximenez Kainz");
});
// Click Static button
@@ -74,7 +93,7 @@ describe("API Panel Test Functionality", function() {
cy.wait(2000);
// Assert statically bound "users" data
cy.readTabledataPublish("1", "1").then((cellData) => {
- expect(cellData).to.be.equal("Ervin Howell");
+ expect(cellData).to.be.equal("OUT_FOR_DELIVERY");
});
// Click dynamic button
@@ -84,8 +103,8 @@ describe("API Panel Test Functionality", function() {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000);
// Assert dynamically bound "todos" data
- cy.readTabledataPublish("0", "2").then((cellData) => {
- expect(cellData).to.be.equal("delectus aut autem");
+ cy.readTabledataPublish("0", "1").then((cellData) => {
+ expect(cellData).to.be.equal("DISCOUNT");
});
});
});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ApiPaneTests/API_all_sidebar_actions_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ApiPaneTests/API_all_sidebar_actions_spec.js
index b09e52daff..b718d908aa 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ApiPaneTests/API_all_sidebar_actions_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/ApiPaneTests/API_all_sidebar_actions_spec.js
@@ -15,6 +15,11 @@ describe("API Panel Test Functionality ", function() {
.click({ force: true });
cy.CopyAPIToHome();
cy.GlobalSearchEntity("FirstAPICopy");
+ // click on learn how link
+ cy.get(".t--learn-how-apis-link").click();
+ // this should open in a global search modal
+ cy.get(commonlocators.globalSearchModal);
+ cy.get("body").click(0, 0);
cy.DeleteAPIFromSideBar();
});
});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/BindApi_withPageload_Input_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/BindApi_withPageload_Input_spec.js
index f6057bc596..163331e028 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/BindApi_withPageload_Input_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Binding/BindApi_withPageload_Input_spec.js
@@ -1,9 +1,7 @@
const testdata = require("../../../../fixtures/testdata.json");
const apiwidget = require("../../../../locators/apiWidgetslocator.json");
const commonlocators = require("../../../../locators/commonlocators.json");
-const formWidgetsPage = require("../../../../locators/FormWidgets.json");
const dsl = require("../../../../fixtures/MultipleInput.json");
-const pages = require("../../../../locators/Pages.json");
const widgetsPage = require("../../../../locators/Widgets.json");
const publish = require("../../../../locators/publishWidgetspage.json");
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Debugger/Logs_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Debugger/Logs_spec.js
new file mode 100644
index 0000000000..e884caf535
--- /dev/null
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Debugger/Logs_spec.js
@@ -0,0 +1,14 @@
+const dsl = require("../../../../fixtures/buttondsl.json");
+
+describe("Debugger logs", function() {
+ before(() => {
+ cy.addDsl(dsl);
+ });
+ it("Modifying widget properties should log the same", function() {
+ cy.openPropertyPane("buttonwidget");
+ cy.testJsontext("label", "Test");
+
+ cy.get(".t--debugger").click();
+ cy.get(".t--debugger-log-state").contains("Test");
+ });
+});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Modal_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Modal_spec.js
index 9bb36c8c10..ba257c5ae2 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Modal_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Modal_spec.js
@@ -1,5 +1,4 @@
const dsl = require("../../../../fixtures/ModalDsl.json");
-const publishPage = require("../../../../locators/publishWidgetspage.json");
const explorer = require("../../../../locators/explorerlocators.json");
describe("Modal Widget Functionality", function() {
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_PropertyPane_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_PropertyPane_spec.js
index 8329b92cda..1f2035eeab 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_PropertyPane_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Table_PropertyPane_spec.js
@@ -10,21 +10,8 @@ describe("Table Widget property pane feature validation", function() {
cy.addDsl(dsl);
});
- it("Check collapse section feature in property pane", function() {
- cy.openPropertyPane("tablewidget");
- //check open and collapse
- cy.get(commonlocators.collapsesection)
- .first()
- .should("be.visible")
- .click();
- cy.assertControlVisibility("tabledata");
- });
-
it("Check open section and column data in property pane", function() {
- cy.get(commonlocators.collapsesection)
- .scrollIntoView()
- .first()
- .click();
+ cy.openPropertyPane("tablewidget");
cy.tableColumnDataValidation("id");
cy.tableColumnDataValidation("email");
cy.tableColumnDataValidation("userName");
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Text_new_feature_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Text_new_feature_spec.js
new file mode 100644
index 0000000000..a35162eca6
--- /dev/null
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/Text_new_feature_spec.js
@@ -0,0 +1,109 @@
+const commonlocators = require("../../../../locators/commonlocators.json");
+const widgetsPage = require("../../../../locators/Widgets.json");
+const publishPage = require("../../../../locators/publishWidgetspage.json");
+const dsl = require("../../../../fixtures/textDsl.json");
+const pages = require("../../../../locators/Pages.json");
+
+describe("Text Widget color/font/alignment Functionality", function() {
+ before(() => {
+ cy.addDsl(dsl);
+ });
+
+ beforeEach(() => {
+ cy.openPropertyPane("textwidget");
+ });
+
+ it("Text-TextStyle Heading, Text Name Validation", function() {
+ //changing the Text Name and verifying
+ cy.widgetText(
+ this.data.TextName,
+ widgetsPage.textWidget,
+ widgetsPage.textWidget + " " + commonlocators.widgetNameTag,
+ );
+
+ //Changing the text label
+ cy.testCodeMirror(this.data.TextLabelValueScrollable);
+
+ cy.ChangeTextStyle(
+ this.data.TextHeading,
+ commonlocators.headingTextStyle,
+ this.data.TextLabelValueScrollable,
+ );
+ cy.wait("@updateLayout");
+ cy.PublishtheApp();
+ cy.get(commonlocators.headingTextStyle)
+ .should("have.text", this.data.TextLabelValueScrollable)
+ .should("have.css", "font-size", "24px");
+ cy.get(publishPage.backToEditor).click({ force: true });
+ });
+
+ it("Test to validate text format", function() {
+ //Changing the Text Style's and validating
+ cy.get(widgetsPage.italics).click({ force: true });
+ cy.readTextDataValidateCSS("font-style", "italic");
+ cy.get(widgetsPage.bold).click({ force: true });
+ cy.readTextDataValidateCSS("font-weight", "400");
+ cy.get(widgetsPage.bold).click({ force: true });
+ cy.readTextDataValidateCSS("font-weight", "700");
+ cy.get(widgetsPage.italics).click({ force: true });
+ cy.readTextDataValidateCSS("font-style", "normal");
+ cy.closePropertyPane();
+ });
+
+ it("Test to validate color changes in text and background", function() {
+ //Changing the Text Style's and validating
+ cy.get(widgetsPage.textColor)
+ .first()
+ .click({ force: true });
+ cy.xpath(widgetsPage.greenColor).click();
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(500);
+ cy.wait("@updateLayout");
+ cy.readTextDataValidateCSS("color", "rgb(3, 179, 101)");
+ cy.get(widgetsPage.textColor)
+ .clear({ force: true })
+ .type("purple", { force: true });
+ cy.wait("@updateLayout");
+ cy.readTextDataValidateCSS("color", "rgb(128, 0, 128)");
+ cy.get(widgetsPage.backgroundColor)
+ .first()
+ .click({ force: true });
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(500);
+ cy.xpath(widgetsPage.greenColor)
+ .first()
+ .click();
+ // eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(500);
+ cy.wait("@updateLayout");
+ cy.PublishtheApp();
+ cy.get(publishPage.backToEditor).click({ force: true });
+ });
+
+ it("Test to validate text alignment", function() {
+ cy.get(widgetsPage.centerAlign)
+ .first()
+ .click({ force: true });
+ cy.readTextDataValidateCSS("text-align", "center");
+ cy.get(widgetsPage.rightAlign)
+ .first()
+ .click({ force: true });
+ cy.readTextDataValidateCSS("text-align", "right");
+ cy.get(widgetsPage.leftAlign)
+ .first()
+ .click({ force: true });
+ cy.readTextDataValidateCSS("text-align", "left");
+ cy.closePropertyPane();
+ });
+
+ it("Test to validate enable scroll feature", function() {
+ cy.get(".t--property-control-enablescroll .bp3-switch").click({
+ force: true,
+ });
+ cy.wait("@updateLayout");
+ cy.get(commonlocators.headingTextStyle).trigger("mouseover", {
+ force: true,
+ });
+ cy.get(commonlocators.headingTextStyle).scrollIntoView({ duration: 2000 });
+ });
+});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/FilePicker_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/FilePicker_spec.js
index 1a71d138c1..3330821242 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/FilePicker_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/FilePicker_spec.js
@@ -43,6 +43,29 @@ describe("FilePicker Widget Functionality", function() {
cy.get("button").contains("1 files selected");
});
+ it("It checks the deletion of filepicker works as expected", function() {
+ cy.get(commonlocators.filePickerButton).click();
+ cy.get(commonlocators.filePickerInput)
+ .first()
+ .attachFile("testFile.mov");
+ cy.get(commonlocators.filePickerUploadButton).click();
+ //eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(500);
+ cy.get("button").contains("1 files selected");
+ cy.get(commonlocators.filePickerButton).click();
+ //eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(200);
+ cy.get("button.uppy-Dashboard-Item-action--remove").click();
+ cy.get("button.uppy-Dashboard-browse").click();
+ cy.get(commonlocators.filePickerInput)
+ .first()
+ .attachFile("testFile2.mov");
+ cy.get(commonlocators.filePickerUploadButton).click();
+ //eslint-disable-next-line cypress/no-unnecessary-waiting
+ cy.wait(500);
+ cy.get("button").contains("1 files selected");
+ });
+
afterEach(() => {
// put your clean up code if any
});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/GlobalSearch/GlobalSearch_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/GlobalSearch/GlobalSearch_spec.js
index 179a20bfce..3f60f9e819 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/GlobalSearch/GlobalSearch_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/GlobalSearch/GlobalSearch_spec.js
@@ -54,14 +54,12 @@ describe("GlobalSearch", function() {
cy.get(commonlocators.globalSearchTrigger).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
- cy.get(commonlocators.globalSearchClearInput).click({ force: true });
cy.get(commonlocators.globalSearchInput).type("Page1");
cy.get("body").type("{enter}");
cy.get(commonlocators.globalSearchTrigger).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
- cy.get(commonlocators.globalSearchClearInput).click({ force: true });
cy.get(commonlocators.globalSearchInput).type("SomeApi");
cy.get("body").type("{enter}");
cy.window()
@@ -90,14 +88,12 @@ describe("GlobalSearch", function() {
cy.get(commonlocators.globalSearchTrigger).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // modal open transition should be deterministic
- cy.get(commonlocators.globalSearchClearInput).click({ force: true });
cy.get(commonlocators.globalSearchInput).type("Page1");
cy.get("body").type("{enter}");
cy.get(commonlocators.globalSearchTrigger).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); // modal open transition should be deterministic
- cy.get(commonlocators.globalSearchClearInput).click({ force: true });
cy.get(commonlocators.globalSearchInput).type(expectedDatasource.name);
cy.get("body").type("{enter}");
cy.location().should((loc) => {
@@ -111,7 +107,6 @@ describe("GlobalSearch", function() {
cy.get(commonlocators.globalSearchTrigger).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
- cy.get(commonlocators.globalSearchClearInput).click({ force: true });
cy.get(commonlocators.globalSearchInput).type("Page1");
cy.get("body").type("{enter}");
cy.window()
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/LayoutWidgets/Container_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/LayoutWidgets/Container_spec.js
index 1729993c2d..883257100f 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/LayoutWidgets/Container_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/LayoutWidgets/Container_spec.js
@@ -22,10 +22,13 @@ describe("Container Widget Functionality", function() {
/**
* @param{Text} Random Colour
*/
- cy.testCodeMirror(this.data.colour);
+ cy.get(widgetsPage.backgroundcolorPicker)
+ .first()
+ .click({ force: true });
+ cy.xpath(widgetsPage.greenColor).click();
cy.get(widgetsPage.containerD)
.should("have.css", "background-color")
- .and("eq", this.data.rgbValue);
+ .and("eq", "rgb(3, 179, 101)");
/**
* @param{toggleButton Css} Assert to be checked
*/
@@ -41,7 +44,7 @@ describe("Container Widget Functionality", function() {
cy.get(widgetsPage.containerD)
.eq(0)
.should("have.css", "background-color")
- .and("eq", this.data.rgbValue);
+ .and("eq", "rgb(3, 179, 101)");
});
afterEach(() => {
// put your clean up code if any
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/QueryPaneTests/Datasourcedocs_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/QueryPaneTests/Datasourcedocs_spec.js
new file mode 100644
index 0000000000..85badafaa2
--- /dev/null
+++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/QueryPaneTests/Datasourcedocs_spec.js
@@ -0,0 +1,56 @@
+const datasource = require("../../../../locators/DatasourcesEditor.json");
+const queryLocators = require("../../../../locators/QueryEditor.json");
+const commonlocators = require("../../../../locators/commonlocators.json");
+
+describe("Check datasource doc links", function() {
+ let postgresDatasourceName;
+
+ beforeEach(() => {
+ cy.startRoutesForDatasource();
+ });
+
+ it("Create postgres datasource", function() {
+ cy.NavigateToDatasourceEditor();
+ cy.get(datasource.PostgreSQL).click();
+ cy.generateUUID().then((uid) => {
+ postgresDatasourceName = uid;
+
+ cy.get(".t--edit-datasource-name").click();
+ cy.get(".t--edit-datasource-name input")
+ .clear()
+ .type(postgresDatasourceName, { force: true })
+ .should("have.value", postgresDatasourceName)
+ .blur();
+ });
+ cy.wait("@saveDatasource").should(
+ "have.nested.property",
+ "response.body.responseMeta.status",
+ 200,
+ );
+ cy.fillPostgresDatasourceForm();
+ cy.testSaveDatasource();
+ });
+
+ it("Check that documentation opens global modal", function() {
+ cy.NavigateToQueryEditor();
+
+ cy.contains(".t--datasource-name", postgresDatasourceName)
+ .find(queryLocators.createQuery)
+ .click();
+
+ cy.get(".t--datasource-documentation-link").click();
+ cy.get(commonlocators.globalSearchModal);
+ cy.get("body").click(0, 0);
+ });
+
+ it("Delete the query and datasources", function() {
+ cy.get(queryLocators.deleteQuery).click();
+ cy.wait("@deleteAction").should(
+ "have.nested.property",
+ "response.body.responseMeta.status",
+ 200,
+ );
+
+ cy.deleteDatasource(postgresDatasourceName);
+ });
+});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/LayoutWidgets/List_spec.js b/app/client/cypress/integration/Smoke_TestSuite/LayoutWidgets/List_spec.js
new file mode 100644
index 0000000000..8221072b87
--- /dev/null
+++ b/app/client/cypress/integration/Smoke_TestSuite/LayoutWidgets/List_spec.js
@@ -0,0 +1,89 @@
+const commonlocators = require("../../../locators/commonlocators.json");
+const widgetsPage = require("../../../locators/Widgets.json");
+const dsl = require("../../../fixtures/listdsl.json");
+const publishPage = require("../../../locators/publishWidgetspage.json");
+
+describe("Container Widget Functionality", function() {
+ const items = JSON.parse(dsl.dsl.children[0].items);
+
+ before(() => {
+ cy.addDsl(dsl);
+ });
+
+ it("checks if list shows correct no. of items", function() {
+ cy.get(commonlocators.containerWidget).then(function($lis) {
+ expect($lis).to.have.length(2);
+ });
+ });
+
+ it("checks currentItem binding", function() {
+ cy.SearchEntityandOpen("Text1");
+ cy.getCodeMirror().then(($cm) => {
+ cy.get(".CodeMirror textarea")
+ .first()
+ .type(`{{currentItem.first_name}}`, {
+ force: true,
+ parseSpecialCharSequences: false,
+ });
+ });
+
+ cy.wait(1000);
+
+ cy.closePropertyPane();
+
+ cy.get(commonlocators.TextInside).then(function($lis) {
+ expect($lis.eq(0)).to.contain(items[0].first_name);
+ expect($lis.eq(1)).to.contain(items[1].first_name);
+ });
+ });
+
+ it("checks button action", function() {
+ cy.SearchEntityandOpen("Button1");
+ cy.getCodeMirror().then(($cm) => {
+ cy.get(".CodeMirror textarea")
+ .first()
+ .type(`{{currentItem.first_name}}`, {
+ force: true,
+ parseSpecialCharSequences: false,
+ });
+ });
+ cy.addAction("{{currentItem.first_name}}");
+
+ cy.PublishtheApp();
+
+ cy.get(`${widgetsPage.widgetBtn}`)
+ .first()
+ .click();
+
+ cy.get(commonlocators.toastmsg).contains(items[0].first_name);
+ });
+
+ it("it checks onListItem click action", function() {
+ cy.get(publishPage.backToEditor).click({ force: true });
+
+ cy.SearchEntityandOpen("List1");
+ cy.addAction("{{currentItem.first_name}}");
+
+ cy.PublishtheApp();
+
+ cy.get(
+ "div[type='LIST_WIDGET'] .t--widget-containerwidget:first-child",
+ ).click();
+
+ cy.get(commonlocators.toastmsg).contains(items[0].first_name);
+ });
+
+ it("it checks pagination", function() {
+ // clicking on second pagination button
+ cy.get(`${commonlocators.paginationButton}-2`).click();
+
+ // now we are on the second page which shows first the 3rd item in the list
+ cy.get(commonlocators.TextInside).then(function($lis) {
+ expect($lis.eq(0)).to.contain(items[2].first_name);
+ });
+ });
+
+ afterEach(() => {
+ // put your clean up code if any
+ });
+});
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/ApiPaneTests/API_All_Verb_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/ApiPaneTests/API_All_Verb_spec.js
index 84030d93bb..5411c7745f 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/ApiPaneTests/API_All_Verb_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/ApiPaneTests/API_All_Verb_spec.js
@@ -184,7 +184,7 @@ describe("API Panel Test Functionality", function() {
);
cy.WaitAutoSave();
cy.RunAPI();
- cy.validateRequest(testdata.baseUrl, testdata.methods, testdata.Get);
+ cy.validateRequest(testdata.baseUrl, testdata.methods, testdata.Get, true);
cy.ResponseStatusCheck("5000");
cy.log("Response code check successful");
cy.ResponseCheck("Invalid value for Content-Type");
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/AddWidget_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/AddWidget_spec.js
index 539900d5dc..281400a1ff 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/AddWidget_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/AddWidget_spec.js
@@ -24,7 +24,7 @@ describe("Add widget", function() {
.focus()
.type("select * from configs");
// eslint-disable-next-line cypress/no-unnecessary-waiting
- cy.wait(500);
+ cy.WaitAutoSave();
cy.get(queryEditor.runQuery).click();
cy.wait("@postExecute").should(
"have.nested.property",
diff --git a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/EmptyDataSource_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/EmptyDataSource_spec.js
index cf8ceae494..b4ce6a9abd 100644
--- a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/EmptyDataSource_spec.js
+++ b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/EmptyDataSource_spec.js
@@ -31,10 +31,8 @@ describe("Create a query with a empty datasource, run, save the query", function
cy.EvaluateCurrentValue("select * from users limit 10");
cy.runQuery();
- cy.get(".react-tabs p")
- .last()
- .contains(
- "[Missing endpoint., Missing username for authentication., Missing password for authentication.]",
- );
+ cy.get(".t--query-error").contains(
+ "[Missing endpoint., Missing username for authentication., Missing password for authentication.]",
+ );
});
});
diff --git a/app/client/cypress/locators/Widgets.json b/app/client/cypress/locators/Widgets.json
index fda4bfc2c6..3e67eecebb 100644
--- a/app/client/cypress/locators/Widgets.json
+++ b/app/client/cypress/locators/Widgets.json
@@ -65,6 +65,7 @@
"verticalCenter": ".t--icon-tab-CENTER",
"verticalBottom": ".t--icon-tab-BOTTOM",
"textColor": ".t--property-control-textcolor input",
+ "backgroundcolorPicker": ".t--property-control-backgroundcolor input",
"greenColor": "//div[@color='rgb(3, 179, 101)']",
"toggleJsColor": ".t--property-control-textcolor .t--js-toggle",
"backgroundColor": ".t--property-control-cellbackground input",
diff --git a/app/client/cypress/locators/commonlocators.json b/app/client/cypress/locators/commonlocators.json
index d575271bcf..7248cf2091 100644
--- a/app/client/cypress/locators/commonlocators.json
+++ b/app/client/cypress/locators/commonlocators.json
@@ -100,11 +100,13 @@
"filePickerUploadButton": ".uppy-StatusBar-actionBtn--upload",
"filePickerOnFilesSelected": ".t--property-control-onfilesselected",
"dataType": ".t--property-control-datatype .bp3-popover-target",
- "evaluateMsg": ".t--CodeEditor-evaluatedValue p",
+ "evaluateMsg": ".t--evaluatedPopup-error",
"globalSearchModal": ".t--global-search-modal",
"globalSearchInput": ".t--global-search-input",
"globalSearchTrigger": ".t--global-search-modal-trigger",
"globalSearchClearInput": ".t--global-clear-input",
+ "containerWidget": ".t--widget-containerwidget",
+ "paginationButton": ".rc-pagination-item",
"switchWidgetActive": ".t--switch-widget-active",
"switchWidgetInActive": ".t--switch-widget-inactive",
"switchWidgetLoading": ".t--switch-widget-loading"
diff --git a/app/client/cypress/manual_TestSuite/new_Table_Spec.js b/app/client/cypress/manual_TestSuite/new_Table_Spec.js
index 9e74f08edd..1af26c075a 100644
--- a/app/client/cypress/manual_TestSuite/new_Table_Spec.js
+++ b/app/client/cypress/manual_TestSuite/new_Table_Spec.js
@@ -12,13 +12,11 @@ describe("Table functionality ", function() {
// Navigate to add background colour and Text colour
// Ensure the row colour gets overlapped on table colour
});
-
it("Collapse the tabs of Property pane", function() {
// Add a table
// Click on the property pane
// Collapse the General ,Action and Tab option
});
-
it("Bind the column with same name", function() {
// Add a table
// Click on the property pane
diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js
index fdfd69473f..781a118230 100644
--- a/app/client/cypress/support/commands.js
+++ b/app/client/cypress/support/commands.js
@@ -577,16 +577,26 @@ Cypress.Commands.add("SaveAndRunAPI", () => {
cy.RunAPI();
});
-Cypress.Commands.add("validateRequest", (baseurl, path, verb) => {
- cy.xpath(apiwidget.Request)
- .should("be.visible")
- .click({ force: true });
- cy.xpath(apiwidget.RequestURL).contains(baseurl.concat(path));
- cy.xpath(apiwidget.RequestMethod).contains(verb);
- cy.xpath(apiwidget.Responsetab)
- .should("be.visible")
- .click({ force: true });
-});
+Cypress.Commands.add(
+ "validateRequest",
+ (baseurl, path, verb, error = false) => {
+ cy.get(".react-tabs__tab")
+ .contains("Logs")
+ .click();
+
+ if (!error) {
+ cy.get(".object-key")
+ .last()
+ .contains("request")
+ .click();
+ }
+ cy.get(".string-value").contains(baseurl.concat(path));
+ cy.get(".string-value").contains(verb);
+ cy.xpath(apiwidget.Responsetab)
+ .should("be.visible")
+ .click({ force: true });
+ },
+);
Cypress.Commands.add("SelectAction", (action) => {
cy.get(ApiEditor.ApiVerb)
@@ -1409,6 +1419,14 @@ Cypress.Commands.add(
},
);
+Cypress.Commands.add("readTextDataValidateCSS", (cssProperty, cssValue) => {
+ cy.get(commonlocators.headingTextStyle).should(
+ "have.css",
+ cssProperty,
+ cssValue,
+ );
+});
+
Cypress.Commands.add("evaluateErrorMessage", (value) => {
cy.get(commonlocators.evaluateMsg)
.first()
@@ -1921,7 +1939,7 @@ Cypress.Commands.add("deleteDatasource", (datasourceName) => {
});
Cypress.Commands.add("runQuery", () => {
- cy.get(queryEditor.runQuery).click();
+ cy.get(queryEditor.runQuery).click({ force: true });
cy.wait("@postExecute").should(
"have.nested.property",
"response.body.responseMeta.status",
diff --git a/app/client/docker/templates/nginx-app.conf.template b/app/client/docker/templates/nginx-app.conf.template
index 07e0ed2601..4b7c5fdf4e 100644
--- a/app/client/docker/templates/nginx-app.conf.template
+++ b/app/client/docker/templates/nginx-app.conf.template
@@ -47,6 +47,7 @@ server {
sub_filter __APPSMITH_INTERCOM_APP_ID__ '${APPSMITH_INTERCOM_APP_ID}';
sub_filter __APPSMITH_MAIL_ENABLED__ '${APPSMITH_MAIL_ENABLED}';
sub_filter __APPSMITH_DISABLE_TELEMETRY__ '${APPSMITH_DISABLE_TELEMETRY}';
+ sub_filter __APPSMITH_CLOUD_SERVICES_BASE_URL__ '${APPSMITH_CLOUD_SERVICES_BASE_URL}';
}
location /f {
diff --git a/app/client/jest.config.js b/app/client/jest.config.js
index 43e381ac5f..6599de0964 100644
--- a/app/client/jest.config.js
+++ b/app/client/jest.config.js
@@ -15,7 +15,7 @@ module.exports = {
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"],
moduleDirectories: ["node_modules", "src", "test"],
transformIgnorePatterns: [
- "/node_modules/(?!codemirror|react-dnd|dnd-core|@babel|(@blueprintjs/core/lib/esnext)|(@blueprintjs/core/lib/esm)|@github)",
+ "/node_modules/(?!codemirror|react-dnd|dnd-core|@babel|(@blueprintjs/core/lib/esnext)|(@blueprintjs/core/lib/esm)|@github|lodash-es)",
],
moduleNameMapper: {
"\\.(css|less)$": "/test/__mocks__/styleMock.js",
@@ -23,6 +23,7 @@ module.exports = {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
"/test/__mocks__/fileMock.js",
"^worker-loader!": "/test/__mocks__/workerMock.js",
+ "^!!raw-loader!": "/test/__mocks__/derivedMock.js",
"test/(.*)": "/test/$1",
},
globals: {
diff --git a/app/client/package.json b/app/client/package.json
index 2e3b0c51c6..00fa708665 100644
--- a/app/client/package.json
+++ b/app/client/package.json
@@ -89,6 +89,7 @@
"popper.js": "^1.15.0",
"prettier": "^1.18.2",
"prismjs": "^1.23.0",
+ "rc-pagination": "^3.1.3",
"re-reselect": "^3.4.0",
"react": "^16.12.0",
"react-base-table": "^1.9.1",
@@ -131,7 +132,8 @@
"tinycolor2": "^1.4.1",
"toposort": "^2.0.2",
"ts-loader": "^6.0.4",
- "typescript": "^3.9.2",
+ "tslib": "^2.1.0",
+ "typescript": "^4.1.3",
"unescape-js": "^1.1.4",
"url-search-params-polyfill": "^8.0.0",
"worker-loader": "^3.0.2",
@@ -150,6 +152,7 @@
"start-prod": "REACT_APP_ENVIRONMENT=PRODUCTION craco start",
"cytest": "REACT_APP_TESTING=TESTING REACT_APP_ENVIRONMENT=DEVELOPMENT craco start & ./node_modules/.bin/cypress open",
"test:unit": "$(npm bin)/jest -b --colors --no-cache --coverage --collectCoverage=true --coverageDirectory='../../' --coverageReporters='json-summary'",
+ "test:jest": "$(npm bin)/jest --watch",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public"
},
@@ -179,7 +182,7 @@
"@storybook/preset-create-react-app": "^3.1.4",
"@storybook/react": "^5.3.19",
"@testing-library/jest-dom": "^5.11.4",
- "@testing-library/react": "^11.2.5",
+ "@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^13.1.1",
"@types/codemirror": "^0.0.96",
"@types/deep-diff": "^1.0.0",
@@ -189,14 +192,15 @@
"@types/react-beautiful-dnd": "^11.0.4",
"@types/react-select": "^3.0.5",
"@types/react-tabs": "^2.3.1",
+ "@types/react-test-renderer": "^17.0.1",
"@types/react-window": "^1.8.2",
"@types/redux-form": "^8.1.9",
"@types/redux-mock-store": "^1.0.2",
"@types/styled-system": "^5.1.9",
"@types/tern": "0.22.0",
"@types/toposort": "^2.0.3",
- "@typescript-eslint/eslint-plugin": "^4.6.0",
- "@typescript-eslint/parser": "^4.6.0",
+ "@typescript-eslint/eslint-plugin": "^4.15.0",
+ "@typescript-eslint/parser": "^4.15.0",
"babel-loader": "^8.1.0",
"babel-plugin-styled-components": "^1.10.7",
"craco-babel-loader": "^0.1.4",
@@ -212,6 +216,7 @@
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.21.3",
"eslint-plugin-react-hooks": "^2.3.0",
+ "factory.ts": "^0.5.1",
"jest-canvas-mock": "^2.3.1",
"mocha": "^7.1.0",
"mocha-junit-reporter": "^1.23.3",
diff --git a/app/client/public/index.html b/app/client/public/index.html
index d4e841f00b..558f9ccca9 100755
--- a/app/client/public/index.html
+++ b/app/client/public/index.html
@@ -36,6 +36,46 @@
diff --git a/app/client/public/privacy-policy.html b/app/client/public/privacy-policy.html
index e0938fe862..db20473ea4 100644
--- a/app/client/public/privacy-policy.html
+++ b/app/client/public/privacy-policy.html
@@ -72,7 +72,7 @@
At appsmith, accessible from www.appsmith.com, one of our main priorities is the privacy of
our visitors.
This Privacy Policy document contains types of information that is collected and recorded by
- appsmith and
+ appsmith and its "Services" and
how we use it.
If you have additional questions or require more information about our Privacy Policy, do not
hesitate to
@@ -99,13 +99,20 @@
How we use your information
We use the information we collect in various ways, including to:
- Provide, operate, and maintain our webste
- Improve, personalize, and expand our webste
- Understand and analyze how you use our webste
+ Provide, operate, and maintain our website
+ The information that you provide, or that we receive from third party integrations,
+ are used to retrieve and process your data as part of our services.
+ We do not store any of your data on our servers. We may however,
+ retain your identifiers to provide unhindered access to these services. These identifiers
+ could be your Google access tokens, for example.
+ Wherever our services do this, our documentation will contain a reminder for such
+ access.
+ Improve, personalize, and expand our website
+ Understand and analyze how you use our website
Develop new products, services, features, and functionality
Communicate with you, either directly or through one of our partners, including for
customer service,
- to provide you with updates and other information relating to the webste, and for
+ to provide you with updates and other information relating to the website, and for
marketing and
promotional purposes
Send you emails
diff --git a/app/client/src/AppErrorBoundry.tsx b/app/client/src/AppErrorBoundry.tsx
index 776993508a..172c4aab80 100644
--- a/app/client/src/AppErrorBoundry.tsx
+++ b/app/client/src/AppErrorBoundry.tsx
@@ -51,7 +51,7 @@ class AppErrorBoundary extends Component {
if (this.state.hasError) {
return (
-
+
Oops! Something went wrong
diff --git a/app/client/src/AppRouter.tsx b/app/client/src/AppRouter.tsx
index 9d91296f6e..1ba02d5b77 100644
--- a/app/client/src/AppRouter.tsx
+++ b/app/client/src/AppRouter.tsx
@@ -90,24 +90,24 @@ class AppRouter extends React.Component {
<>
-
+
-
-
-
+
+
+
-
+
-
-
+
+
>
diff --git a/app/client/src/LandingScreen.tsx b/app/client/src/LandingScreen.tsx
index 3a3457aee1..8b456959a9 100755
--- a/app/client/src/LandingScreen.tsx
+++ b/app/client/src/LandingScreen.tsx
@@ -13,7 +13,7 @@ type Props = {
authError: string;
};
-const LandingScreen = (props: Props) => {
+function LandingScreen(props: Props) {
if (props.user && window.location.pathname === BASE_URL) {
if (props.user.email === ANONYMOUS_USERNAME) {
return ;
@@ -25,7 +25,7 @@ const LandingScreen = (props: Props) => {
return ;
}
return ;
-};
+}
const mapStateToProps = (state: AppState) => ({
user: getCurrentUser(state),
diff --git a/app/client/src/actions/actionActions.ts b/app/client/src/actions/actionActions.ts
index 216aae3c56..673f0b1282 100644
--- a/app/client/src/actions/actionActions.ts
+++ b/app/client/src/actions/actionActions.ts
@@ -3,6 +3,8 @@ import {
ReduxActionTypes,
ReduxAction,
ReduxActionErrorTypes,
+ EvaluationReduxAction,
+ ReduxActionWithoutPayload,
} from "constants/ReduxActionConstants";
import { Action } from "entities/Action";
import { batchAction } from "actions/batchActions";
@@ -27,10 +29,12 @@ export type FetchActionsPayload = {
export const fetchActions = (
applicationId: string,
-): ReduxAction => {
+ postEvalActions: Array | ReduxActionWithoutPayload>,
+): EvaluationReduxAction => {
return {
type: ReduxActionTypes.FETCH_ACTIONS_INIT,
payload: { applicationId },
+ postEvalActions,
};
};
diff --git a/app/client/src/actions/controlActions.tsx b/app/client/src/actions/controlActions.tsx
index d04a9410cc..2880e30ac6 100644
--- a/app/client/src/actions/controlActions.tsx
+++ b/app/client/src/actions/controlActions.tsx
@@ -22,6 +22,7 @@ export const updateWidgetPropertyRequest = (
export interface BatchPropertyUpdatePayload {
modify?: Record; //Key value pairs of paths and values to update
remove?: string[]; //Array of paths to delete
+ triggerPaths?: string[]; // Array of paths in the modify and remove list which are trigger paths
}
export const batchUpdateWidgetProperty = (
diff --git a/app/client/src/actions/datasourceActions.ts b/app/client/src/actions/datasourceActions.ts
index cffe0e5181..6fa834fd62 100644
--- a/app/client/src/actions/datasourceActions.ts
+++ b/app/client/src/actions/datasourceActions.ts
@@ -5,6 +5,7 @@ import {
} from "constants/ReduxActionConstants";
import { CreateDatasourceConfig } from "api/DatasourcesApi";
import { Datasource } from "entities/Datasource";
+import { PluginType } from "entities/Action";
export const createDatasourceFromForm = (payload: CreateDatasourceConfig) => {
return {
@@ -44,12 +45,14 @@ export const updateDatasourceSuccess = (
export const redirectAuthorizationCode = (
pageId: string,
datasourceId: string,
+ pluginType: PluginType,
) => {
return {
type: ReduxActionTypes.REDIRECT_AUTHORIZATION_CODE,
payload: {
pageId,
datasourceId,
+ pluginType,
},
};
};
@@ -105,10 +108,16 @@ export const testDatasource = (payload: Partial) => {
};
};
-export const deleteDatasource = (payload: Partial) => {
+export const deleteDatasource = (
+ payload: Partial,
+ onSuccess?: ReduxAction,
+ onError?: ReduxAction,
+): ReduxActionWithCallbacks, unknown, unknown> => {
return {
type: ReduxActionTypes.DELETE_DATASOURCE_INIT,
payload,
+ onSuccess,
+ onError,
};
};
@@ -128,15 +137,6 @@ export const fetchDatasources = () => {
};
};
-export const selectPlugin = (pluginId: string) => {
- return {
- type: ReduxActionTypes.SELECT_PLUGIN,
- payload: {
- pluginId,
- },
- };
-};
-
export const initDatasourcePane = (
pluginType: string,
urlId?: string,
@@ -153,8 +153,14 @@ export const storeAsDatasource = () => {
};
};
+export const getOAuthAccessToken = (datasourceId: string) => {
+ return {
+ type: ReduxActionTypes.SAAS_GET_OAUTH_ACCESS_TOKEN,
+ payload: { datasourceId },
+ };
+};
+
export default {
fetchDatasources,
initDatasourcePane,
- selectPlugin,
};
diff --git a/app/client/src/actions/debuggerActions.ts b/app/client/src/actions/debuggerActions.ts
new file mode 100644
index 0000000000..a0ca54e4a7
--- /dev/null
+++ b/app/client/src/actions/debuggerActions.ts
@@ -0,0 +1,31 @@
+import { ReduxActionTypes } from "constants/ReduxActionConstants";
+import { Message } from "entities/AppsmithConsole";
+
+export const debuggerLogInit = (payload: Message) => ({
+ type: ReduxActionTypes.DEBUGGER_LOG_INIT,
+ payload,
+});
+
+export const debuggerLog = (payload: Message) => ({
+ type: ReduxActionTypes.DEBUGGER_LOG,
+ payload,
+});
+
+export const clearLogs = () => ({
+ type: ReduxActionTypes.CLEAR_DEBUGGER_LOGS,
+});
+
+export const showDebugger = (payload?: boolean) => ({
+ type: ReduxActionTypes.SHOW_DEBUGGER,
+ payload,
+});
+
+export const errorLog = (payload: Message) => ({
+ type: ReduxActionTypes.DEBUGGER_ERROR_LOG,
+ payload,
+});
+
+export const updateErrorLog = (payload: Message) => ({
+ type: ReduxActionTypes.DEBUGGER_UPDATE_ERROR_LOG,
+ payload,
+});
diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx
index a199240e90..f454c0349d 100644
--- a/app/client/src/actions/pageActions.tsx
+++ b/app/client/src/actions/pageActions.tsx
@@ -1,15 +1,16 @@
-import { FetchPageRequest, PageLayout, SavePageResponse } from "api/PageApi";
-import { WidgetOperation } from "widgets/BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import {
EvaluationReduxAction,
ReduxAction,
ReduxActionTypes,
+ ReduxActionWithoutPayload,
UpdateCanvasPayload,
} from "constants/ReduxActionConstants";
-import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
import AnalyticsUtil from "utils/AnalyticsUtil";
+import { WidgetOperation } from "widgets/BaseWidget";
+import { FetchPageRequest, PageLayout, SavePageResponse } from "api/PageApi";
import { APP_MODE, UrlDataState } from "reducers/entityReducers/appReducer";
+import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
export interface FetchPageListPayload {
applicationId: string;
@@ -46,18 +47,14 @@ export const fetchPublishedPage = (pageId: string, bustCache = false) => ({
},
});
-export const fetchPageSuccess = (
- postEvalActions: ReduxAction[],
-): EvaluationReduxAction => {
+export const fetchPageSuccess = (): ReduxActionWithoutPayload => {
return {
type: ReduxActionTypes.FETCH_PAGE_SUCCESS,
- payload: {},
- postEvalActions,
};
};
export const fetchPublishedPageSuccess = (
- postEvalActions: ReduxAction[],
+ postEvalActions: Array | ReduxActionWithoutPayload>,
): EvaluationReduxAction => ({
type: ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS,
postEvalActions,
@@ -230,12 +227,23 @@ export type WidgetAddChildren = {
}>;
};
+export type WidgetUpdateProperty = {
+ widgetId: string;
+ propertyPath: string;
+ propertyValue: any;
+};
+
export const updateWidget = (
operation: WidgetOperation,
widgetId: string,
payload: any,
): ReduxAction<
- WidgetAddChild | WidgetMove | WidgetResize | WidgetDelete | WidgetAddChildren
+ | WidgetAddChild
+ | WidgetMove
+ | WidgetResize
+ | WidgetDelete
+ | WidgetAddChildren
+ | WidgetUpdateProperty
> => {
return {
type: ReduxActionTypes["WIDGET_" + operation],
diff --git a/app/client/src/actions/pluginActions.ts b/app/client/src/actions/pluginActions.ts
index 6b0830bd5a..573853e2bc 100644
--- a/app/client/src/actions/pluginActions.ts
+++ b/app/client/src/actions/pluginActions.ts
@@ -4,6 +4,7 @@ import {
ReduxActionWithoutPayload,
} from "constants/ReduxActionConstants";
import { PluginFormPayload } from "api/PluginApi";
+import { DependencyMap } from "utils/DynamicBindingUtils";
export const fetchPlugins = (): ReduxActionWithoutPayload => ({
type: ReduxActionTypes.FETCH_PLUGINS_REQUEST,
@@ -17,6 +18,7 @@ export type PluginFormsPayload = {
formConfigs: Record;
editorConfigs: Record;
settingConfigs: Record;
+ dependencies: Record;
};
export const fetchPluginFormConfigsSuccess = (
diff --git a/app/client/src/actions/propertyPaneActions.test.ts b/app/client/src/actions/propertyPaneActions.test.ts
new file mode 100644
index 0000000000..5914e6c8b8
--- /dev/null
+++ b/app/client/src/actions/propertyPaneActions.test.ts
@@ -0,0 +1,11 @@
+import * as actions from "./propertyPaneActions";
+import { ReduxActionTypes } from "constants/ReduxActionConstants";
+
+describe("property pane action actions", () => {
+ it("should create an action hide Property Pane", () => {
+ const expectedAction = {
+ type: ReduxActionTypes.HIDE_PROPERTY_PANE,
+ };
+ expect(actions.hidePropertyPane()).toEqual(expectedAction);
+ });
+});
diff --git a/app/client/src/actions/propertyPaneActions.ts b/app/client/src/actions/propertyPaneActions.ts
index 615daa5170..a90d3a1453 100644
--- a/app/client/src/actions/propertyPaneActions.ts
+++ b/app/client/src/actions/propertyPaneActions.ts
@@ -8,3 +8,9 @@ export const updateWidgetName = (widgetId: string, newName: string) => {
},
};
};
+
+export const hidePropertyPane = () => {
+ return {
+ type: ReduxActionTypes.HIDE_PROPERTY_PANE,
+ };
+};
diff --git a/app/client/src/actions/utilActions.ts b/app/client/src/actions/utilActions.ts
new file mode 100644
index 0000000000..9597b4b119
--- /dev/null
+++ b/app/client/src/actions/utilActions.ts
@@ -0,0 +1,15 @@
+import { ReduxActionTypes } from "constants/ReduxActionConstants";
+
+export const historyPush = (url: string) => ({
+ type: ReduxActionTypes.HISTORY_PUSH,
+ payload: {
+ url,
+ },
+});
+
+export const windowRedirect = (url: string) => ({
+ type: ReduxActionTypes.REDIRECT_WINDOW_LOCATION,
+ payload: {
+ url,
+ },
+});
diff --git a/app/client/src/actions/widgetActions.tsx b/app/client/src/actions/widgetActions.tsx
index 814f7a6987..03e1f59548 100644
--- a/app/client/src/actions/widgetActions.tsx
+++ b/app/client/src/actions/widgetActions.tsx
@@ -2,11 +2,11 @@ import {
ReduxActionTypes,
ReduxAction,
ReduxActionErrorTypes,
+ ReduxActionWithoutPayload,
} from "constants/ReduxActionConstants";
import {
ExecuteActionPayload,
ExecuteErrorPayload,
- PageAction,
} from "constants/AppsmithActionConstants/ActionConstants";
import { BatchAction, batchAction } from "actions/batchActions";
import PerformanceTracker, {
@@ -30,11 +30,8 @@ export const executeActionError = (
};
};
-export const executePageLoadActions = (
- payload: PageAction[][],
-): ReduxAction => ({
+export const executePageLoadActions = (): ReduxActionWithoutPayload => ({
type: ReduxActionTypes.EXECUTE_PAGE_LOAD_ACTIONS,
- payload,
});
export const disableDragAction = (
diff --git a/app/client/src/api/ActionAPI.tsx b/app/client/src/api/ActionAPI.tsx
index d82c6e7291..03d6f54900 100644
--- a/app/client/src/api/ActionAPI.tsx
+++ b/app/client/src/api/ActionAPI.tsx
@@ -108,11 +108,7 @@ class ActionAPI extends API {
static apiUpdateCancelTokenSource: CancelTokenSource;
static queryUpdateCancelTokenSource: CancelTokenSource;
- static fetchAPI(id: string): AxiosPromise> {
- return API.get(`${ActionAPI.url}/${id}`);
- }
-
- static createAPI(
+ static createAction(
apiConfig: Partial,
): AxiosPromise {
return API.post(ActionAPI.url, apiConfig);
@@ -136,7 +132,7 @@ class ActionAPI extends API {
return API.get(ActionAPI.url, { pageId });
}
- static updateAPI(
+ static updateAction(
apiConfig: Partial,
): AxiosPromise {
if (ActionAPI.apiUpdateCancelTokenSource) {
@@ -159,24 +155,6 @@ class ActionAPI extends API {
return API.delete(`${ActionAPI.url}/${id}`);
}
- static createQuery(
- createQuery: CreateActionRequest,
- ): AxiosPromise {
- return API.post(ActionAPI.url, createQuery);
- }
-
- static updateQuery(
- updateQuery: UpdateActionRequest,
- ): AxiosPromise {
- if (ActionAPI.queryUpdateCancelTokenSource) {
- ActionAPI.queryUpdateCancelTokenSource.cancel();
- }
- ActionAPI.queryUpdateCancelTokenSource = axios.CancelToken.source();
- return API.post(ActionAPI.url, updateQuery, undefined, {
- cancelToken: ActionAPI.queryUpdateCancelTokenSource.token,
- });
- }
-
static executeAction(
executeAction: ExecuteActionRequest,
timeout?: number,
@@ -192,12 +170,6 @@ class ActionAPI extends API {
});
}
- static executeQuery(
- executeAction: any,
- ): AxiosPromise {
- return API.post(ActionAPI.url + "/execute", executeAction);
- }
-
static toggleActionExecuteOnLoad(actionId: string, shouldExecute: boolean) {
return API.put(ActionAPI.url + `/executeOnLoad/${actionId}`, undefined, {
flag: shouldExecute.toString(),
diff --git a/app/client/src/api/CloudServicesApi.ts b/app/client/src/api/CloudServicesApi.ts
new file mode 100644
index 0000000000..c4abc26056
--- /dev/null
+++ b/app/client/src/api/CloudServicesApi.ts
@@ -0,0 +1,6 @@
+import { getAppsmithConfigs } from "configs";
+
+const { cloudServicesBaseUrl: BASE_URL } = getAppsmithConfigs();
+
+export const authorizeSaasWithAppsmithToken = (appsmithToken: string) =>
+ `${BASE_URL}/api/v1/integrations/oauth/authorize?appsmithToken=${appsmithToken}`;
diff --git a/app/client/src/api/PluginApi.ts b/app/client/src/api/PluginApi.ts
index 6c46bf1a7d..938b7bff26 100644
--- a/app/client/src/api/PluginApi.ts
+++ b/app/client/src/api/PluginApi.ts
@@ -1,11 +1,13 @@
import Api from "api/Api";
import { AxiosPromise } from "axios";
import { GenericApiResponse } from "api/ApiResponses";
+import { PluginType } from "entities/Action";
+import { DependencyMap } from "utils/DynamicBindingUtils";
export interface Plugin {
id: string;
name: string;
- type: "API" | "DB";
+ type: PluginType;
packageName: string;
iconLocation?: string;
uiComponent: "ApiEditorForm" | "RapidApiEditorForm" | "DbEditorForm";
@@ -20,6 +22,7 @@ export interface PluginFormPayload {
form: any[];
editor: any[];
setting: any[];
+ dependencies: DependencyMap;
}
class PluginsApi extends Api {
diff --git a/app/client/src/api/SaasApi.ts b/app/client/src/api/SaasApi.ts
new file mode 100644
index 0000000000..b463883d62
--- /dev/null
+++ b/app/client/src/api/SaasApi.ts
@@ -0,0 +1,25 @@
+import Api from "./Api";
+import { AxiosPromise } from "axios";
+import { GenericApiResponse } from "api/ApiResponses";
+import { Datasource } from "entities/Datasource";
+
+class SaasApi extends Api {
+ static url = "v1/saas";
+ static getAppsmithToken(
+ datasourceId: string,
+ pageId: string,
+ ): AxiosPromise> {
+ return Api.post(`${SaasApi.url}/${datasourceId}/pages/${pageId}/oauth`);
+ }
+
+ static getAccessToken(
+ datasourceId: string,
+ token: string,
+ ): AxiosPromise> {
+ return Api.post(
+ `${SaasApi.url}/${datasourceId}/token?appsmithToken=${token}`,
+ );
+ }
+}
+
+export default SaasApi;
diff --git a/app/client/src/assets/icons/ads/bug.svg b/app/client/src/assets/icons/ads/bug.svg
new file mode 100644
index 0000000000..28f60f75af
--- /dev/null
+++ b/app/client/src/assets/icons/ads/bug.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/client/src/assets/icons/ads/cancel.svg b/app/client/src/assets/icons/ads/cancel.svg
new file mode 100644
index 0000000000..254210469e
--- /dev/null
+++ b/app/client/src/assets/icons/ads/cancel.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/client/src/assets/icons/ads/cross.svg b/app/client/src/assets/icons/ads/cross.svg
new file mode 100644
index 0000000000..9589ed4d54
--- /dev/null
+++ b/app/client/src/assets/icons/ads/cross.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/client/src/assets/icons/ads/open.svg b/app/client/src/assets/icons/ads/open.svg
new file mode 100644
index 0000000000..2b43521e49
--- /dev/null
+++ b/app/client/src/assets/icons/ads/open.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/client/src/assets/icons/ads/wand.svg b/app/client/src/assets/icons/ads/wand.svg
new file mode 100644
index 0000000000..5a51055344
--- /dev/null
+++ b/app/client/src/assets/icons/ads/wand.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/client/src/assets/icons/ads/warning-triangle.svg b/app/client/src/assets/icons/ads/warning-triangle.svg
new file mode 100644
index 0000000000..350e33a327
--- /dev/null
+++ b/app/client/src/assets/icons/ads/warning-triangle.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/client/src/assets/icons/widget/list.svg b/app/client/src/assets/icons/widget/list.svg
new file mode 100644
index 0000000000..87348a0e9e
--- /dev/null
+++ b/app/client/src/assets/icons/widget/list.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/app/client/src/components/ads/AppIcon.tsx b/app/client/src/components/ads/AppIcon.tsx
index adb38cc047..bfc56042cd 100644
--- a/app/client/src/components/ads/AppIcon.tsx
+++ b/app/client/src/components/ads/AppIcon.tsx
@@ -223,7 +223,7 @@ export type AppIconProps = CommonComponentProps & {
name: AppIconName;
};
-const AppIcon = (props: AppIconProps) => {
+function AppIcon(props: AppIconProps) {
const styledProps = useMemo(() => appSizeHandler(props.size || Size.medium), [
props,
]);
@@ -484,6 +484,6 @@ const AppIcon = (props: AppIconProps) => {
{returnIcon}
) : null;
-};
+}
export default AppIcon;
diff --git a/app/client/src/components/ads/Button.tsx b/app/client/src/components/ads/Button.tsx
index 584a257d82..ea97229575 100644
--- a/app/client/src/components/ads/Button.tsx
+++ b/app/client/src/components/ads/Button.tsx
@@ -376,13 +376,13 @@ const IconSizeProp = (size?: Size) => {
return size ? sizeMapping[size] : IconSize.SMALL;
};
-const TextLoadingState = ({ text }: { text?: string }) => (
- {text}
-);
+function TextLoadingState({ text }: { text?: string }) {
+ return {text} ;
+}
-const IconLoadingState = ({ size, icon }: { size?: Size; icon?: IconName }) => (
-
-);
+function IconLoadingState({ size, icon }: { size?: Size; icon?: IconName }) {
+ return ;
+}
const getIconContent = (props: ButtonProps) =>
props.icon ? (
@@ -410,39 +410,44 @@ const getButtonContent = (props: ButtonProps) => (
>
);
-const ButtonComponent = (props: ButtonProps) => (
- ) =>
- props.onClick && props.onClick(e)
- }
- >
- {getButtonContent(props)}
-
-);
+function ButtonComponent(props: ButtonProps) {
+ return (
+ ) =>
+ props.onClick && props.onClick(e)
+ }
+ >
+ {getButtonContent(props)}
+
+ );
+}
-const LinkButtonComponent = (props: ButtonProps) => (
- ) =>
- props.onClick && props.onClick(e)
- }
- >
- {getButtonContent(props)}
-
-);
+function LinkButtonComponent(props: ButtonProps) {
+ return (
+ ) =>
+ props.onClick && props.onClick(e)
+ }
+ >
+ {getButtonContent(props)}
+
+ );
+}
-const Button = (props: ButtonProps) =>
- props.tag === "button" ? (
+function Button(props: ButtonProps) {
+ return props.tag === "button" ? (
) : (
);
+}
export default Button;
diff --git a/app/client/src/components/ads/ButtonTabComponent.tsx b/app/client/src/components/ads/ButtonTabComponent.tsx
index 4fd11e6b73..4fe5bbe03f 100644
--- a/app/client/src/components/ads/ButtonTabComponent.tsx
+++ b/app/client/src/components/ads/ButtonTabComponent.tsx
@@ -41,7 +41,7 @@ interface ButtonTabComponentProps {
selectButton: (value: string) => void;
}
-const ButtonTabComponent = (props: ButtonTabComponentProps) => {
+function ButtonTabComponent(props: ButtonTabComponentProps) {
return (
{props.options.map((option: ButtonTabOption, index: number) => {
@@ -50,17 +50,17 @@ const ButtonTabComponent = (props: ButtonTabComponentProps) => {
const isSelected = props.values.includes(option.value);
return (
props.selectButton(option.value)}
className={`t--button-tab-${option.value}`}
+ key={index}
+ onClick={() => props.selectButton(option.value)}
+ selected={isSelected}
>
-
+
);
})}
);
-};
+}
export default ButtonTabComponent;
diff --git a/app/client/src/components/ads/Callout.tsx b/app/client/src/components/ads/Callout.tsx
index a1eeabb6e8..2df99e39a2 100644
--- a/app/client/src/components/ads/Callout.tsx
+++ b/app/client/src/components/ads/Callout.tsx
@@ -73,14 +73,14 @@ Callout.defaultProps = {
function Callout(props: CalloutProps) {
return (
-
+
{props.text && props.variant !== Variant.info ? (
) : null}
{props.text}
{props.label ? props.label : null}
{props.closeButton ? (
-
+
) : null}
diff --git a/app/client/src/components/ads/Checkbox.tsx b/app/client/src/components/ads/Checkbox.tsx
index 295944f6c7..a8ab84d1ae 100644
--- a/app/client/src/components/ads/Checkbox.tsx
+++ b/app/client/src/components/ads/Checkbox.tsx
@@ -106,7 +106,7 @@ const useUpdate = (intitialValue?: boolean) => {
return [checked, setChecked] as const;
};
-const Checkbox = (props: CheckboxProps) => {
+function Checkbox(props: CheckboxProps) {
const [checked, setChecked] = useUpdate(props.isDefaultChecked);
const onChangeHandler = (checked: boolean) => {
@@ -121,20 +121,20 @@ const Checkbox = (props: CheckboxProps) => {
{props.info ? {props.info} : null}
) =>
onChangeHandler(e.target.checked)
}
+ type="checkbox"
/>
);
-};
+}
export default Checkbox;
diff --git a/app/client/src/components/ads/ColorPickerComponent.tsx b/app/client/src/components/ads/ColorPickerComponent.tsx
index f7cd8bd8f8..83deb47adc 100644
--- a/app/client/src/components/ads/ColorPickerComponent.tsx
+++ b/app/client/src/components/ads/ColorPickerComponent.tsx
@@ -93,14 +93,14 @@ const EmptyColorIconWrapper = styled.div`
}
`;
-const ColorBoard = (props: ColorBoardProps) => {
+function ColorBoard(props: ColorBoardProps) {
return (
{defaultColors.map((color: string, index: number) => (
props.selectColor(color)}
>
{props.selectedColor === color && }
@@ -113,7 +113,7 @@ const ColorBoard = (props: ColorBoardProps) => {
);
-};
+}
const NoColorIconWrapper = styled.div`
position: absolute;
@@ -148,7 +148,7 @@ interface ColorPickerProps {
changeColor: (color: string) => void;
}
-const ColorPickerComponent = (props: ColorPickerProps) => {
+function ColorPickerComponent(props: ColorPickerProps) {
const [color, setColor] = React.useState(props.color);
const debouncedOnChange = React.useCallback(
debounce(props.changeColor, 500),
@@ -161,16 +161,16 @@ const ColorPickerComponent = (props: ColorPickerProps) => {
};
return (
{
value={color}
/>
{
setColor(color);
props.changeColor(color);
}}
+ selectedColor={color}
/>
);
-};
+}
export default ColorPickerComponent;
diff --git a/app/client/src/components/ads/ColorSelector.tsx b/app/client/src/components/ads/ColorSelector.tsx
index 6153bc06f9..3a7ee96504 100644
--- a/app/client/src/components/ads/ColorSelector.tsx
+++ b/app/client/src/components/ads/ColorSelector.tsx
@@ -56,7 +56,7 @@ const ColorBox = styled.div<{ selected: string; color: string }>`
`}
`;
-const ColorSelector = (props: ColorSelectorProps) => {
+function ColorSelector(props: ColorSelectorProps) {
const [selected, setSelected] = useState(
props.defaultValue || props.colorPalette[0],
);
@@ -68,28 +68,28 @@ const ColorSelector = (props: ColorSelectorProps) => {
}, [props.defaultValue]);
return (
-
+
{props.colorPalette.map((hex: string, index: number) => {
return (
{
if (selected !== hex) {
setSelected(hex);
props.onSelect && props.onSelect(hex);
}
}}
- className={
- selected === hex ? "t--color-selected" : "t--color-not-selected"
- }
+ selected={selected}
/>
);
})}
);
-};
+}
ColorSelector.defaultProps = {
fill: false,
diff --git a/app/client/src/components/ads/CopyToClipBoard.tsx b/app/client/src/components/ads/CopyToClipBoard.tsx
index e6ff4633a3..f6bc79a55e 100644
--- a/app/client/src/components/ads/CopyToClipBoard.tsx
+++ b/app/client/src/components/ads/CopyToClipBoard.tsx
@@ -15,7 +15,7 @@ const Wrapper = styled.div`
}
`;
-const CopyToClipboard = (props: any) => {
+function CopyToClipboard(props: any) {
const { copyText } = props;
const copyURLInput = createRef();
const [isCopied, setIsCopied] = useState(false);
@@ -36,25 +36,25 @@ const CopyToClipboard = (props: any) => {
return (
{
selectText();
}}
- defaultValue={copyText}
+ readOnly
+ ref={copyURLInput}
/>
{
copyToClipboard(copyText);
}}
size={Size.large}
+ text={isCopied ? "Copied" : "Copy"}
/>
);
-};
+}
export default CopyToClipboard;
diff --git a/app/client/src/components/ads/DatePickerComponent.tsx b/app/client/src/components/ads/DatePickerComponent.tsx
index b455082ea4..4cee86022e 100644
--- a/app/client/src/components/ads/DatePickerComponent.tsx
+++ b/app/client/src/components/ads/DatePickerComponent.tsx
@@ -100,25 +100,25 @@ interface DatePickerComponentProps {
parseDate?: (dateStr: string) => Date;
}
-const DatePickerComponent = (props: DatePickerComponentProps) => {
+function DatePickerComponent(props: DatePickerComponentProps) {
return (
);
-};
+}
DatePickerComponent.defaultProps = {
highlightCurrentDay: true,
diff --git a/app/client/src/components/ads/DialogComponent.tsx b/app/client/src/components/ads/DialogComponent.tsx
index 698b996b7c..8dd7df4533 100644
--- a/app/client/src/components/ads/DialogComponent.tsx
+++ b/app/client/src/components/ads/DialogComponent.tsx
@@ -93,7 +93,7 @@ type DialogComponentProps = {
className?: string;
};
-export const DialogComponent = (props: DialogComponentProps) => {
+export function DialogComponent(props: DialogComponentProps) {
const [isOpen, setIsOpen] = useState(!!props.isOpen);
const onClose = () => {
@@ -107,7 +107,7 @@ export const DialogComponent = (props: DialogComponentProps) => {
const getHeader = props.getHeader;
return (
-
+ <>
{
@@ -118,23 +118,23 @@ export const DialogComponent = (props: DialogComponentProps) => {
{props.trigger}
{getHeader && getHeader()}
{props.children}
-
+ >
);
-};
+}
export default DialogComponent;
diff --git a/app/client/src/components/ads/DraggableList.tsx b/app/client/src/components/ads/DraggableList.tsx
index 34f1f79428..79a03ed66d 100644
--- a/app/client/src/components/ads/DraggableList.tsx
+++ b/app/client/src/components/ads/DraggableList.tsx
@@ -59,7 +59,7 @@ const DraggableListWrapper = styled.div`
}
`;
-const DraggableList = ({ items, ItemRenderer, onUpdate, itemHeight }: any) => {
+function DraggableList({ items, ItemRenderer, onUpdate, itemHeight }: any) {
// order of items in the list
const order = useRef(items.map((_: any, index: any) => index));
@@ -111,12 +111,12 @@ const DraggableList = ({ items, ItemRenderer, onUpdate, itemHeight }: any) => {
});
return (
{
// set events to null to stop other parent draggable elements execution(ex: Property pane)
document.onmouseup = null;
document.onmousemove = null;
}}
- className="content"
style={{ height: items.length * itemHeight }}
>
{springs.map(({ zIndex, y, scale }, i) => (
@@ -134,13 +134,13 @@ const DraggableList = ({ items, ItemRenderer, onUpdate, itemHeight }: any) => {
}}
>
-
+
))}
);
-};
+}
DraggableList.displayName = "DraggableList";
export default DraggableList;
diff --git a/app/client/src/components/ads/Dropdown.tsx b/app/client/src/components/ads/Dropdown.tsx
index 004196265b..77e7ce9191 100644
--- a/app/client/src/components/ads/Dropdown.tsx
+++ b/app/client/src/components/ads/Dropdown.tsx
@@ -185,22 +185,24 @@ const SelectedIcon = styled(Icon)`
}
`;
-const DefaultDropDownValueNode = ({
+function DefaultDropDownValueNode({
selected,
showLabelOnly,
}: {
selected: DropdownOption;
showLabelOnly?: boolean;
-}) => (
-
- {selected.icon ? (
-
- ) : null}
-
- {showLabelOnly ? selected.label : selected.value}
-
-
-);
+}) {
+ return (
+
+ {selected.icon ? (
+
+ ) : null}
+
+ {showLabelOnly ? selected.label : selected.value}
+
+
+ );
+}
export default function Dropdown(props: DropdownProps) {
const {
@@ -226,25 +228,25 @@ export default function Dropdown(props: DropdownProps) {
);
return (
setIsOpen(state)}
popoverClassName={props.className}
position={Position.BOTTOM_LEFT}
- isOpen={isOpen && !props.disabled}
- onInteraction={(state) => setIsOpen(state)}
- boundary="scrollParent"
>
setIsOpen(!isOpen)}
className={props.className}
+ disabled={props.disabled}
height={props.height || "38px"}
+ isOpen={isOpen}
+ onClick={() => setIsOpen(!isOpen)}
>
{
return (
optionClickHandler(option)}
className="t--dropdown-option"
+ key={index}
+ onClick={() => optionClickHandler(option)}
+ selected={selected.value === option.value}
>
{option.icon ? (
) : null}
diff --git a/app/client/src/components/ads/EditableText.tsx b/app/client/src/components/ads/EditableText.tsx
index c1f0bb4843..bca0528165 100644
--- a/app/client/src/components/ads/EditableText.tsx
+++ b/app/client/src/components/ads/EditableText.tsx
@@ -152,7 +152,7 @@ const IconWrapper = styled.div`
justify-content: flex-end;
`;
-export const EditableText = (props: EditableTextProps) => {
+export function EditableText(props: EditableTextProps) {
const {
onBlur,
onTextChanged,
@@ -268,36 +268,36 @@ export const EditableText = (props: EditableTextProps) => {
return (
{savingState === SavingState.STARTED ? (
@@ -317,6 +317,6 @@ export const EditableText = (props: EditableTextProps) => {
) : null}
);
-};
+}
export default EditableText;
diff --git a/app/client/src/components/ads/EditableTextWrapper.tsx b/app/client/src/components/ads/EditableTextWrapper.tsx
index 62713190c1..5fe58511fd 100644
--- a/app/client/src/components/ads/EditableTextWrapper.tsx
+++ b/app/client/src/components/ads/EditableTextWrapper.tsx
@@ -86,23 +86,16 @@ export default function EditableTextWrapper(props: EditableTextWrapperProps) {
return (
{
- setIsEditing(false);
- props.onBlur && props.onBlur(value);
- }}
- className={props.className}
- onTextChanged={() => setIsEditing(true)}
isInvalid={(value: string) => {
setIsEditing(true);
if (props.isInvalid) {
@@ -118,6 +111,13 @@ export default function EditableTextWrapper(props: EditableTextWrapperProps) {
return false;
}
}}
+ onBlur={(value) => {
+ setIsEditing(false);
+ props.onBlur && props.onBlur(value);
+ }}
+ onTextChanged={() => setIsEditing(true)}
+ placeholder={props.placeholder}
+ savingState={props.savingState}
/>
);
diff --git a/app/client/src/components/ads/FilePicker.tsx b/app/client/src/components/ads/FilePicker.tsx
index 9ca21e2956..1d5d6936b4 100644
--- a/app/client/src/components/ads/FilePicker.tsx
+++ b/app/client/src/components/ads/FilePicker.tsx
@@ -158,7 +158,7 @@ export function CloudinaryUploader(
});
}
-const FilePickerComponent = (props: FilePickerProps) => {
+function FilePickerComponent(props: FilePickerProps) {
const { logoUploadError } = props;
const [fileInfo, setFileInfo] = useState<{ name: string; size: number }>({
name: "",
@@ -293,64 +293,64 @@ const FilePickerComponent = (props: FilePickerProps) => {
return (
-
+
-
+
Drag & Drop files to upload or
-
+
{fileInfo.name}
{fileInfo.size}KB
removeFile()}
+ size={Size.medium}
+ text="remove"
/>
);
-};
+}
-const FilePicker = (props: FilePickerProps) => {
+function FilePicker(props: FilePickerProps) {
return (
);
-};
+}
export default FilePicker;
diff --git a/app/client/src/components/ads/GifPlayerComponent.tsx b/app/client/src/components/ads/GifPlayerComponent.tsx
index abd58e55af..3074ee7e0d 100644
--- a/app/client/src/components/ads/GifPlayerComponent.tsx
+++ b/app/client/src/components/ads/GifPlayerComponent.tsx
@@ -52,24 +52,20 @@ const Overlay = styled.div`
transition: 0.5s ease;
`;
-const GifPlayerComponent = (props: GifPlayerProps) => {
+function GifPlayerComponent(props: GifPlayerProps) {
const [startGif, setStartGif] = useState(false);
- return (
-
- {!startGif ? (
- setStartGif(!startGif)}>
-
-
-
-
- Click to play
-
-
- ) : (
-
- )}
-
+ return !startGif ? (
+
setStartGif(!startGif)}>
+
+
+
+
+ Click to play
+
+
+ ) : (
+
);
-};
+}
export default GifPlayerComponent;
diff --git a/app/client/src/components/ads/Icon.tsx b/app/client/src/components/ads/Icon.tsx
index f2eb7aa482..d1e7283cab 100644
--- a/app/client/src/components/ads/Icon.tsx
+++ b/app/client/src/components/ads/Icon.tsx
@@ -1,6 +1,10 @@
import React, { forwardRef, Ref } from "react";
import { ReactComponent as DeleteIcon } from "assets/icons/ads/delete.svg";
import { ReactComponent as BookIcon } from "assets/icons/ads/book.svg";
+import { ReactComponent as BugIcon } from "assets/icons/ads/bug.svg";
+import { ReactComponent as CancelIcon } from "assets/icons/ads/cancel.svg";
+import { ReactComponent as CrossIcon } from "assets/icons/ads/cross.svg";
+import { ReactComponent as OpenIcon } from "assets/icons/ads/open.svg";
import { ReactComponent as UserIcon } from "assets/icons/ads/user.svg";
import { ReactComponent as GeneralIcon } from "assets/icons/ads/general.svg";
import { ReactComponent as BillingIcon } from "assets/icons/ads/billing.svg";
@@ -11,6 +15,7 @@ import { ReactComponent as SuccessIcon } from "assets/icons/ads/success.svg";
import { ReactComponent as SearchIcon } from "assets/icons/ads/search.svg";
import { ReactComponent as CloseIcon } from "assets/icons/ads/close.svg";
import { ReactComponent as WarningIcon } from "assets/icons/ads/warning.svg";
+import { ReactComponent as WarningTriangleIcon } from "assets/icons/ads/warning-triangle.svg";
import { ReactComponent as DownArrow } from "assets/icons/ads/down_arrow.svg";
import { ReactComponent as ShareIcon } from "assets/icons/ads/share.svg";
import { ReactComponent as RocketIcon } from "assets/icons/ads/launch.svg";
@@ -37,6 +42,7 @@ import { ReactComponent as RightArrowIcon } from "assets/icons/ads/right-arrow.s
import { ReactComponent as DatasourceIcon } from "assets/icons/ads/datasource.svg";
import { ReactComponent as PlayIcon } from "assets/icons/ads/play.svg";
import { ReactComponent as DesktopIcon } from "assets/icons/ads/desktop.svg";
+import { ReactComponent as WandIcon } from "assets/icons/ads/wand.svg";
import { ReactComponent as MobileIcon } from "assets/icons/ads/mobile.svg";
import { ReactComponent as TabletIcon } from "assets/icons/ads/tablet.svg";
import { ReactComponent as FluidIcon } from "assets/icons/ads/fluid.svg";
@@ -95,7 +101,11 @@ export const sizeHandler = (size?: IconSize) => {
export const IconCollection = [
"book",
+ "bug",
+ "cancel",
+ "cross",
"delete",
+ "open",
"user",
"general",
"billing",
@@ -114,6 +124,7 @@ export const IconCollection = [
"view-all",
"view-less",
"warning",
+ "warning-triangle",
"downArrow",
"context-menu",
"duplicate",
@@ -133,6 +144,7 @@ export const IconCollection = [
"datasource",
"play",
"desktop",
+ "wand",
"mobile",
"tablet",
"fluid",
@@ -154,17 +166,29 @@ export const IconWrapper = styled.span
`
svg {
width: ${(props) => sizeHandler(props.size)}px;
height: ${(props) => sizeHandler(props.size)}px;
+ ${(props) =>
+ !props.keepColors
+ ? `
path {
- fill: ${(props) => props.fillColor || props.theme.colors.icon.normal};
+ fill: ${props.fillColor || props.theme.colors.icon.normal};
}
- }
+ circle {
+ fill: ${props.fillColor || props.theme.colors.icon.normal};
+ }
+ `
+ : ""}
${(props) => (props.invisible ? `visibility: hidden;` : null)};
&:hover {
cursor: pointer;
+ ${(props) =>
+ !props.keepColors
+ ? `
path {
- fill: ${(props) => props.theme.colors.icon.hover};
+ fill: ${props.theme.colors.icon.hover};
}
+ `
+ : ""}
}
&:active {
@@ -182,6 +206,7 @@ export type IconProps = {
className?: string;
onClick?: (e: React.MouseEvent) => void;
fillColor?: string;
+ keepColors?: boolean;
};
const Icon = forwardRef(
@@ -191,9 +216,21 @@ const Icon = forwardRef(
case "book":
returnIcon = ;
break;
+ case "bug":
+ returnIcon = ;
+ break;
+ case "cancel":
+ returnIcon = ;
+ break;
+ case "cross":
+ returnIcon = ;
+ break;
case "delete":
returnIcon = ;
break;
+ case "open":
+ returnIcon = ;
+ break;
case "user":
returnIcon = ;
break;
@@ -233,6 +270,9 @@ const Icon = forwardRef(
case "rocket":
returnIcon = ;
break;
+ case "wand":
+ returnIcon = ;
+ break;
case "workspace":
returnIcon = ;
break;
@@ -263,6 +303,9 @@ const Icon = forwardRef(
case "warning":
returnIcon = ;
break;
+ case "warning-triangle":
+ returnIcon = ;
+ break;
case "arrow-left":
returnIcon = ;
break;
@@ -321,7 +364,7 @@ const Icon = forwardRef(
case "PARAGRAPH":
case "PARAGRAPH_TWO":
const ControlIcon = ControlIcons[props.name];
- returnIcon = ;
+ returnIcon = ;
break;
default:
diff --git a/app/client/src/components/ads/IconSelector.tsx b/app/client/src/components/ads/IconSelector.tsx
index e71b7f6317..61b0632d26 100644
--- a/app/client/src/components/ads/IconSelector.tsx
+++ b/app/client/src/components/ads/IconSelector.tsx
@@ -58,7 +58,7 @@ const IconBox = styled.div<{ selectedColor?: string }>`
: null};
`;
-const IconSelector = (props: IconSelectorProps) => {
+function IconSelector(props: IconSelectorProps) {
const iconRef = useRef(null);
const [selected, setSelected] = useState(firstSelectedIcon());
const iconPaletteRef = React.createRef();
@@ -87,8 +87,8 @@ const IconSelector = (props: IconSelectorProps) => {
return (
{props.iconPalette &&
@@ -96,19 +96,19 @@ const IconSelector = (props: IconSelectorProps) => {
return (
{
if (iconName !== selected) {
setSelected(iconName);
props.onSelect && props.onSelect(iconName);
}
}}
+ selectedColor={selected === iconName ? props.selectedColor : ""}
>
@@ -117,7 +117,7 @@ const IconSelector = (props: IconSelectorProps) => {
);
-};
+}
IconSelector.defaultProps = {
fill: false,
diff --git a/app/client/src/components/ads/IconTabsComponent.tsx b/app/client/src/components/ads/IconTabsComponent.tsx
index 36dea7abc2..0ea7d8e293 100644
--- a/app/client/src/components/ads/IconTabsComponent.tsx
+++ b/app/client/src/components/ads/IconTabsComponent.tsx
@@ -38,7 +38,7 @@ interface IconTabsComponentProps {
selectOption: (value: string) => void;
}
-const IconTabsComponent = (props: IconTabsComponentProps) => {
+function IconTabsComponent(props: IconTabsComponentProps) {
return (
{props.options.map((option: IconTabOption, index: number) => {
@@ -47,17 +47,17 @@ const IconTabsComponent = (props: IconTabsComponentProps) => {
const isSelected = props.value === option.value;
return (
props.selectOption(option.value)}
className={`t--icon-tab-${option.value}`}
+ key={index}
+ onClick={() => props.selectOption(option.value)}
+ selected={isSelected}
>
-
+
);
})}
);
-};
+}
export default IconTabsComponent;
diff --git a/app/client/src/components/ads/Menu.tsx b/app/client/src/components/ads/Menu.tsx
index 116dcfed15..dc3437cba9 100644
--- a/app/client/src/components/ads/Menu.tsx
+++ b/app/client/src/components/ads/Menu.tsx
@@ -24,18 +24,18 @@ const MenuOption = styled.div`
font-family: ${(props) => props.theme.fonts[3]};
`;
-const Menu = (props: MenuProps) => {
+function Menu(props: MenuProps) {
return (
{props.target}
@@ -46,6 +46,6 @@ const Menu = (props: MenuProps) => {
);
-};
+}
export default Menu;
diff --git a/app/client/src/components/ads/MenuItem.tsx b/app/client/src/components/ads/MenuItem.tsx
index cf0b12e76c..6bf988dfa9 100644
--- a/app/client/src/components/ads/MenuItem.tsx
+++ b/app/client/src/components/ads/MenuItem.tsx
@@ -90,7 +90,7 @@ const IconContainer = styled.span`
const MenuItem = forwardRef(
(props: MenuItemProps, ref: Ref) => {
return props.ellipsize && props.text.length > props.ellipsize ? (
-
+
) : (
@@ -102,13 +102,13 @@ const MenuItemContent = forwardRef(
(props: MenuItemProps, ref: Ref) => {
return (
{props.icon ? : null}
diff --git a/app/client/src/components/ads/MultiSwitch.tsx b/app/client/src/components/ads/MultiSwitch.tsx
index e1382bafff..1e08617841 100644
--- a/app/client/src/components/ads/MultiSwitch.tsx
+++ b/app/client/src/components/ads/MultiSwitch.tsx
@@ -55,10 +55,10 @@ export default function MultiSwitch(props: MultiSwitchProps) {
{props.tabs.map((tab) => (
props.onSelect(tab.title)}
+ selected={props.selected.value === tab.key}
>
-
+
{tab.title}
diff --git a/app/client/src/components/ads/MultiselectDropdown.tsx b/app/client/src/components/ads/MultiselectDropdown.tsx
index d4c258a1fd..57b3a9d6e2 100644
--- a/app/client/src/components/ads/MultiselectDropdown.tsx
+++ b/app/client/src/components/ads/MultiselectDropdown.tsx
@@ -166,7 +166,7 @@ type DropdownProps = CommonComponentProps & {
selectAllQuantifier?: string;
};
-const MultiSelectDropdown = (props: DropdownProps) => {
+function MultiSelectDropdown(props: DropdownProps) {
const [isOpen, setIsOpen] = useState(false);
const [containerWidth, setContainerWidth] = useState("0px");
@@ -229,23 +229,23 @@ const MultiSelectDropdown = (props: DropdownProps) => {
return (
setIsOpen(state)}
boundary="scrollParent"
+ isOpen={isOpen && !props.disabled}
+ minimal
+ onInteraction={(state) => setIsOpen(state)}
+ position={Position.TOP_LEFT}
>
setIsOpen(!isOpen)}
className={props.className}
+ disabled={props.disabled}
+ isOpen={isOpen}
+ onClick={() => setIsOpen(!isOpen)}
>
{props.selected.length
@@ -260,12 +260,12 @@ const MultiSelectDropdown = (props: DropdownProps) => {
{props.options.map((option: DropdownOption, index: number) => {
return (
{
optionClickHandler(option.value as string);
}}
- className="t--multi-dropdown-option"
+ selected={isItemSelected(option.value)}
>
{option.icon ? (
@@ -288,6 +288,6 @@ const MultiSelectDropdown = (props: DropdownProps) => {
);
-};
+}
export default MultiSelectDropdown;
diff --git a/app/client/src/components/ads/Radio.tsx b/app/client/src/components/ads/Radio.tsx
index 8d21f828db..2d89c7e2d3 100644
--- a/app/client/src/components/ads/Radio.tsx
+++ b/app/client/src/components/ads/Radio.tsx
@@ -129,29 +129,29 @@ export default function RadioComponent(props: RadioProps) {
return (
onChangeHandler(e.target.value)}
className={props.className}
+ columns={props.columns}
+ data-cy={props.cypressSelector}
+ onChange={(e: any) => onChangeHandler(e.target.value)}
+ rows={props.rows}
>
{props.options.map((option: OptionProps, index: number) => (
{option.label}
option.onSelect && option.onSelect(e.target.value)}
type="radio"
value={option.value}
- disabled={props.disabled || option.disabled}
- onChange={(e) => option.onSelect && option.onSelect(e.target.value)}
- checked={selected === option.value}
- name="radio"
/>
-
+
))}
diff --git a/app/client/src/components/ads/RectangularSwitcher.tsx b/app/client/src/components/ads/RectangularSwitcher.tsx
index 179c662ea9..08228fb044 100644
--- a/app/client/src/components/ads/RectangularSwitcher.tsx
+++ b/app/client/src/components/ads/RectangularSwitcher.tsx
@@ -100,14 +100,13 @@ export default function Switch(props: SwitchProps) {
return (
) => {
if (!firstRender) {
@@ -115,8 +114,9 @@ export default function Switch(props: SwitchProps) {
}
onChangeHandler(e.target.checked);
}}
+ type="checkbox"
/>
-
+
Light
diff --git a/app/client/src/components/ads/ScrollIndicator.tsx b/app/client/src/components/ads/ScrollIndicator.tsx
index cc1c88a758..159164bc2d 100644
--- a/app/client/src/components/ads/ScrollIndicator.tsx
+++ b/app/client/src/components/ads/ScrollIndicator.tsx
@@ -47,7 +47,7 @@ interface Props {
right?: string;
mode?: "DARK" | "LIGHT";
}
-const ScrollIndicator = ({ containerRef, top, bottom, right }: Props) => {
+function ScrollIndicator({ containerRef, top, bottom, right }: Props) {
const [{ thumbPosition }, setThumbPosition] = useSpring<{
thumbPosition: number;
config: {
@@ -105,10 +105,10 @@ const ScrollIndicator = ({ containerRef, top, bottom, right }: Props) => {
return (
{
/>
);
-};
+}
export default ScrollIndicator;
diff --git a/app/client/src/components/ads/SearchInput.tsx b/app/client/src/components/ads/SearchInput.tsx
index f0feeb39b2..6a3e6f27c2 100644
--- a/app/client/src/components/ads/SearchInput.tsx
+++ b/app/client/src/components/ads/SearchInput.tsx
@@ -118,30 +118,30 @@ const SearchInput = forwardRef(
return (
-
+
setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onChange={memoizedChangeHandler}
+ onFocus={() => setIsFocused(true)}
+ placeholder={props.placeholder ? props.placeholder : ""}
/>
{searchValue && props.variant === SearchVariant.BACKGROUND ? (
setSearchValue("")}
+ size={IconSize.MEDIUM}
/>
) : null}
diff --git a/app/client/src/components/ads/Spinner.tsx b/app/client/src/components/ads/Spinner.tsx
index 4f1b24bcbd..a1e7cb7247 100644
--- a/app/client/src/components/ads/Spinner.tsx
+++ b/app/client/src/components/ads/Spinner.tsx
@@ -48,11 +48,11 @@ Spinner.defaultProp = {
export default function Spinner(props: SpinnerProp) {
return (
-
+
);
}
diff --git a/app/client/src/components/ads/StepComponent.tsx b/app/client/src/components/ads/StepComponent.tsx
index 8826f22b56..403fb24c77 100644
--- a/app/client/src/components/ads/StepComponent.tsx
+++ b/app/client/src/components/ads/StepComponent.tsx
@@ -63,7 +63,7 @@ interface StepComponentProps {
onChange: (value: number) => void;
}
-export const StepComponent = (props: StepComponentProps) => {
+export function StepComponent(props: StepComponentProps) {
function decrease() {
if (props.value < props.min) {
return;
@@ -80,11 +80,11 @@ export const StepComponent = (props: StepComponentProps) => {
}
return (
-
+
{props.displayFormat(props.value)}
-
+
);
-};
+}
export default StepComponent;
diff --git a/app/client/src/components/ads/Table.tsx b/app/client/src/components/ads/Table.tsx
index 4af94a42f1..fdfd1501be 100644
--- a/app/client/src/components/ads/Table.tsx
+++ b/app/client/src/components/ads/Table.tsx
@@ -138,8 +138,8 @@ function Table(props: TableProps) {
return (
{cell.render("Cell")}
diff --git a/app/client/src/components/ads/TableDropdown.tsx b/app/client/src/components/ads/TableDropdown.tsx
index a27b050d87..9afcbdbf92 100644
--- a/app/client/src/components/ads/TableDropdown.tsx
+++ b/app/client/src/components/ads/TableDropdown.tsx
@@ -1,14 +1,14 @@
-import React, { Fragment, useState } from "react";
-import { CommonComponentProps, Classes } from "./common";
-import Text, { TextType } from "./Text";
-import styled from "styled-components";
+import { Position } from "@blueprintjs/core/lib/esm/common/position";
import {
Popover,
PopoverInteractionKind,
} from "@blueprintjs/core/lib/esm/components/popover/popover";
-import { Position } from "@blueprintjs/core/lib/esm/common/position";
+import React, { useState } from "react";
+import styled from "styled-components";
+import { Classes, CommonComponentProps } from "./common";
import Icon, { IconSize } from "./Icon";
import Spinner from "./Spinner";
+import Text, { TextType } from "./Text";
type DropdownOption = {
name: string;
@@ -79,7 +79,7 @@ const Content = styled.div<{ isLoading?: boolean }>`
}
`;
-const TableDropdown = (props: DropdownProps) => {
+function TableDropdown(props: DropdownProps) {
const [selectedIndex, setSelectedIndex] = useState(props.selectedIndex);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState(
@@ -93,41 +93,37 @@ const TableDropdown = (props: DropdownProps) => {
setIsDropdownOpen(false);
};
- return (
-
- {props.isLoading ? (
-
- ) : (
- setIsDropdownOpen(state)}
- interactionKind={PopoverInteractionKind.CLICK}
- >
-
-
- {selectedOption.name}
-
-
-
-
- {props.options.map((el: DropdownOption, index: number) => (
- optionSelector(index)}
- >
- {el.name}
- {el.desc}
-
- ))}
-
-
- )}
-
+ return props.isLoading ? (
+
+ ) : (
+ setIsDropdownOpen(state)}
+ position={props.position || Position.BOTTOM_LEFT}
+ usePortal={false}
+ >
+
+
+ {selectedOption.name}
+
+
+
+
+ {props.options.map((el: DropdownOption, index: number) => (
+ optionSelector(index)}
+ >
+ {el.name}
+ {el.desc}
+
+ ))}
+
+
);
-};
+}
export default TableDropdown;
diff --git a/app/client/src/components/ads/Tabs.tsx b/app/client/src/components/ads/Tabs.tsx
index b5b9b40e80..a70206d531 100644
--- a/app/client/src/components/ads/Tabs.tsx
+++ b/app/client/src/components/ads/Tabs.tsx
@@ -17,9 +17,6 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
user-select: none;
border-radius: 0px;
height: 100%;
- .${Classes.ICON} {
- margin-right: ${(props) => props.theme.spaces[3]}px;
- }
.react-tabs {
height: 100%;
}
@@ -104,6 +101,9 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
const TabTitleWrapper = styled.div`
display: flex;
align-items: center;
+ .${Classes.ICON} {
+ margin-right: ${(props) => props.theme.spaces[3]}px;
+ }
`;
const TabTitle = styled.span`
@@ -130,17 +130,17 @@ type TabbedViewComponentType = CommonComponentProps & {
overflow?: boolean;
};
-export const TabComponent = (props: TabbedViewComponentType) => {
+export function TabComponent(props: TabbedViewComponentType) {
return (
{
props.onSelect && props.onSelect(index);
}}
+ selectedIndex={props.selectedIndex}
>
{props.tabs.map((tab) => (
@@ -163,4 +163,4 @@ export const TabComponent = (props: TabbedViewComponentType) => {
);
-};
+}
diff --git a/app/client/src/components/ads/TagInputComponent.tsx b/app/client/src/components/ads/TagInputComponent.tsx
index 79ad502e8c..38de855dc8 100644
--- a/app/client/src/components/ads/TagInputComponent.tsx
+++ b/app/client/src/components/ads/TagInputComponent.tsx
@@ -62,7 +62,7 @@ type TagInputProps = {
* On addition or removal of tags, passes the comman separated string to input.onChange prop
* @param props : TagInputProps
*/
-const TagInputComponent = (props: TagInputProps) => {
+function TagInputComponent(props: TagInputProps) {
const _values =
props.input.value && props.input.value.length > 0
? props.input.value.split(",")
@@ -145,25 +145,25 @@ const TagInputComponent = (props: TagInputProps) => {
return (
);
-};
+}
export default TagInputComponent;
diff --git a/app/client/src/components/ads/TextInput.tsx b/app/client/src/components/ads/TextInput.tsx
index 814670b05c..a7aee853bf 100644
--- a/app/client/src/components/ads/TextInput.tsx
+++ b/app/client/src/components/ads/TextInput.tsx
@@ -88,11 +88,11 @@ const StyledInput = styled((props) => {
return props.asyncControl ? (
) : (
-
+
);
})`
width: ${(props) => (props.fill ? "100%" : "320px")};
@@ -200,17 +200,17 @@ const TextInput = forwardRef(
return (
{ErrorMessage}
diff --git a/app/client/src/components/ads/Toast.tsx b/app/client/src/components/ads/Toast.tsx
index ad54862175..8685e03e1c 100644
--- a/app/client/src/components/ads/Toast.tsx
+++ b/app/client/src/components/ads/Toast.tsx
@@ -7,6 +7,8 @@ import { toast, ToastOptions, ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { ReduxActionType } from "constants/ReduxActionConstants";
import { useDispatch } from "react-redux";
+import { Colors } from "constants/Colors";
+import DebugButton from "components/editorComponents/Debugger/DebugCTA";
type ToastProps = ToastOptions &
CommonComponentProps & {
@@ -37,13 +39,13 @@ const WrappedToastContainer = styled.div`
top: 4em;
}
`;
-export const StyledToastContainer = (props: ToastOptions) => {
+export function StyledToastContainer(props: ToastOptions) {
return (
);
-};
+}
const ToastBody = styled.div<{
variant?: Variant;
@@ -59,7 +61,7 @@ const ToastBody = styled.div<{
justify-content: space-between;
overflow-wrap: anywhere;
- .${Classes.ICON} {
+ div > .${Classes.ICON} {
cursor: auto;
margin-right: ${(props) => props.theme.spaces[3]}px;
margin-top: ${(props) => props.theme.spaces[1] / 2}px;
@@ -104,31 +106,39 @@ const FlexContainer = styled.div`
align-items: flex-start;
`;
-const ToastComponent = (props: ToastProps & { undoAction?: () => void }) => {
+const StyledDebugButton = styled(DebugButton)`
+ margin-left: auto;
+`;
+
+function ToastComponent(props: ToastProps & { undoAction?: () => void }) {
const dispatch = useDispatch();
return (
{props.variant === Variant.success ? (
-
+
) : props.variant === Variant.warning ? (
) : null}
{props.variant === Variant.danger ? (
) : null}
- {props.text}
+
+ {props.text}
+ {props.variant === Variant.danger ? (
+
+ ) : null}
+
{props.onUndo || props.dispatchableAction ? (
{
if (props.dispatchableAction) {
dispatch(props.dispatchableAction);
@@ -137,6 +147,7 @@ const ToastComponent = (props: ToastProps & { undoAction?: () => void }) => {
props.undoAction && props.undoAction();
}
}}
+ type={TextType.H6}
>
UNDO
@@ -144,7 +155,7 @@ const ToastComponent = (props: ToastProps & { undoAction?: () => void }) => {
);
-};
+}
export const Toaster = {
show: (config: ToastProps) => {
diff --git a/app/client/src/components/ads/Toggle.tsx b/app/client/src/components/ads/Toggle.tsx
index 60ae853016..5ae09a22ff 100644
--- a/app/client/src/components/ads/Toggle.tsx
+++ b/app/client/src/components/ads/Toggle.tsx
@@ -126,21 +126,21 @@ export default function Toggle(props: ToggleProps) {
return (
) =>
onChangeHandler(e.target.checked)
}
+ type="checkbox"
/>
-
+
{props.isLoading ? (
diff --git a/app/client/src/components/ads/Tooltip.tsx b/app/client/src/components/ads/Tooltip.tsx
index 6c858528bd..da2b2d7b23 100644
--- a/app/client/src/components/ads/Tooltip.tsx
+++ b/app/client/src/components/ads/Tooltip.tsx
@@ -19,26 +19,26 @@ type TooltipProps = CommonComponentProps & {
minimal?: boolean;
};
-const TooltipComponent = (props: TooltipProps) => {
+function TooltipComponent(props: TooltipProps) {
return (
{props.children}
);
-};
+}
TooltipComponent.defaultProps = {
position: Position.TOP,
diff --git a/app/client/src/components/ads/TreeDropdown.tsx b/app/client/src/components/ads/TreeDropdown.tsx
index a25274362f..bede261783 100644
--- a/app/client/src/components/ads/TreeDropdown.tsx
+++ b/app/client/src/components/ads/TreeDropdown.tsx
@@ -169,10 +169,11 @@ export default function TreeDropdown(props: TreeDropdownProps) {
selectedOption.type === option.value;
return (
e.stopPropagation() },
}}
+ text={option.label}
>
{option.children && option.children.map(renderTreeOption)}
@@ -202,30 +202,30 @@ export default function TreeDropdown(props: TreeDropdownProps) {
const defaultToggle = (
);
return (
{
setIsOpen(false);
props.onMenuToggle && props.onMenuToggle(false);
}}
+ position={PopoverPosition.LEFT}
targetProps={{
onClick: (e: any) => {
setIsOpen(true);
diff --git a/app/client/src/components/ads/formFields/FieldError.tsx b/app/client/src/components/ads/formFields/FieldError.tsx
index a5459d0a67..5b5471d30c 100644
--- a/app/client/src/components/ads/formFields/FieldError.tsx
+++ b/app/client/src/components/ads/formFields/FieldError.tsx
@@ -20,7 +20,7 @@ type FormFieldErrorProps = {
className?: string;
};
-export const FormFieldError = (props: FormFieldErrorProps) => {
+export function FormFieldError(props: FormFieldErrorProps) {
return (
{
{props.error || " "}
);
-};
+}
export default FormFieldError;
diff --git a/app/client/src/components/ads/formFields/FormMessage.tsx b/app/client/src/components/ads/formFields/FormMessage.tsx
index 3dd062d8ab..cdfa07f01f 100644
--- a/app/client/src/components/ads/formFields/FormMessage.tsx
+++ b/app/client/src/components/ads/formFields/FormMessage.tsx
@@ -38,13 +38,13 @@ const StyledAction = styled.div<{ intent: Intent }>`
}
`;
-export const ActionButton = (props: MessageAction) => {
+export function ActionButton(props: MessageAction) {
if (props.url) {
const isExternal = props.url.indexOf("//") !== -1;
return (
{isExternal ? (
-
+
{props.text}
) : (
@@ -54,13 +54,13 @@ export const ActionButton = (props: MessageAction) => {
);
} else if (props.onClick) {
return (
-
+
{props.text}
);
}
return null;
-};
+}
export type FormMessageProps = {
intent: Intent;
@@ -68,18 +68,18 @@ export type FormMessageProps = {
actions?: MessageAction[];
};
-export const FormMessage = (props: FormMessageProps) => {
+export function FormMessage(props: FormMessageProps) {
const actions =
props.actions &&
props.actions.map((action) => (
));
return (
-
+
{props.message}
{actions && {actions} }
);
-};
+}
export default FormMessage;
diff --git a/app/client/src/components/ads/formFields/TextField.tsx b/app/client/src/components/ads/formFields/TextField.tsx
index cef1273bca..38df047f1d 100644
--- a/app/client/src/components/ads/formFields/TextField.tsx
+++ b/app/client/src/components/ads/formFields/TextField.tsx
@@ -17,10 +17,10 @@ const renderComponent = (
const showError = componentProps.meta.touched && !componentProps.meta.active;
return (
-
+ <>
-
+ >
);
};
@@ -34,12 +34,8 @@ type FormTextFieldProps = {
autoFocus?: boolean;
};
-const FormTextField = (props: FormTextFieldProps) => {
- return (
-
-
-
- );
-};
+function FormTextField(props: FormTextFieldProps) {
+ return ;
+}
export default FormTextField;
diff --git a/app/client/src/components/designSystems/appsmith/ChartComponent.tsx b/app/client/src/components/designSystems/appsmith/ChartComponent.tsx
index faccb28c53..ca49f9b40b 100644
--- a/app/client/src/components/designSystems/appsmith/ChartComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/ChartComponent.tsx
@@ -1,10 +1,10 @@
-import _, { isString } from "lodash";
+import _, { get } from "lodash";
import React from "react";
import styled from "styled-components";
import { getBorderCSSShorthand, invisible } from "constants/DefaultTheme";
import { getAppsmithConfigs } from "configs";
-import { ChartData, ChartDataPoint, ChartType } from "widgets/ChartWidget";
+import { AllChartData, ChartDataPoint, ChartType } from "widgets/ChartWidget";
import log from "loglevel";
export interface CustomFusionChartConfig {
@@ -43,7 +43,7 @@ FusionCharts.options.license({
export interface ChartComponentProps {
chartType: ChartType;
- chartData: ChartData[];
+ chartData: AllChartData;
customFusionChartConfig: CustomFusionChartConfig;
xAxisName: string;
yAxisName: string;
@@ -73,7 +73,8 @@ class ChartComponent extends React.Component {
getChartType = () => {
const { chartType, allowHorizontalScroll, chartData } = this.props;
- const isMSChart = chartData.length > 1;
+ const dataLength = Object.keys(chartData).length;
+ const isMSChart = dataLength > 1;
switch (chartType) {
case "PIE_CHART":
return "pie2d";
@@ -107,9 +108,11 @@ class ChartComponent extends React.Component {
};
getChartData = () => {
- const chartData: ChartData[] = this.props.chartData;
+ const chartData: AllChartData = this.props.chartData;
+ const dataLength = Object.keys(chartData).length;
- if (chartData.length === 0) {
+ // if datalength is zero, just pass a empty datum
+ if (dataLength === 0) {
return [
{
label: "",
@@ -118,14 +121,13 @@ class ChartComponent extends React.Component {
];
}
- let data: ChartDataPoint[] = chartData[0].data;
- if (isString(chartData[0].data)) {
- try {
- data = JSON.parse(chartData[0].data);
- } catch (e) {
- data = [];
- }
+ const firstKey = Object.keys(chartData)[0] as string;
+ let data = get(chartData, `${firstKey}.data`, []) as ChartDataPoint[];
+
+ if (!Array.isArray(data)) {
+ data = [];
}
+
if (data.length === 0) {
return [
{
@@ -134,6 +136,7 @@ class ChartComponent extends React.Component {
},
];
}
+
return data.map((item) => {
return {
label: item.x,
@@ -142,22 +145,30 @@ class ChartComponent extends React.Component {
});
};
- getChartCategoriesMutliSeries = (chartData: ChartData[]) => {
+ getChartCategoriesMutliSeries = (chartData: AllChartData) => {
const categories: string[] = [];
- for (let index = 0; index < chartData.length; index++) {
- const data: ChartDataPoint[] = chartData[index].data;
+
+ Object.keys(chartData).forEach((key: string) => {
+ let data = get(chartData, `${key}.data`, []) as ChartDataPoint[];
+
+ if (!Array.isArray(data)) {
+ data = [];
+ }
+
for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {
const category = data[dataIndex].x;
if (!categories.includes(category)) {
categories.push(category);
}
}
- }
+ });
+
return categories;
};
- getChartCategories = (chartData: ChartData[]) => {
+ getChartCategories = (chartData: AllChartData) => {
const categories: string[] = this.getChartCategoriesMutliSeries(chartData);
+
if (categories.length === 0) {
return [
{
@@ -192,9 +203,18 @@ class ChartComponent extends React.Component {
});
};
- getChartDataset = (chartData: ChartData[]) => {
+ /**
+ * creates dataset need by fusion chart from widget object-data
+ *
+ * @param chartData
+ * @returns
+ */
+ getChartDataset = (chartData: AllChartData) => {
const categories: string[] = this.getChartCategoriesMutliSeries(chartData);
- return chartData.map((item: ChartData) => {
+
+ const dataset = Object.keys(chartData).map((key: string) => {
+ const item = get(chartData, `${key}`);
+
const seriesChartData: Array {
data: seriesChartData,
};
});
+
+ return dataset;
};
getChartConfig = () => {
@@ -219,10 +241,9 @@ class ChartComponent extends React.Component {
};
getChartDataSource = () => {
- if (
- this.props.chartData.length <= 1 ||
- this.props.chartType === "PIE_CHART"
- ) {
+ const dataLength = Object.keys(this.props.chartData).length;
+
+ if (dataLength <= 1 || this.props.chartType === "PIE_CHART") {
return {
chart: this.getChartConfig(),
data: this.getChartData(),
diff --git a/app/client/src/components/designSystems/appsmith/ContainerComponent.tsx b/app/client/src/components/designSystems/appsmith/ContainerComponent.tsx
index dcc2dc0c09..16cc613961 100644
--- a/app/client/src/components/designSystems/appsmith/ContainerComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/ContainerComponent.tsx
@@ -25,13 +25,16 @@ const StyledContainerComponent = styled.div<
background: ${(props) => props.backgroundColor};
${(props) => (!props.isVisible ? invisible : "")};
+ opacity: ${(props) => (props.resizeDisabled ? "0.5" : "1")};
+ pointer-events: ${(props) => (props.resizeDisabled ? "none" : "inherit")};
overflow: hidden;
${(props) => (props.shouldScrollContents ? scrollContents : "")}
}`;
-const ContainerComponent = (props: ContainerComponentProps) => {
+function ContainerComponent(props: ContainerComponentProps) {
const containerStyle = props.containerStyle || "card";
const containerRef: RefObject = useRef(null);
+
useEffect(() => {
if (!props.shouldScrollContents) {
const supportsNativeSmoothScroll =
@@ -48,18 +51,18 @@ const ContainerComponent = (props: ContainerComponentProps) => {
return (
{props.children}
);
-};
+}
export type ContainerStyle = "border" | "card" | "rounded-border" | "none";
@@ -69,6 +72,7 @@ export interface ContainerComponentProps extends ComponentProps {
className?: string;
backgroundColor?: Color;
shouldScrollContents?: boolean;
+ resizeDisabled?: boolean;
}
export default ContainerComponent;
diff --git a/app/client/src/components/designSystems/appsmith/CopyToClipBoard.tsx b/app/client/src/components/designSystems/appsmith/CopyToClipBoard.tsx
index cbcf6cda22..c7719d08c8 100644
--- a/app/client/src/components/designSystems/appsmith/CopyToClipBoard.tsx
+++ b/app/client/src/components/designSystems/appsmith/CopyToClipBoard.tsx
@@ -19,7 +19,7 @@ const Wrapper = styled.div`
}
`;
-const CopyToClipboard = (props: any) => {
+function CopyToClipboard(props: any) {
const { copyText } = props;
const copyURLInput = createRef();
const [isCopied, setIsCopied] = useState(false);
@@ -40,22 +40,22 @@ const CopyToClipboard = (props: any) => {
return (
{
selectText();
}}
- defaultValue={copyText}
/>
{
copyToClipboard(copyText);
}}
+ text={isCopied ? "Copied" : "Copy"}
/>
);
-};
+}
export default CopyToClipboard;
diff --git a/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx b/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx
index 4fb0345d34..d6465d62a9 100644
--- a/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx
+++ b/app/client/src/components/designSystems/appsmith/CreatableDropdown.tsx
@@ -94,12 +94,14 @@ class CreatableDropdown extends React.Component {
return (
input.value}
onChange={(value) => {
const formattedValue = value;
if (formattedValue && formattedValue.length > 1) {
@@ -108,8 +110,6 @@ class CreatableDropdown extends React.Component {
input.onChange(formattedValue);
}}
- onBlur={() => input.value}
- isClearable
{...optionalProps}
/>
);
diff --git a/app/client/src/components/designSystems/appsmith/DraggableListComponent.tsx b/app/client/src/components/designSystems/appsmith/DraggableListComponent.tsx
index 313233f5e0..ca1fb37219 100644
--- a/app/client/src/components/designSystems/appsmith/DraggableListComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/DraggableListComponent.tsx
@@ -100,8 +100,8 @@ export class DroppableComponent extends React.Component<
return (
{({ innerRef, draggableProps, dragHandleProps }) => (
({}),
};
-export const BaseDropdown = (props: DropdownProps) => {
+export function BaseDropdown(props: DropdownProps) {
const { input, customSelectStyles } = props;
return (
input.onChange(value)}
- isSearchable={props.isSearchable}
isDisabled={props.isDisabled}
+ isSearchable={props.isSearchable}
+ onChange={(value) => input.onChange(value)}
+ width={props.width}
{...props}
/>
);
-};
+}
-const Dropdown = (props: DropdownProps) => {
+function Dropdown(props: DropdownProps) {
return ;
-};
+}
export default Dropdown;
diff --git a/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx b/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx
index fb241629c1..834ef89be8 100644
--- a/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/FilePickerComponent.tsx
@@ -26,16 +26,14 @@ class FilePickerComponent extends React.Component<
label = `${this.props.files.length} files selected`;
}
return (
-
-
-
+
);
}
diff --git a/app/client/src/components/designSystems/appsmith/IconComponent.tsx b/app/client/src/components/designSystems/appsmith/IconComponent.tsx
index 14058919bf..33364043f2 100644
--- a/app/client/src/components/designSystems/appsmith/IconComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/IconComponent.tsx
@@ -8,15 +8,15 @@ class IconComponent extends React.Component {
render() {
return (
);
}
diff --git a/app/client/src/components/designSystems/appsmith/ImageComponent.tsx b/app/client/src/components/designSystems/appsmith/ImageComponent.tsx
index dd66dc6154..ee3ea08429 100644
--- a/app/client/src/components/designSystems/appsmith/ImageComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/ImageComponent.tsx
@@ -74,29 +74,18 @@ class ImageComponent extends React.Component<
{
- this.props.disableDrag(true);
+ doubleClick={{
+ disabled: true,
}}
onPanning={() => {
this.isPanning = true;
}}
+ onPanningStart={() => {
+ this.props.disableDrag(true);
+ }}
onPanningStop={() => {
this.props.disableDrag(false);
}}
- options={{
- maxScale: maxZoomLevel,
- disabled: !zoomActive,
- transformEnabled: zoomActive,
- }}
- pan={{
- disabled: !zoomActive,
- }}
- wheel={{
- disabled: !zoomActive,
- }}
- doubleClick={{
- disabled: true,
- }}
onZoomChange={(zoom: any) => {
if (zoomActive) {
//Check max zoom
@@ -119,42 +108,51 @@ class ImageComponent extends React.Component<
}
}
}}
+ options={{
+ maxScale: maxZoomLevel,
+ disabled: !zoomActive,
+ transformEnabled: zoomActive,
+ }}
+ pan={{
+ disabled: !zoomActive,
+ }}
+ wheel={{
+ disabled: !zoomActive,
+ }}
>
{({ zoomIn, zoomOut }: any) => (
-
-
- ) => {
- if (!this.isPanning) {
- if (isZoomingIn) {
- zoomIn(event);
- } else {
- zoomOut(event);
- }
- this.props.onClick && this.props.onClick(event);
+
+ ) => {
+ if (!this.isPanning) {
+ if (isZoomingIn) {
+ zoomIn(event);
+ } else {
+ zoomOut(event);
}
- this.isPanning = false;
+ this.props.onClick && this.props.onClick(event);
+ }
+ this.isPanning = false;
+ }}
+ style={{
+ cursor,
+ }}
+ >
+
-
-
-
-
+ />
+
+
)}
diff --git a/app/client/src/components/designSystems/appsmith/MapComponent.tsx b/app/client/src/components/designSystems/appsmith/MapComponent.tsx
index d7083f085f..6b74f1a829 100644
--- a/app/client/src/components/designSystems/appsmith/MapComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/MapComponent.tsx
@@ -115,6 +115,12 @@ const MyMapComponent = withGoogleMap((props: any) => {
}, [props.center, props.selectedMarker]);
return (
{
+ if (props.enableCreateMarker) {
+ props.saveMarker(e.latLng.lat(), e.latLng.lng());
+ }
+ }}
options={{
zoomControl: props.allowZoom,
fullscreenControl: false,
@@ -124,12 +130,6 @@ const MyMapComponent = withGoogleMap((props: any) => {
streetViewControl: false,
}}
zoom={props.zoom}
- center={mapCenter}
- onClick={(e) => {
- if (props.enableCreateMarker) {
- props.saveMarker(e.latLng.lat(), e.latLng.lng());
- }
- }}
>
{props.enableSearch && (
{
onPlacesChanged={onPlacesChanged}
ref={searchBox}
>
-
+
)}
- {props.markers.map((marker: any, index: number) => (
- {
- setMapCenter({
- ...marker,
- lng: marker.long,
- });
- props.selectMarker(marker.lat, marker.long, marker.title);
- }}
- onDragEnd={(de) => {
- props.updateMarker(de.latLng.lat(), de.latLng.lng(), index);
- }}
- />
- ))}
+ {Array.isArray(props.markers) &&
+ props.markers.map((marker: MarkerProps, index: number) => (
+ {
+ setMapCenter({
+ ...marker,
+ lng: marker.long,
+ });
+ props.selectMarker(marker.lat, marker.long, marker.title);
+ }}
+ onDragEnd={(de) => {
+ props.updateMarker(de.latLng.lat(), de.latLng.lng(), index);
+ }}
+ position={{ lat: marker.lat, lng: marker.long }}
+ title={marker.title}
+ />
+ ))}
{props.enablePickLocation && (
@@ -175,7 +176,7 @@ const MyMapComponent = withGoogleMap((props: any) => {
);
});
-const MapComponent = (props: MapComponentProps) => {
+function MapComponent(props: MapComponentProps) {
const zoom = Math.floor(props.zoomLevel / 5);
const status = useScript(
`https://maps.googleapis.com/maps/api/js?key=${props.apiKey}&v=3.exp&libraries=geometry,drawing,places`,
@@ -185,8 +186,8 @@ const MapComponent = (props: MapComponentProps) => {
{status === ScriptStatus.READY && (
}
containerElement={ }
+ loadingElement={ }
mapElement={ }
{...props}
zoom={zoom}
@@ -194,6 +195,6 @@ const MapComponent = (props: MapComponentProps) => {
)}
);
-};
+}
export default MapComponent;
diff --git a/app/client/src/components/designSystems/appsmith/PopoverVideo.tsx b/app/client/src/components/designSystems/appsmith/PopoverVideo.tsx
index dc4d490fa0..c60737f857 100644
--- a/app/client/src/components/designSystems/appsmith/PopoverVideo.tsx
+++ b/app/client/src/components/designSystems/appsmith/PopoverVideo.tsx
@@ -26,16 +26,14 @@ const PlayerWrapper = styled.div` import React, { Ref } from "react";
height: 400px;
`;
-const PopoverVideo = (props: VideoComponentProps) => {
+function PopoverVideo(props: VideoComponentProps) {
return (
e.stopPropagation()}>
{
boundariesElement: "viewport",
},
}}
+ position={PopoverPosition.AUTO}
+ usePortal
>
-
+
);
-};
+}
export default PopoverVideo;
diff --git a/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx b/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx
index 46a845f2f2..db47d63a73 100644
--- a/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx
+++ b/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from "react";
+import React, { CSSProperties, ReactNode, useMemo } from "react";
import { BaseStyle } from "widgets/BaseWidget";
import { WIDGET_PADDING } from "constants/WidgetConstants";
import { generateClassName } from "utils/generators";
@@ -17,38 +17,46 @@ type PositionedContainerProps = {
widgetType: string;
};
-export const PositionedContainer = (props: PositionedContainerProps) => {
+export function PositionedContainer(props: PositionedContainerProps) {
const x = props.style.xPosition + (props.style.xPositionUnit || "px");
const y = props.style.yPosition + (props.style.yPositionUnit || "px");
const padding = WIDGET_PADDING;
const openPropertyPane = useClickOpenPropPane();
+ // memoized classname
+ const containerClassName = useMemo(() => {
+ return (
+ generateClassName(props.widgetId) +
+ " positioned-widget " +
+ `t--widget-${props.widgetType
+ .split("_")
+ .join("")
+ .toLowerCase()}`
+ );
+ }, [props.widgetType, props.widgetId]);
+ const containerStyle: CSSProperties = useMemo(() => {
+ return {
+ position: "absolute",
+ left: x,
+ top: y,
+ height: props.style.componentHeight + (props.style.heightUnit || "px"),
+ width: props.style.componentWidth + (props.style.widthUnit || "px"),
+ padding: padding + "px",
+ };
+ }, [props.style]);
+
return (
{props.children}
);
-};
+}
PositionedContainer.padding = WIDGET_PADDING;
diff --git a/app/client/src/components/designSystems/appsmith/RichTextEditorComponent.tsx b/app/client/src/components/designSystems/appsmith/RichTextEditorComponent.tsx
index 0c8aad75bd..9ef2b16f57 100644
--- a/app/client/src/components/designSystems/appsmith/RichTextEditorComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/RichTextEditorComponent.tsx
@@ -21,9 +21,7 @@ export interface RichtextEditorComponentProps {
isVisible?: boolean;
onValueChange: (valueAsString: string) => void;
}
-export const RichtextEditorComponent = (
- props: RichtextEditorComponentProps,
-) => {
+export function RichtextEditorComponent(props: RichtextEditorComponentProps) {
const status = useScript(
"https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.0/tinymce.min.js",
);
@@ -110,9 +108,9 @@ export const RichtextEditorComponent = (
return (
-
+
);
-};
+}
export default RichtextEditorComponent;
diff --git a/app/client/src/components/designSystems/appsmith/SearchComponent.tsx b/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
index 02b56c0036..8a6c10f677 100644
--- a/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
@@ -53,9 +53,9 @@ class SearchComponent extends React.Component<
return (
);
diff --git a/app/client/src/components/designSystems/appsmith/StepComponent.tsx b/app/client/src/components/designSystems/appsmith/StepComponent.tsx
index 13c003a745..5c7cdda795 100644
--- a/app/client/src/components/designSystems/appsmith/StepComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/StepComponent.tsx
@@ -68,7 +68,7 @@ interface StepComponentProps {
onChange: (value: number) => void;
}
-export const StepComponent = (props: StepComponentProps) => {
+export function StepComponent(props: StepComponentProps) {
function decrease() {
if (props.value < props.min) {
return;
@@ -85,11 +85,11 @@ export const StepComponent = (props: StepComponentProps) => {
}
return (
-
+
{props.displayFormat(props.value)}
-
+
);
-};
+}
export default StepComponent;
diff --git a/app/client/src/components/designSystems/appsmith/TabbedView.tsx b/app/client/src/components/designSystems/appsmith/TabbedView.tsx
index e1c364997a..450d748144 100644
--- a/app/client/src/components/designSystems/appsmith/TabbedView.tsx
+++ b/app/client/src/components/designSystems/appsmith/TabbedView.tsx
@@ -49,14 +49,14 @@ type TabbedViewComponentType = {
overflow?: boolean;
};
-export const BaseTabbedView = (props: TabbedViewComponentType) => {
+export function BaseTabbedView(props: TabbedViewComponentType) {
return (
{
props.setSelectedIndex && props.setSelectedIndex(index);
}}
+ selectedIndex={props.selectedIndex}
>
{props.tabs.map((tab) => (
@@ -69,4 +69,4 @@ export const BaseTabbedView = (props: TabbedViewComponentType) => {
);
-};
+}
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/AutoToolTipComponent.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/AutoToolTipComponent.tsx
index 1bde35098c..f8f9d93fba 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/AutoToolTipComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/AutoToolTipComponent.tsx
@@ -28,7 +28,7 @@ interface Props {
columnType?: string;
}
-const LinkWrapper = (props: Props) => {
+function LinkWrapper(props: Props) {
const ref = createRef();
const [useToolTip, updateToolTip] = useState(false);
useEffect(() => {
@@ -41,24 +41,24 @@ const LinkWrapper = (props: Props) => {
}, [ref]);
return (
{
window.open(props.title, "_blank");
}}
+ useLinkToolTip={useToolTip}
>
-
+
{useToolTip && props.children ? (
{props.title}
}
+ hoverOpenDelay={1000}
position="top"
>
{props.children}
@@ -72,9 +72,9 @@ const LinkWrapper = (props: Props) => {
);
-};
+}
-const AutoToolTipComponent = (props: Props) => {
+function AutoToolTipComponent(props: Props) {
const ref = createRef();
const [useToolTip, updateToolTip] = useState(false);
useEffect(() => {
@@ -90,19 +90,19 @@ const AutoToolTipComponent = (props: Props) => {
}
return (
{useToolTip && props.children ? (
{props.title}
}
+ hoverOpenDelay={1000}
position="top"
>
{props.children}
@@ -112,6 +112,6 @@ const AutoToolTipComponent = (props: Props) => {
)}
);
-};
+}
export default AutoToolTipComponent;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/CascadeFields.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/CascadeFields.tsx
index 22e8fb3d2e..a71efe4e15 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/CascadeFields.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/CascadeFields.tsx
@@ -169,27 +169,23 @@ const columnTypeNameMap: Record = {
[ColumnTypes.URL]: "Url",
};
-const RenderOption = (props: {
- type: string;
- title: string;
- active: boolean;
-}) => {
+function RenderOption(props: { type: string; title: string; active: boolean }) {
return (
{props.title}
{columnTypeNameMap[props.type as ColumnTypes]}
);
-};
+}
-const RenderOptions = (props: {
+function RenderOptions(props: {
columns: DropdownOption[];
selectItem: (column: DropdownOption) => void;
placeholder: string;
value?: string | Condition;
showType?: boolean;
className?: string;
-}) => {
+}) {
const [selectedValue, selectValue] = useState(props.placeholder);
const configs = {
sections: [
@@ -199,9 +195,9 @@ const RenderOptions = (props: {
return {
content: props.showType ? (
) : (
column.label
@@ -223,7 +219,7 @@ const RenderOptions = (props: {
{selectedValue}
-
+
),
},
@@ -244,13 +240,13 @@ const RenderOptions = (props: {
}
}, [props.value, props.placeholder, props.columns]);
return ;
-};
+}
-const RenderInput = (props: {
+function RenderInput(props: {
value: string;
onChange: (value: string) => void;
className?: string;
-}) => {
+}) {
const debouncedOnChange = useCallback(debounce(props.onChange, 400), []);
const [value, setValue] = useState(props.value);
const onChange = (event: React.ChangeEvent) => {
@@ -263,14 +259,14 @@ const RenderInput = (props: {
}, [props.value]);
return (
);
-};
+}
type CascadeFieldProps = {
columns: DropdownOption[];
@@ -429,14 +425,14 @@ function CaseCaseFieldReducer(
}
}
-const CascadeField = (props: CascadeFieldProps) => {
+function CascadeField(props: CascadeFieldProps) {
const memoizedState = React.useMemo(() => calculateInitialState(props), [
props,
]);
return ;
-};
+}
-const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
+function Fields(props: CascadeFieldProps & { state: CascadeFieldState }) {
const { index, removeFilter, applyFilter, hasAnyFilters } = props;
const [state, dispatch] = React.useReducer(CaseCaseFieldReducer, props.state);
const handleRemoveFilter = () => {
@@ -513,22 +509,22 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
return (
{index === 1 ? (
) : (
@@ -538,22 +534,22 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
)}
{showConditions ? (
) : null}
@@ -567,20 +563,20 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
{showDateInput ? (
) : null}
);
-};
+}
export default CascadeField;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.test.ts b/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.test.ts
index 61c8a10b96..026291ff16 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.test.ts
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.test.ts
@@ -1,5 +1,11 @@
-import { sortTableFunction } from "components/designSystems/appsmith/TableComponent/CommonUtilities";
-import { ColumnTypes } from "components/designSystems/appsmith/TableComponent/Constants";
+import {
+ sortTableFunction,
+ transformTableDataIntoCsv,
+} from "components/designSystems/appsmith/TableComponent/CommonUtilities";
+import {
+ ColumnTypes,
+ TableColumnProps,
+} from "components/designSystems/appsmith/TableComponent/Constants";
describe("TableUtilities", () => {
it("works as expected for sort table rows", () => {
@@ -29,3 +35,82 @@ describe("TableUtilities", () => {
expect(sortedTableData).toStrictEqual(expected);
});
});
+
+describe("TransformTableDataIntoArrayOfArray", () => {
+ const columns: TableColumnProps[] = [
+ {
+ Header: "Id",
+ accessor: "id",
+ minWidth: 60,
+ draggable: true,
+ metaProperties: {
+ isHidden: false,
+ type: "string",
+ },
+ columnProperties: {
+ id: "id",
+ label: "Id",
+ columnType: "string",
+ isVisible: true,
+ index: 0,
+ width: 60,
+ isDerived: false,
+ computedValue: "",
+ },
+ },
+ ];
+ it("work as expected", () => {
+ const data = [
+ {
+ id: "abc",
+ },
+ {
+ id: "xyz",
+ },
+ ];
+ const csvData = transformTableDataIntoCsv({
+ columns,
+ data,
+ });
+ const expectedCsvData = [["Id"], ["abc"], ["xyz"]];
+ expect(JSON.stringify(csvData)).toStrictEqual(
+ JSON.stringify(expectedCsvData),
+ );
+ });
+ it("work as expected with newline", () => {
+ const data = [
+ {
+ id: "abc\ntest",
+ },
+ {
+ id: "xyz",
+ },
+ ];
+ const csvData = transformTableDataIntoCsv({
+ columns,
+ data,
+ });
+ const expectedCsvData = [["Id"], ["abc test"], ["xyz"]];
+ expect(JSON.stringify(csvData)).toStrictEqual(
+ JSON.stringify(expectedCsvData),
+ );
+ });
+ it("work as expected with comma", () => {
+ const data = [
+ {
+ id: "abc,test",
+ },
+ {
+ id: "xyz",
+ },
+ ];
+ const csvData = transformTableDataIntoCsv({
+ columns,
+ data,
+ });
+ const expectedCsvData = [["Id"], ['"abc,test"'], ["xyz"]];
+ expect(JSON.stringify(csvData)).toStrictEqual(
+ JSON.stringify(expectedCsvData),
+ );
+ });
+});
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.ts b/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.ts
index b6396d1363..fcce5b042b 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.ts
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/CommonUtilities.ts
@@ -1,5 +1,8 @@
-import { ColumnTypes } from "components/designSystems/appsmith/TableComponent/Constants";
-import { isPlainObject, isNil } from "lodash";
+import {
+ ColumnTypes,
+ TableColumnProps,
+} from "components/designSystems/appsmith/TableComponent/Constants";
+import { isPlainObject, isNil, isString } from "lodash";
import moment from "moment";
export function sortTableFunction(
@@ -51,3 +54,41 @@ export function sortTableFunction(
},
);
}
+
+export const transformTableDataIntoCsv = (props: {
+ columns: TableColumnProps[];
+ data: Array>;
+}) => {
+ const csvData = [];
+ csvData.push(
+ props.columns
+ .map((column: TableColumnProps) => {
+ if (column.metaProperties && !column.metaProperties.isHidden) {
+ return column.Header;
+ }
+ return null;
+ })
+ .filter((i) => !!i),
+ );
+ for (let row = 0; row < props.data.length; row++) {
+ const data: { [key: string]: any } = props.data[row];
+ const csvDataRow = [];
+ for (let colIndex = 0; colIndex < props.columns.length; colIndex++) {
+ const column = props.columns[colIndex];
+ let value = data[column.accessor];
+ if (column.metaProperties && !column.metaProperties.isHidden) {
+ value =
+ isString(value) && value.includes("\n")
+ ? value.replace("\n", " ")
+ : value;
+ if (isString(value) && value.includes(",")) {
+ csvDataRow.push(`"${value}"`);
+ } else {
+ csvDataRow.push(value);
+ }
+ }
+ }
+ csvData.push(csvDataRow);
+ }
+ return csvData;
+};
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts b/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts
index 0d3b923849..1b99cdc16a 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/Constants.ts
@@ -103,7 +103,7 @@ export interface TableColumnMetaProps {
type: string;
}
-export interface ReactTableColumnProps {
+export interface TableColumnProps {
Header: string;
accessor: string;
width?: number;
@@ -114,6 +114,8 @@ export interface ReactTableColumnProps {
metaProperties?: TableColumnMetaProps;
isDerived?: boolean;
columnProperties: ColumnProperties;
+}
+export interface ReactTableColumnProps extends TableColumnProps {
Cell: (props: any) => JSX.Element;
}
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/Table.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/Table.tsx
index f5a59db89e..72d664c25f 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/Table.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/Table.tsx
@@ -62,7 +62,7 @@ const defaultColumn = {
width: 150,
};
-export const Table = (props: TableProps) => {
+export function Table(props: TableProps) {
const isResizingColumn = React.useRef(false);
const tableWrapperRef = React.useRef(null);
@@ -142,45 +142,45 @@ export const Table = (props: TableProps) => {
/* Subtracting 9px to handling widget padding */
return (
{
return column.accessor !== "actions";
})}
- filters={props.filters}
- applyFilter={props.applyFilter}
- editMode={props.editMode}
compactMode={props.compactMode}
- updateCompactMode={props.updateCompactMode}
+ currentPageIndex={currentPageIndex}
+ editMode={props.editMode}
+ filters={props.filters}
+ nextPageClick={props.nextPageClick}
+ pageCount={pageCount}
+ pageNo={props.pageNo}
+ pageOptions={pageOptions}
+ prevPageClick={props.prevPageClick}
+ searchKey={props.searchKey}
+ searchTableData={props.searchTableData}
+ serverSidePaginationEnabled={props.serverSidePaginationEnabled}
+ tableColumns={props.columns}
+ tableData={props.data}
tableSizes={tableSizes}
+ updateCompactMode={props.updateCompactMode}
+ updatePageNo={props.updatePageNo}
+ widgetName={props.widgetName}
+ width={props.width}
/>
{headerGroups.map((headerGroup: any, index: number) => (
{
{headerGroup.headers.map((column: any, columnIndex: number) => {
return (
);
})}
@@ -233,20 +233,20 @@ export const Table = (props: TableProps) => {
: ""
}`
}
+ key={rowIndex}
onClick={() => {
row.toggleRowSelected();
props.selectTableRow(row);
}}
- key={rowIndex}
>
{row.cells.map((cell, cellIndex) => {
return (
{cell.render("Cell")}
@@ -269,6 +269,6 @@ export const Table = (props: TableProps) => {
);
-};
+}
export default Table;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableActionIcon.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableActionIcon.tsx
index ce07706469..d59cdacf23 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableActionIcon.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableActionIcon.tsx
@@ -13,30 +13,30 @@ interface TableActionIconProps {
icon?: React.ReactNode;
}
-const TableActionIcon = (props: TableActionIconProps) => {
+function TableActionIcon(props: TableActionIconProps) {
return (
{
props.selectMenu(!props.selected);
e.stopPropagation();
}}
- className={props.className}
+ selected={props.selected}
>
{props.children}
@@ -44,6 +44,6 @@ const TableActionIcon = (props: TableActionIconProps) => {
);
-};
+}
export default TableActionIcon;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableColumnsVisibility.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableColumnsVisibility.tsx
index 00127e099e..a6a14cc327 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableColumnsVisibility.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableColumnsVisibility.tsx
@@ -75,25 +75,25 @@ interface TableColumnsVisibilityProps {
updateHiddenColumns: (hiddenColumns?: string[]) => void;
}
-const VisibilityIcon = (props: { visible?: boolean }) => {
+function VisibilityIcon(props: { visible?: boolean }) {
return props.visible ? (
) : (
);
-};
+}
-const TableColumnsVisibility = (props: TableColumnsVisibilityProps) => {
+function TableColumnsVisibility(props: TableColumnsVisibilityProps) {
const [selected, selectMenu] = React.useState(false);
if (props.columns.length === 0) {
return (
-
+
@@ -106,30 +106,30 @@ const TableColumnsVisibility = (props: TableColumnsVisibilityProps) => {
);
return (
{
selectMenu(false);
}}
- isOpen={selected}
+ position={Position.BOTTOM}
+ usePortal
>
{
selectMenu(selected);
}}
+ selected={selected}
+ tooltip="Hidden Fields"
>
{columns.map((option: ReactTableColumnProps, index: number) => (
{
const hiddenColumns = Array.isArray(props.hiddenColumns)
@@ -142,7 +142,7 @@ const TableColumnsVisibility = (props: TableColumnsVisibilityProps) => {
}
props.updateHiddenColumns(hiddenColumns);
}}
- className="t--table-column-visibility-column-toggle"
+ selected={!option.isHidden}
>
{option.Header}
@@ -152,19 +152,19 @@ const TableColumnsVisibility = (props: TableColumnsVisibilityProps) => {
))}
{
props.updateHiddenColumns([]);
}}
+ size="small"
+ text="Show All"
/>
);
-};
+}
export default TableColumnsVisibility;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableCompactMode.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableCompactMode.tsx
index 1b964a04b3..400ab38b0b 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableCompactMode.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableCompactMode.tsx
@@ -76,26 +76,26 @@ interface TableCompactModeProps {
updateCompactMode: (mode: CompactMode) => void;
}
-const TableCompactMode = (props: TableCompactModeProps) => {
+function TableCompactMode(props: TableCompactModeProps) {
const [selected, selectMenu] = React.useState(false);
return (
{
selectMenu(false);
}}
- isOpen={selected}
+ position={Position.BOTTOM}
>
{
selectMenu(selected);
}}
- className="t--table-compact-mode-toggle-btn"
+ selected={selected}
+ tooltip="Row Height"
>
@@ -103,14 +103,14 @@ const TableCompactMode = (props: TableCompactModeProps) => {
{CompactModes.map((item: CompactModeItem, index: number) => {
return (
{
props.updateCompactMode(item.value);
}}
- className={`${Classes.POPOVER_DISMISS} t--table-compact-mode-option`}
+ selected={
+ props.compactMode ? props.compactMode === item.value : false
+ }
>
{item.title}
@@ -119,6 +119,6 @@ const TableCompactMode = (props: TableCompactModeProps) => {
);
-};
+}
export default TableCompactMode;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableDataDownload.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableDataDownload.tsx
index 9387136188..3b3be89aa1 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableDataDownload.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableDataDownload.tsx
@@ -11,8 +11,8 @@ import { ReactComponent as DownloadIcon } from "assets/icons/control/download-ta
import { ReactTableColumnProps } from "components/designSystems/appsmith/TableComponent/Constants";
import { TableIconWrapper } from "components/designSystems/appsmith/TableComponent/TableStyledWrappers";
import TableActionIcon from "components/designSystems/appsmith/TableComponent/TableActionIcon";
-import { isString } from "lodash";
import styled from "styled-components";
+import { transformTableDataIntoCsv } from "./CommonUtilities";
const DropDownWrapper = styled.div`
display: flex;
@@ -49,7 +49,6 @@ const OptionWrapper = styled.div`
background: ${Colors.POLAR};
}
`;
-
interface TableDataDownloadProps {
data: Array
>;
columns: ReactTableColumnProps[];
@@ -74,7 +73,59 @@ const dowloadOptions: DownloadOptionProps[] = [
},
];
-const TableDataDownload = (props: TableDataDownloadProps) => {
+const downloadDataAsCSV = (props: {
+ csvData: Array>;
+ fileName: string;
+}) => {
+ let csvContent = "";
+ props.csvData.forEach((infoArray: Array, index: number) => {
+ const dataString = infoArray.join(",");
+ csvContent += index < props.csvData.length ? dataString + "\n" : dataString;
+ });
+ const anchor = document.createElement("a");
+ const mimeType = "application/octet-stream";
+ if (navigator.msSaveBlob) {
+ navigator.msSaveBlob(
+ new Blob([csvContent], {
+ type: mimeType,
+ }),
+ props.fileName,
+ );
+ } else if (URL && "download" in anchor) {
+ anchor.href = URL.createObjectURL(
+ new Blob([csvContent], {
+ type: mimeType,
+ }),
+ );
+ anchor.setAttribute("download", props.fileName);
+ document.body.appendChild(anchor);
+ anchor.click();
+ document.body.removeChild(anchor);
+ }
+};
+
+const downloadDataAsExcel = (tableData: string[][], fileName: string) => {
+ import("xlsx").then((XLSX) => {
+ const workSheet = XLSX.utils.aoa_to_sheet(tableData);
+ const workBook = {
+ Sheets: { data: workSheet, cols: [] },
+ SheetNames: ["data"],
+ };
+ const excelBuffer = XLSX.write(workBook, {
+ bookType: "xlsx",
+ type: "array",
+ });
+ const fileData = new Blob([excelBuffer], {
+ type:
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
+ });
+ import("file-saver").then((FileSaver) => {
+ FileSaver.saveAs(fileData, `${fileName}.xlsx`);
+ });
+ });
+};
+
+function TableDataDownload(props: TableDataDownloadProps) {
const [selected, selectMenu] = React.useState(false);
const downloadFile = (type: string) => {
if (type === "CSV") {
@@ -84,19 +135,19 @@ const TableDataDownload = (props: TableDataDownloadProps) => {
}
};
const downloadTableDataAsExcel = () => {
- const tableData: Array<{ [key: string]: any }> = [];
- const tableHeaders = props.columns
+ const tableData: string[][] = [];
+ const tableHeaders: string[] = props.columns
.map((column: ReactTableColumnProps) => {
if (column.metaProperties && !column.metaProperties.isHidden) {
return column.Header;
}
- return null;
+ return "";
})
.filter((i) => !!i);
tableData.push(tableHeaders);
for (let row = 0; row < props.data.length; row++) {
const data: { [key: string]: any } = props.data[row];
- const tableRow = [];
+ const tableRow: string[] = [];
for (let colIndex = 0; colIndex < props.columns.length; colIndex++) {
const column = props.columns[colIndex];
if (column.metaProperties && !column.metaProperties.isHidden) {
@@ -105,87 +156,25 @@ const TableDataDownload = (props: TableDataDownloadProps) => {
}
tableData.push(tableRow);
}
- import("xlsx").then((XLSX) => {
- const workSheet = XLSX.utils.aoa_to_sheet(tableData);
- const workBook = {
- Sheets: { data: workSheet, cols: [] },
- SheetNames: ["data"],
- };
- const excelBuffer = XLSX.write(workBook, {
- bookType: "xlsx",
- type: "array",
- });
- const fileData = new Blob([excelBuffer], {
- type:
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
- });
- import("file-saver").then((FileSaver) => {
- FileSaver.saveAs(fileData, `${props.widgetName}.xlsx`);
- });
- });
+ downloadDataAsExcel(tableData, props.widgetName);
};
const downloadTableDataAsCsv = () => {
selectMenu(true);
- const csvData = [];
- csvData.push(
- props.columns
- .map((column: ReactTableColumnProps) => {
- if (column.metaProperties && !column.metaProperties.isHidden) {
- return column.Header;
- }
- return null;
- })
- .filter((i) => !!i),
- );
- for (let row = 0; row < props.data.length; row++) {
- const data: { [key: string]: any } = props.data[row];
- const csvDataRow = [];
- for (let colIndex = 0; colIndex < props.columns.length; colIndex++) {
- const column = props.columns[colIndex];
- const value = data[column.accessor];
- if (column.metaProperties && !column.metaProperties.isHidden) {
- if (isString(value) && value.includes(",")) {
- csvDataRow.push(`"${value}"`);
- } else {
- csvDataRow.push(value);
- }
- }
- }
- csvData.push(csvDataRow);
- }
- let csvContent = "";
- csvData.forEach(function(infoArray, index) {
- const dataString = infoArray.join(",");
- csvContent += index < csvData.length ? dataString + "\n" : dataString;
+ const csvData = transformTableDataIntoCsv({
+ columns: props.columns,
+ data: props.data,
+ });
+ downloadDataAsCSV({
+ csvData: csvData,
+ fileName: `${props.widgetName}.csv`,
});
- const fileName = `${props.widgetName}.csv`;
- const anchor = document.createElement("a");
- const mimeType = "application/octet-stream";
- if (navigator.msSaveBlob) {
- navigator.msSaveBlob(
- new Blob([csvContent], {
- type: mimeType,
- }),
- fileName,
- );
- } else if (URL && "download" in anchor) {
- anchor.href = URL.createObjectURL(
- new Blob([csvContent], {
- type: mimeType,
- }),
- );
- anchor.setAttribute("download", fileName);
- document.body.appendChild(anchor);
- anchor.click();
- document.body.removeChild(anchor);
- }
selectMenu(false);
};
if (props.columns.length === 0) {
return (
-
+
@@ -193,22 +182,22 @@ const TableDataDownload = (props: TableDataDownloadProps) => {
}
return (
{
selectMenu(false);
}}
- isOpen={selected}
+ position={Position.BOTTOM}
>
{
selectMenu(selected);
}}
- className="t--table-download-btn"
+ selected={selected}
+ tooltip="Download"
>
@@ -216,11 +205,11 @@ const TableDataDownload = (props: TableDataDownloadProps) => {
{dowloadOptions.map((item: DownloadOptionProps, index: number) => {
return (
{
downloadFile(item.value);
}}
- className={`${Classes.POPOVER_DISMISS} t--table-download-data-option`}
>
{item.label}
@@ -229,6 +218,6 @@ const TableDataDownload = (props: TableDataDownloadProps) => {
);
-};
+}
export default TableDataDownload;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableFilters.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableFilters.tsx
index 4d82c8e00b..145ace9fe5 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableFilters.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableFilters.tsx
@@ -102,7 +102,7 @@ interface TableFilterProps {
editMode: boolean;
}
-const TableFilters = (props: TableFilterProps) => {
+function TableFilters(props: TableFilterProps) {
const [selected, selectMenu] = React.useState(false);
const [filters, updateFilters] = React.useState(
new Array(),
@@ -138,7 +138,7 @@ const TableFilters = (props: TableFilterProps) => {
if (props.columns.length === 0) {
return (
-
+
@@ -163,20 +163,18 @@ const TableFilters = (props: TableFilterProps) => {
);
return (
{
selectMenu(false);
}}
- isOpen={selected}
+ position={Position.BOTTOM}
+ usePortal
>
{filters.length}
@@ -185,6 +183,8 @@ const TableFilters = (props: TableFilterProps) => {
selectMenu={(selected: boolean) => {
selectMenu(selected);
}}
+ selected={selected}
+ tooltip="Filters"
>
@@ -193,16 +193,6 @@ const TableFilters = (props: TableFilterProps) => {
{filters.map((filter: ReactTableFilter, index: number) => {
return (
= 2 ? filters[1].operator : filter.operator
- }
- column={filter.column}
- condition={filter.condition}
- value={filter.value}
- columns={columns}
- hasAnyFilters={hasAnyFilters}
applyFilter={(filter: ReactTableFilter, index: number) => {
const updatedFilters = props.filters
? [...props.filters]
@@ -210,6 +200,15 @@ const TableFilters = (props: TableFilterProps) => {
updatedFilters[index] = filter;
props.applyFilter(updatedFilters);
}}
+ column={filter.column}
+ columns={columns}
+ condition={filter.condition}
+ hasAnyFilters={hasAnyFilters}
+ index={index}
+ key={index}
+ operator={
+ filters.length >= 2 ? filters[1].operator : filter.operator
+ }
removeFilter={(index: number) => {
const filters: ReactTableFilter[] = props.filters || [];
if (index === 1 && filters.length > 2) {
@@ -221,18 +220,19 @@ const TableFilters = (props: TableFilterProps) => {
];
props.applyFilter(newFilters);
}}
+ value={filter.value}
/>
);
})}
{hasAnyFilters ? (
) : null}
@@ -245,6 +245,6 @@ const TableFilters = (props: TableFilterProps) => {
);
-};
+}
export default TableFilters;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableHeader.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableHeader.tsx
index 08609f6e6e..984bd56de4 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableHeader.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableHeader.tsx
@@ -41,25 +41,24 @@ const PageNumberInputWrapper = styled(NumericInput)`
margin: 0 8px;
`;
-const PageNumberInput = (props: {
+function PageNumberInput(props: {
pageNo: number;
pageCount: number;
updatePageNo: (pageNo: number, event?: EventType) => void;
disabled: boolean;
-}) => {
+}) {
const [pageNumber, setPageNumber] = React.useState(props.pageNo || 0);
useEffect(() => {
setPageNumber(props.pageNo || 0);
}, [props.pageNo]);
return (
{
const oldPageNo = Number(props.pageNo || 0);
const value = e.target.value;
@@ -82,9 +81,10 @@ const PageNumberInput = (props: {
setPageNumber(value);
}
}}
+ value={pageNumber}
/>
);
-};
+}
interface TableHeaderProps {
updatePageNo: (pageNo: number, event?: EventType) => void;
@@ -111,32 +111,32 @@ interface TableHeaderProps {
tableSizes: TableSizes;
}
-const TableHeader = (props: TableHeaderProps) => {
+function TableHeader(props: TableHeaderProps) {
const tableHeaderWrapperRef = React.createRef();
return (
{
props.prevPageClick();
}}
>
-
+
-
+
{props.pageNo + 1}
{
props.nextPageClick();
}}
>
-
+
)}
@@ -183,15 +183,15 @@ const TableHeader = (props: TableHeaderProps) => {
props.updatePageNo(pageNo + 1, EventType.ON_PREV_PAGE);
}}
>
-
+
Page{" "}
{" "}
of {props.pageCount}
@@ -206,13 +206,13 @@ const TableHeader = (props: TableHeaderProps) => {
props.updatePageNo(pageNo + 1, EventType.ON_NEXT_PAGE);
}}
>
-
+
)}
);
-};
+}
export default TableHeader;
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TablePagination.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TablePagination.tsx
index f70412b64d..8beca15e4e 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TablePagination.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TablePagination.tsx
@@ -17,14 +17,14 @@ function PagerIcon(props: {
return (
+ />
);
}
interface PagerProps {
@@ -46,14 +46,14 @@ export function TablePagination(props: PagerProps) {
+ icon={"chevron-left"}
+ onClick={props.prevPageClick}
+ />
+ />
);
diff --git a/app/client/src/components/designSystems/appsmith/TableComponent/TableUtilities.tsx b/app/client/src/components/designSystems/appsmith/TableComponent/TableUtilities.tsx
index 4075fae2fd..dfd3f6487b 100644
--- a/app/client/src/components/designSystems/appsmith/TableComponent/TableUtilities.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableComponent/TableUtilities.tsx
@@ -40,10 +40,7 @@ export const renderCell = (
case ColumnTypes.IMAGE:
if (!value) {
return (
-
+
);
} else if (!isString(value)) {
return (
@@ -64,12 +61,12 @@ export const renderCell = (
if (imageUrlRegex.test(item) || base64ImageRegex.test(item)) {
return (
e.stopPropagation()}
- target="_blank"
- rel="noopener noreferrer"
className="image-cell-wrapper"
href={item}
key={index}
+ onClick={(e) => e.stopPropagation()}
+ rel="noopener noreferrer"
+ target="_blank"
>
+
);
} else if (isString(value) && youtubeRegex.test(value)) {
return (
@@ -112,11 +106,11 @@ export const renderCell = (
default:
return (
{value.toString()}
@@ -138,23 +132,18 @@ export const renderActions = (
cellProperties: CellLayoutProperties,
) => {
if (!props.columnActions)
- return (
-
- );
+ return
;
return (
{props.columnActions.map((action: ColumnAction, index: number) => {
return (
);
@@ -163,13 +152,13 @@ export const renderActions = (
);
};
-const TableAction = (props: {
+function TableAction(props: {
isSelected: boolean;
action: ColumnAction;
backgroundColor: string;
buttonLabelColor: string;
onCommandClick: (dynamicTrigger: string, onComplete: () => void) => void;
-}) => {
+}) {
const [loading, setLoading] = useState(false);
const onComplete = () => {
setLoading(false);
@@ -186,19 +175,19 @@ const TableAction = (props: {
}}
>
{
setLoading(true);
props.onCommandClick(props.action.dynamicTrigger, onComplete);
}}
- text={props.action.label}
- filled
size="small"
+ text={props.action.label}
/>
);
-};
+}
export const renderEmptyRows = (
rowCount: number,
@@ -227,7 +216,7 @@ export const renderEmptyRows = (
? columns
: new Array(3).fill({ width: tableWidth / 3, isHidden: false });
return (
-
+ <>
{rows.map((row: string, index: number) => {
return (
{
return (
);
})}
-
+ >
);
};
@@ -283,7 +272,7 @@ const DescendingIcon = styled(ControlIcons.SORT_CONTROL as AnyStyledComponent)`
}
`;
-export const TableHeaderCell = (props: {
+export function TableHeaderCell(props: {
columnName: string;
columnIndex: number;
isHidden: boolean;
@@ -291,7 +280,7 @@ export const TableHeaderCell = (props: {
sortTableColumn: (columnIndex: number, asc: boolean) => void;
isResizingColumn: boolean;
column: any;
-}) => {
+}) {
const { column } = props;
const handleSortColumn = () => {
if (props.isResizingColumn) return;
@@ -320,7 +309,6 @@ export const TableHeaderCell = (props: {
) : null}
{props.columnName}
@@ -341,7 +330,7 @@ export const TableHeaderCell = (props: {
/>
);
-};
+}
export function getDefaultColumnProperties(
accessor: string,
@@ -445,8 +434,8 @@ export const renderDropdown = (props: {
const isSelected: boolean = isOptionSelected(option);
return (
) => {
e.stopPropagation();
}}
+ style={{ height: "100%" }}
>
{
props.onItemSelect(props.onOptionChange, item);
}}
@@ -471,7 +461,6 @@ export const renderDropdown = (props: {
usePortal: true,
popoverClassName: "select-popover-wrapper",
}}
- filterable={false}
>
void;
}
-const ReactTableComponent = (props: ReactTableComponentProps) => {
+function ReactTableComponent(props: ReactTableComponentProps) {
const { columnOrder, hiddenColumns } = useMemo(() => {
const order: string[] = [];
const hidden: string[] = [];
@@ -181,45 +181,45 @@ const ReactTableComponent = (props: ReactTableComponentProps) => {
return (
{
- props.nextPageClick();
- }}
- prevPageClick={() => {
- props.prevPageClick();
- }}
- serverSidePaginationEnabled={props.serverSidePaginationEnabled}
- selectedRowIndex={props.selectedRowIndex}
- selectedRowIndices={props.selectedRowIndices}
disableDrag={() => {
props.disableDrag(true);
}}
+ editMode={props.editMode}
enableDrag={() => {
props.disableDrag(false);
}}
- searchTableData={props.searchTableData}
filters={props.filters}
- applyFilter={props.applyFilter}
- compactMode={props.compactMode}
+ handleResizeColumn={props.handleResizeColumn}
+ height={props.height}
+ isLoading={props.isLoading}
+ nextPageClick={() => {
+ props.nextPageClick();
+ }}
+ pageNo={props.pageNo - 1}
+ pageSize={props.pageSize || 1}
+ prevPageClick={() => {
+ props.prevPageClick();
+ }}
+ searchKey={props.searchKey}
+ searchTableData={props.searchTableData}
+ selectTableRow={selectTableRow}
+ selectedRowIndex={props.selectedRowIndex}
+ selectedRowIndices={props.selectedRowIndices}
+ serverSidePaginationEnabled={props.serverSidePaginationEnabled}
+ sortTableColumn={sortTableColumn}
+ triggerRowSelection={props.triggerRowSelection}
updateCompactMode={props.updateCompactMode}
+ updatePageNo={props.updatePageNo}
+ widgetId={props.widgetId}
+ widgetName={props.widgetName}
+ width={props.width}
/>
);
-};
+}
export default ReactTableComponent;
diff --git a/app/client/src/components/designSystems/appsmith/TabsComponent.tsx b/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
index 820bd47509..75a541f905 100644
--- a/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
@@ -1,7 +1,10 @@
import React, { RefObject, ReactNode, useEffect, useRef } from "react";
import styled, { css } from "styled-components";
import { ComponentProps } from "./BaseComponent";
-import { TabsWidgetProps, TabContainerWidgetProps } from "widgets/TabsWidget";
+import {
+ TabsWidgetProps,
+ TabContainerWidgetProps,
+} from "widgets/Tabs/TabsWidget";
import { generateClassName, getCanvasClassName } from "utils/generators";
import { getBorderCSSShorthand } from "constants/DefaultTheme";
import ScrollIndicator from "components/ads/ScrollIndicator";
@@ -109,7 +112,7 @@ const StyledText = styled.div`
}
`;
-const TabsComponent = (props: TabsComponentProps) => {
+function TabsComponent(props: TabsComponentProps) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { onTabChange, ...remainingProps } = props;
const tabContainerRef: RefObject = useRef(
@@ -129,12 +132,12 @@ const TabsComponent = (props: TabsComponentProps) => {
{props.tabs.map((tab, index) => (
) => {
onTabChange(tab.widgetId);
event.stopPropagation();
}}
selected={props.selectedTabWidgetId === tab.widgetId}
- key={index}
>
{tab.label}
@@ -157,6 +160,6 @@ const TabsComponent = (props: TabsComponentProps) => {
);
-};
+}
export default TabsComponent;
diff --git a/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx b/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx
index 8f8b766fc5..b6464432aa 100644
--- a/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx
@@ -126,14 +126,14 @@ export class BaseTextInput extends Component {
return (
-
+
@@ -146,8 +146,8 @@ export class BaseTextInput extends Component {
* Text Input Component
* Has Icon, placholder, errors, etc.
*/
-const TextInputComponent = (props: TextInputProps & ComponentProps) => {
+function TextInputComponent(props: TextInputProps & ComponentProps) {
return ;
-};
+}
export default TextInputComponent;
diff --git a/app/client/src/components/designSystems/appsmith/VideoComponent.tsx b/app/client/src/components/designSystems/appsmith/VideoComponent.tsx
index aa569f8f29..b24fda9851 100644
--- a/app/client/src/components/designSystems/appsmith/VideoComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/VideoComponent.tsx
@@ -42,31 +42,27 @@ export default function VideoComponent(props: VideoComponentProps) {
onError,
player,
} = props;
- return (
- <>
- {url ? (
-
- ) : (
-
- {createMessage(ENTER_VIDEO_URL)}
-
- )}
- >
+ return url ? (
+
+ ) : (
+
+ {createMessage(ENTER_VIDEO_URL)}
+
);
}
diff --git a/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx
index 7fd9615df8..47696ec88b 100644
--- a/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx
+++ b/app/client/src/components/designSystems/appsmith/header/DeployLinkButton.tsx
@@ -46,28 +46,26 @@ export const DeployLinkButton = withTheme((props: Props) => {
};
return (
-
-
-
- Current deployed version
-
-
-
- }
- canEscapeKeyClose={false}
- onClose={onClose}
- isOpen={isOpen}
- position={PopoverPosition.BOTTOM_RIGHT}
- >
- setIsOpen(true)}>{props.trigger}
-
-
+
+
+ Current deployed version
+
+
+
+ }
+ isOpen={isOpen}
+ modifiers={{ offset: { enabled: true, offset: "0, -3" } }}
+ onClose={onClose}
+ position={PopoverPosition.BOTTOM_RIGHT}
+ >
+ setIsOpen(true)}>{props.trigger}
+
);
});
diff --git a/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx b/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx
index 6705113b6e..d306372002 100644
--- a/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx
+++ b/app/client/src/components/designSystems/appsmith/header/ThreeDotsLoading.tsx
@@ -56,7 +56,7 @@ type Props = {
className?: string;
};
-const ThreeDotLoading = (props: Props) => {
+function ThreeDotLoading(props: Props) {
return (
@@ -64,6 +64,6 @@ const ThreeDotLoading = (props: Props) => {
);
-};
+}
export default ThreeDotLoading;
diff --git a/app/client/src/components/designSystems/appsmith/help/CollapsibleHelp.tsx b/app/client/src/components/designSystems/appsmith/help/CollapsibleHelp.tsx
index 7bdd33d935..f0712e1af1 100644
--- a/app/client/src/components/designSystems/appsmith/help/CollapsibleHelp.tsx
+++ b/app/client/src/components/designSystems/appsmith/help/CollapsibleHelp.tsx
@@ -45,7 +45,7 @@ export default function CollapsibleHelp(props: CollapsibleHelpProps) {
return (
-
+
{props.children}
);
diff --git a/app/client/src/components/designSystems/appsmith/help/DocumentationSearch.tsx b/app/client/src/components/designSystems/appsmith/help/DocumentationSearch.tsx
index 93eeaf879a..89fe057084 100644
--- a/app/client/src/components/designSystems/appsmith/help/DocumentationSearch.tsx
+++ b/app/client/src/components/designSystems/appsmith/help/DocumentationSearch.tsx
@@ -84,7 +84,7 @@ const StyledDiscordIcon = styled(DiscordIcon)`
}
`;
-const Hit = (props: { hit: { path: string } }) => {
+function Hit(props: { hit: { path: string } }) {
return (
);
-};
+}
-const DefaultHelpMenuItem = (props: {
+function DefaultHelpMenuItem(props: {
item: { label: string; link?: string; id?: string; icon: React.ReactNode };
onSelect: () => void;
-}) => {
+}) {
return (
);
-};
+}
const SearchContainer = styled.div`
height: 100%;
@@ -322,22 +322,22 @@ type HelpItem = {
const HELP_MENU_ITEMS: HelpItem[] = [
{
- icon:
,
+ icon:
,
label: "Documentation",
link: "https://docs.appsmith.com/",
},
{
- icon:
,
+ icon:
,
label: "Report a bug",
link: "https://github.com/appsmithorg/appsmith/issues/new/choose",
},
{
- icon:
,
+ icon:
,
label: "Chat with us",
link: "https://github.com/appsmithorg/appsmith/discussions",
},
{
- icon:
,
+ icon:
,
label: "Join our Discord",
link: "https://discord.gg/rBTTVJp",
},
@@ -345,7 +345,7 @@ const HELP_MENU_ITEMS: HelpItem[] = [
if (cloudHosting) {
HELP_MENU_ITEMS[2] = {
- icon:
,
+ icon:
,
label: "Chat with us",
id: "intercom-trigger",
};
@@ -394,6 +394,10 @@ class DocumentationSearch extends React.Component
{
{!this.props.hideMinimizeBtn && (
{
cursor: "pointer",
zIndex: 1,
}}
- icon="minus"
- color="white"
- iconSize={14}
- onClick={this.handleClose}
/>
)}
{
)}
@@ -429,8 +429,8 @@ class DocumentationSearch extends React.Component {
{HELP_MENU_ITEMS.map((item) => (
))}
diff --git a/app/client/src/components/designSystems/appsmith/help/HelpModal.tsx b/app/client/src/components/designSystems/appsmith/help/HelpModal.tsx
index f71ff00a4f..0ce2e8032a 100644
--- a/app/client/src/components/designSystems/appsmith/help/HelpModal.tsx
+++ b/app/client/src/components/designSystems/appsmith/help/HelpModal.tsx
@@ -100,17 +100,17 @@ class HelpModal extends React.Component {
<>
{isHelpModalOpen && (
diff --git a/app/client/src/components/designSystems/blueprint/ButtonComponent.tsx b/app/client/src/components/designSystems/blueprint/ButtonComponent.tsx
index 542a31e81d..44b5338312 100644
--- a/app/client/src/components/designSystems/blueprint/ButtonComponent.tsx
+++ b/app/client/src/components/designSystems/blueprint/ButtonComponent.tsx
@@ -121,9 +121,9 @@ type ButtonStyleProps = {
};
// To be used in any other part of the app
-export const BaseButton = (props: IButtonProps & ButtonStyleProps) => {
+export function BaseButton(props: IButtonProps & ButtonStyleProps) {
return ;
-};
+}
BaseButton.defaultProps = {
accent: "secondary",
@@ -167,12 +167,12 @@ const mapButtonStyleToStyleName = (buttonStyle?: ButtonStyle) => {
}
};
-const RecaptchaComponent = (
+function RecaptchaComponent(
props: {
children: any;
onClick?: (event: React.MouseEvent) => void;
} & RecaptchaProps,
-) => {
+) {
function handleError(event: React.MouseEvent, error: string) {
Toaster.show({
text: error,
@@ -209,41 +209,41 @@ const RecaptchaComponent = (
{props.children}
);
-};
+}
-const BtnWrapper = (
+function BtnWrapper(
props: {
children: any;
onClick?: (event: React.MouseEvent) => void;
} & RecaptchaProps,
-) => {
+) {
if (!props.googleRecaptchaKey)
return {props.children}
;
- return ;
-};
+ return ;
+}
// To be used with the canvas
-const ButtonContainer = (
+function ButtonContainer(
props: ButtonContainerProps & ButtonStyleProps & RecaptchaProps,
-) => {
+) {
return (
);
-};
+}
export default ButtonContainer;
diff --git a/app/client/src/components/designSystems/blueprint/CheckboxComponent.tsx b/app/client/src/components/designSystems/blueprint/CheckboxComponent.tsx
index 199aee5a1d..bcded2fe5a 100644
--- a/app/client/src/components/designSystems/blueprint/CheckboxComponent.tsx
+++ b/app/client/src/components/designSystems/blueprint/CheckboxComponent.tsx
@@ -36,19 +36,19 @@ class CheckboxComponent extends React.Component {
this.props.alignWidget === "RIGHT" ? Alignment.RIGHT : Alignment.LEFT;
return (
);
diff --git a/app/client/src/components/designSystems/blueprint/CloseButton.tsx b/app/client/src/components/designSystems/blueprint/CloseButton.tsx
index a641527d48..01c96d2eac 100644
--- a/app/client/src/components/designSystems/blueprint/CloseButton.tsx
+++ b/app/client/src/components/designSystems/blueprint/CloseButton.tsx
@@ -22,13 +22,13 @@ const StyledButton = styled(Button)`
}
`;
-export const CloseButton = (props: CloseButtonProps) => {
+export function CloseButton(props: CloseButtonProps) {
return (
);
-};
+}
diff --git a/app/client/src/components/designSystems/blueprint/DatePickerComponent.tsx b/app/client/src/components/designSystems/blueprint/DatePickerComponent.tsx
index 27c60a9970..d85e2158d7 100644
--- a/app/client/src/components/designSystems/blueprint/DatePickerComponent.tsx
+++ b/app/client/src/components/designSystems/blueprint/DatePickerComponent.tsx
@@ -141,17 +141,17 @@ class DatePickerComponent extends React.Component<
>
}
diff --git a/app/client/src/components/designSystems/blueprint/DatePickerComponent2.tsx b/app/client/src/components/designSystems/blueprint/DatePickerComponent2.tsx
index a181b53f74..13f2aaf2e5 100644
--- a/app/client/src/components/designSystems/blueprint/DatePickerComponent2.tsx
+++ b/app/client/src/components/designSystems/blueprint/DatePickerComponent2.tsx
@@ -142,17 +142,17 @@ class DatePickerComponent extends React.Component<
>
}
diff --git a/app/client/src/components/designSystems/blueprint/DropdownComponent.tsx b/app/client/src/components/designSystems/blueprint/DropdownComponent.tsx
index 5c1b1de9b0..f5a45770fe 100644
--- a/app/client/src/components/designSystems/blueprint/DropdownComponent.tsx
+++ b/app/client/src/components/designSystems/blueprint/DropdownComponent.tsx
@@ -258,17 +258,17 @@ class DropDownComponent extends React.Component {
{this.props.selectionType === "SINGLE_SELECT" ? (
{
) : (
({
@@ -308,13 +314,7 @@ class DropDownComponent extends React.Component {
fill: true,
rightElement: ,
}}
- hideCloseButtonIndex={hideCloseButtonIndex}
- onItemSelect={this.onItemSelect}
- popoverProps={{
- minimal: true,
- usePortal: true,
- popoverClassName: "select-popover-wrapper",
- }}
+ tagRenderer={this.renderTag}
width={this.props.width}
/>
)}
@@ -365,8 +365,8 @@ class DropDownComponent extends React.Component {
const isSelected: boolean = this.isOptionSelected(option);
return (
{
}
const isSelected: boolean = this.isOptionSelected(option);
const content: ReactNode = (
-
- itemProps.handleClick(e)}
- />
-
+ itemProps.handleClick(e)}
+ />
);
return (
diff --git a/app/client/src/components/designSystems/blueprint/InputComponent.tsx b/app/client/src/components/designSystems/blueprint/InputComponent.tsx
index cfb21a3d02..24d684b7fc 100644
--- a/app/client/src/components/designSystems/blueprint/InputComponent.tsx
+++ b/app/client/src/components/designSystems/blueprint/InputComponent.tsx
@@ -169,39 +169,39 @@ class InputComponent extends React.Component<
private numericInputComponent = () => (
this.setFocusState(true)}
+ max={this.props.maxNum}
+ maxLength={this.props.maxChars}
+ min={this.props.minNum}
onBlur={() => this.setFocusState(false)}
+ onFocus={() => this.setFocusState(true)}
onKeyDown={this.onKeyDown}
+ onValueChange={this.onNumberChange}
+ placeholder={this.props.placeholder}
+ stepSize={this.props.stepSize}
+ type={this.props.inputType === "PHONE_NUMBER" ? "tel" : undefined}
+ value={this.props.value}
/>
);
private textAreaInputComponent = () => (