From dbc179ceadbc0a63969b8c62627e2b38cb18daec Mon Sep 17 00:00:00 2001
From: Abhinav Jha
Date: Thu, 13 Aug 2020 10:16:06 +0530
Subject: [PATCH 01/14] Add sentry release and environment configurations
(#277)
* Add sentry release and environment configurations
* Fixing nginx config issue
Co-authored-by: Satbir Singh
---
.../templates/nginx-linux.conf.template | 4 ++
.../docker/templates/nginx-mac.conf.template | 4 ++
app/client/public/index.html | 6 ++-
app/client/src/configs/index.ts | 39 +++++++++++++++++--
app/client/src/configs/types.ts | 4 +-
app/client/src/utils/AppsmithUtils.tsx | 2 +-
6 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/app/client/docker/templates/nginx-linux.conf.template b/app/client/docker/templates/nginx-linux.conf.template
index ad70d138c3..7142c4355e 100644
--- a/app/client/docker/templates/nginx-linux.conf.template
+++ b/app/client/docker/templates/nginx-linux.conf.template
@@ -31,6 +31,8 @@ server {
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
+ sub_filter __APPSMITH_SENTRY_RELEASE__ '${APPSMITH_SENTRY_RELEASE}';
+ sub_filter __APPSMITH_SENTRY_ENVIRONMENT__ '${APPSMITH_SENTRY_ENVIRONMENT}';
}
location /f {
@@ -93,6 +95,8 @@ server {
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
+ sub_filter __APPSMITH_SENTRY_RELEASE__ '${APPSMITH_SENTRY_RELEASE}';
+ sub_filter __APPSMITH_SENTRY_ENVIRONMENT__ '${APPSMITH_SENTRY_ENVIRONMENT}';
}
location /f {
diff --git a/app/client/docker/templates/nginx-mac.conf.template b/app/client/docker/templates/nginx-mac.conf.template
index bbef205cd5..39ec75fd7b 100644
--- a/app/client/docker/templates/nginx-mac.conf.template
+++ b/app/client/docker/templates/nginx-mac.conf.template
@@ -31,6 +31,8 @@ server {
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
+ sub_filter __APPSMITH_SENTRY_RELEASE__ '${APPSMITH_SENTRY_RELEASE}';
+ sub_filter __APPSMITH_SENTRY_ENVIRONMENT__ '${APPSMITH_SENTRY_ENVIRONMENT}';
}
location /f {
@@ -94,6 +96,8 @@ server {
sub_filter __APPSMITH_CLIENT_LOG_LEVEL__ '${APPSMITH_CLIENT_LOG_LEVEL}';
sub_filter __APPSMITH_GOOGLE_MAPS_API_KEY__ '${APPSMITH_GOOGLE_MAPS_API_KEY}';
sub_filter __APPSMITH_TNC_PP__ '${APPSMITH_TNC_PP}';
+ sub_filter __APPSMITH_SENTRY_RELEASE__ '${APPSMITH_SENTRY_RELEASE}';
+ sub_filter __APPSMITH_SENTRY_ENVIRONMENT__ '${APPSMITH_SENTRY_ENVIRONMENT}';
}
diff --git a/app/client/public/index.html b/app/client/public/index.html
index c24a1fd079..1df3d5fcc9 100755
--- a/app/client/public/index.html
+++ b/app/client/public/index.html
@@ -53,7 +53,11 @@
const CONFIG_LOG_LEVEL_INDEX = LOG_LEVELS.indexOf(parseConfig("__APPSMITH_CLIENT_LOG_LEVEL__"));
window.SENTRY_CONFIG = parseConfig("__APPSMITH_SENTRY_DSN__");
window.APPSMITH_FEATURE_CONFIGS = {
- sentry: parseConfig("__APPSMITH_SENTRY_DSN__"),
+ sentry: {
+ dsn: parseConfig("__APPSMITH_SENTRY_DSN__"),
+ release: parseConfig("__APPSMITH_SENTRY_RELEASE__"),
+ environment: parseConfig("__APPSMITH_SENTRY_ENVIRONMENT__"),
+ },
hotjar: {
id: parseConfig("__APPSMITH_HOTJAR_HJID__"),
sv: parseConfig("__APPSMITH_HOTJAR_HJSV__"),
diff --git a/app/client/src/configs/index.ts b/app/client/src/configs/index.ts
index 1ad9d0ba7a..24ba7f7a3a 100644
--- a/app/client/src/configs/index.ts
+++ b/app/client/src/configs/index.ts
@@ -1,6 +1,10 @@
import { AppsmithUIConfigs, FeatureFlagConfig } from "./types";
type INJECTED_CONFIGS = {
- sentry: string;
+ sentry: {
+ dsn: string;
+ release: string;
+ environment: string;
+ };
hotjar: {
id: string;
sv: string;
@@ -27,9 +31,19 @@ declare global {
}
}
+const capitalizeText = (text: string) => {
+ const rest = text.slice(1);
+ const first = text[0].toUpperCase();
+ return `${first}${rest}`;
+};
+
const getConfigsFromEnvVars = (): INJECTED_CONFIGS => {
return {
- sentry: process.env.REACT_APP_SENTRY_DSN || "",
+ sentry: {
+ dsn: process.env.REACT_APP_SENTRY_DSN || "",
+ release: process.env.REACT_APP_SENTRY_RELEASE || "",
+ environment: capitalizeText(process.env.NODE_ENV),
+ },
hotjar: {
id: process.env.REACT_APP_HOTJAR_HJID || "",
sv: process.env.REACT_APP_HOTJAR_HJSV || "",
@@ -92,7 +106,19 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => {
return;
};
- const sentry = getConfig(ENV_CONFIG.sentry, APPSMITH_FEATURE_CONFIGS.sentry);
+ // const sentry = getConfig(ENV_CONFIG.sentry, APPSMITH_FEATURE_CONFIGS.sentry);
+ const sentryDSN = getConfig(
+ ENV_CONFIG.sentry.dsn,
+ APPSMITH_FEATURE_CONFIGS.sentry.dsn,
+ );
+ const sentryRelease = getConfig(
+ ENV_CONFIG.sentry.release,
+ APPSMITH_FEATURE_CONFIGS.sentry.release,
+ );
+ const sentryENV = getConfig(
+ APPSMITH_FEATURE_CONFIGS.sentry.environment,
+ ENV_CONFIG.sentry.environment,
+ );
const segment = getConfig(
ENV_CONFIG.segment,
APPSMITH_FEATURE_CONFIGS.segment,
@@ -124,7 +150,12 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => {
);
return {
- sentry: { enabled: sentry.enabled, apiKey: sentry.value },
+ sentry: {
+ enabled: sentryDSN.enabled && sentryRelease.enabled && sentryENV.enabled,
+ dsn: sentryDSN.value,
+ release: sentryRelease.value,
+ environment: sentryENV.value,
+ },
hotjar: {
enabled: hotjarId.enabled && hotjarSV.enabled,
id: hotjarId.value,
diff --git a/app/client/src/configs/types.ts b/app/client/src/configs/types.ts
index 03e62bef6a..7fbd8178c3 100644
--- a/app/client/src/configs/types.ts
+++ b/app/client/src/configs/types.ts
@@ -26,7 +26,9 @@ export type FeatureFlagConfig = {
export type AppsmithUIConfigs = {
sentry: {
enabled: boolean;
- apiKey: string;
+ dsn: string;
+ release: string;
+ environment: string;
};
hotjar: {
enabled: boolean;
diff --git a/app/client/src/utils/AppsmithUtils.tsx b/app/client/src/utils/AppsmithUtils.tsx
index 0e1199435c..643a4611b4 100644
--- a/app/client/src/utils/AppsmithUtils.tsx
+++ b/app/client/src/utils/AppsmithUtils.tsx
@@ -31,7 +31,7 @@ export const appInitializer = () => {
FeatureFlag.initialize(appsmithConfigs.featureFlag);
if (appsmithConfigs.sentry.enabled) {
- Sentry.init({ dsn: appsmithConfigs.sentry.apiKey });
+ Sentry.init(appsmithConfigs.sentry);
}
if (appsmithConfigs.hotjar.enabled) {
const { id, sv } = appsmithConfigs.hotjar;
From 3b1c43dbdcc16e80442f57b982a6c7fecdd204c5 Mon Sep 17 00:00:00 2001
From: satbir121 <39981226+satbir121@users.noreply.github.com>
Date: Thu, 13 Aug 2020 22:07:15 +0530
Subject: [PATCH 02/14] Adding base64 library to realm executor (#304)
* Adding base64 library to realm executor
* Changing base64 interface to btoa and atob
* Making base64 a dependancy
---
app/client/package.json | 1 +
.../jsExecution/JSExecutionManagerSingleton.ts | 9 +++++++++
app/client/yarn.lock | 15 +++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/app/client/package.json b/app/client/package.json
index b239f4ef7c..1c0cae4845 100644
--- a/app/client/package.json
+++ b/app/client/package.json
@@ -60,6 +60,7 @@
"instantsearch.js": "^4.4.1",
"interweave": "^12.1.1",
"interweave-autolink": "^4.0.1",
+ "js-base64": "^3.4.5",
"json-fn": "^1.1.1",
"lint-staged": "^9.2.5",
"localforage": "^1.7.3",
diff --git a/app/client/src/jsExecution/JSExecutionManagerSingleton.ts b/app/client/src/jsExecution/JSExecutionManagerSingleton.ts
index df0240c910..f10d0d2f8c 100644
--- a/app/client/src/jsExecution/JSExecutionManagerSingleton.ts
+++ b/app/client/src/jsExecution/JSExecutionManagerSingleton.ts
@@ -1,6 +1,7 @@
import RealmExecutor from "./RealmExecutor";
import moment from "moment-timezone";
import { ActionDescription } from "entities/DataTree/dataTreeFactory";
+import { btoa, atob } from "js-base64";
export type JSExecutorGlobal = Record;
export type JSExecutorResult = {
@@ -30,6 +31,14 @@ export const extraLibraries = [
accessor: "moment",
lib: moment,
},
+ {
+ accessor: "btoa",
+ lib: btoa,
+ },
+ {
+ accessor: "atob",
+ lib: atob,
+ },
];
class JSExecutionManager {
diff --git a/app/client/yarn.lock b/app/client/yarn.lock
index 10b4a26d63..a131cdba8e 100644
--- a/app/client/yarn.lock
+++ b/app/client/yarn.lock
@@ -7322,6 +7322,21 @@ js-base64@^2.1.8:
version "2.5.1"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
+js-base64@^3.4.5:
+ version "3.4.5"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.4.5.tgz#6d1921e65a172cfd924604e1416dfaff45752c3e"
+ integrity sha512-Ub/AANierdcT8nm4ndBn3KzpZQ3MdHX4a+bwoVdjgeHCZ0ZEcP+UB4nmR4Z5lR6SH3Y+qAPmgVR0RxKJNHNHEg==
+
+js-string-escape@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
+ integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=
+
+js-stringify@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db"
+ integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds=
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
From 78c4b5a38287b4b97dac0fc08854282fd3e9217b Mon Sep 17 00:00:00 2001
From: Hetu Nandu
Date: Mon, 17 Aug 2020 10:33:15 +0530
Subject: [PATCH 03/14] Fixes date widget crashing when no date format is
mentioned (#322)
Fixed by using a proper default format string for ISO dates
---
app/client/src/constants/WidgetValidation.ts | 2 ++
app/client/src/utils/Validators.ts | 5 +++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/app/client/src/constants/WidgetValidation.ts b/app/client/src/constants/WidgetValidation.ts
index 9741656714..556c0e6fe3 100644
--- a/app/client/src/constants/WidgetValidation.ts
+++ b/app/client/src/constants/WidgetValidation.ts
@@ -33,3 +33,5 @@ export type Validator = (
props: WidgetProps,
dataTree?: DataTree,
) => ValidationResponse;
+
+export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.SSSZ";
diff --git a/app/client/src/utils/Validators.ts b/app/client/src/utils/Validators.ts
index 449f23e8f1..7be2897b03 100644
--- a/app/client/src/utils/Validators.ts
+++ b/app/client/src/utils/Validators.ts
@@ -1,5 +1,6 @@
import _ from "lodash";
import {
+ ISO_DATE_FORMAT,
VALIDATION_TYPES,
ValidationResponse,
ValidationType,
@@ -392,8 +393,8 @@ export const VALIDATORS: Record = {
.minute(0)
.second(0)
.millisecond(0);
- const dateFormat = props.dateFormat ? props.dateFormat : moment.ISO_8601;
- // const dateStr = moment().toISOString();
+ const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT;
+
const todayDateString = today.format(dateFormat);
if (dateString === undefined) {
return {
From 9ecb402f5b672fc8b0a95ec0f9e2ed8a044f6a4c Mon Sep 17 00:00:00 2001
From: areyabhishek
Date: Tue, 18 Aug 2020 23:57:50 +0530
Subject: [PATCH 04/14] Update README.md
---
README.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index b47e3f5e29..a5e6130258 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,8 @@
-
Open source alternative to Power Apps, Salesforce Lightning platform, and Retool
+ The quickest way to build dashboards, workflows, forms, or any kind of internal business tool.
+ Open source alternative to Power Apps, Salesforce Lightning platform, Unqork, Forest admin, and Retool.
@@ -23,9 +24,9 @@
-----------------
Appsmith is a fast, easy, and secure way to build any custom internal tools. Using Appsmith is easy.
-1. Create a page using pre-built UI components like table, charts, and forms.
+1. Create a page using pre-built UI components like table, charts, map viewers and forms.
2. Connect the UI components to any REST API or databases like MySQL, Postgres, and MongoDB. Write any logic in JS.
-3. Then deploy the interal tool to a custom URL and invite users to sign in with their Google acounts.
+3. Deploy the interal tool to a custom URL and invite users to sign in with their Google acounts.
Do all this **without HTML/CSS**, and writing any custom integrations.
From 62d0ec6b17618413f80b680bf78dff5bf719b7ad Mon Sep 17 00:00:00 2001
From: areyabhishek
Date: Tue, 18 Aug 2020 23:58:30 +0530
Subject: [PATCH 05/14] Update README.md
---
README.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/README.md b/README.md
index a5e6130258..0208af071a 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,6 @@
The quickest way to build dashboards, workflows, forms, or any kind of internal business tool.
- Open source alternative to Power Apps, Salesforce Lightning platform, Unqork, Forest admin, and Retool.
From 3762ea6210dcdb0b435c460192a86ac74655a9bd Mon Sep 17 00:00:00 2001
From: areyabhishek
Date: Wed, 19 Aug 2020 00:06:40 +0530
Subject: [PATCH 06/14] Update README.md
---
README.md | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 0208af071a..417f240f4c 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Appsmith is a fast, easy, and secure way to build any custom internal tools. Usi
2. Connect the UI components to any REST API or databases like MySQL, Postgres, and MongoDB. Write any logic in JS.
3. Deploy the interal tool to a custom URL and invite users to sign in with their Google acounts.
-Do all this **without HTML/CSS**, and writing any custom integrations.
+Do all this without depending on multiple UI libraries, coding authentication logic or writing any DB or API integrations. See the looped gif below to see how something gets built on Appsmith.

@@ -38,21 +38,22 @@ Do all this **without HTML/CSS**, and writing any custom integrations.
* [Customer Support Dashboard](https://app.appsmith.com/applications/5f2aeb2580ca1f6faaed4e4a/pages/5f2aeb2580ca1f6faaed4e4c#utm_source=github&utm_medium=homepage)
## Getting Started
-
-* [Cloud Hosted](https://app.appsmith.com/user/signup)
+You can try our online sandbox or deploy a Docker image on a server.
+* [Online sandbox](https://app.appsmith.com/user/signup)
* [Deploy with Docker](https://docs.appsmith.com/quick-start#docker)
## Why Appsmith?
-If we're building an internal tool, our obvious choices are to use an admin panel or if we happen to be blessed with HTML/CSS skills, we might **"bootstrap"** a new project. While this may seem like a great idea at first, internal tools almost always require a ton of iterations and eventually we reach a point where we're either spending a lot of time customising the admin panel or the UI terrifies users so much, they prefer [holding our hand](https://giphy.com/gifs/agentm-agent-m-1gg6pvaqHBv56/fullscreen) every time they try to use it.
+When we need an internal tool, we turn to admin panels frameworks or use a bootstrap theme. Admin panels have an opinionated design
+These choices don't always work out because internal tools require iterations, maintenance, enhancements and eventually we reach a point where we're either spending a lot of time customising the admin panel or the UI terrifies users so much, they prefer [holding our hand](https://giphy.com/gifs/agentm-agent-m-1gg6pvaqHBv56/fullscreen) every time they try to use it.
Appsmith provides a better way of building internal tools by visualising them as modular blocks (**Widgets, APIs, Queries, JS**) and giving developers a simple user interface to configure them. With appsmith updating UI, changing dataflows and modifying business logic becomes a [piece of cake](https://i.kym-cdn.com/photos/images/newsfeed/001/355/125/5ca.png) because you no longer have to trudge through large undocumented code bases or **fight with HTML/CSS**. We understand that while some configurations are static and are better controlled via UI, a lot of it is dynamic and should be configured through code. Appsmith doesn't take the fun out of coding, instead it treats every block as an object and exposes it via javascript so that you can read, transform and manipulate it. Whether it's a widget, API or query, you get to decide where you need to configure and where you need to code.
## Features
* **Build custom UI**: Drag & drop, resize and style widgets **without HTML / CSS**. [Read more](https://docs.appsmith.com/core-concepts/building-the-ui)
-* **Query data**: Query & update your database directly from the UI. Supports **postgres, mongo, REST & GraphQL APIs**. [Read more](https://docs.appsmith.com/core-concepts/building-the-ui/displaying-api-data)
-* **JS Logic**: Write snippets of business logic using JS to transform data, manipuate UI or trigger workflows
+* **Query data**: Query & update your database directly from the UI. Connect to **postgres, mongo, MySQL, REST & GraphQL APIs**. [Read more](https://docs.appsmith.com/core-concepts/building-the-ui/displaying-api-data)
+* **JS Logic**: Write snippets of business logic using JS to transform data, manipuate UI or trigger workflows. Use Lodash functions
* **Data Workflows**: Simple configuration to create flows when users interact with the UI. [Read more](https://docs.appsmith.com/core-concepts/building-the-ui/calling-apis-from-widgets)
* **Realtime Editor**: Changes in your application reflect instantly with every edit. No need to compile!
* **Works with existing, live databases**: Connect directly to any Postgres & Mongo db
From fb279442c2e6d826d4d6eceddffc517d5f9e3c93 Mon Sep 17 00:00:00 2001
From: areyabhishek
Date: Wed, 19 Aug 2020 00:17:58 +0530
Subject: [PATCH 07/14] Update README.md
---
README.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 417f240f4c..af4c8dbb36 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Appsmith is a fast, easy, and secure way to build any custom internal tools. Usi
2. Connect the UI components to any REST API or databases like MySQL, Postgres, and MongoDB. Write any logic in JS.
3. Deploy the interal tool to a custom URL and invite users to sign in with their Google acounts.
-Do all this without depending on multiple UI libraries, coding authentication logic or writing any DB or API integrations. See the looped gif below to see how something gets built on Appsmith.
+Do all this without depending on multiple UI libraries, coding authentication logic or writing any DB or API integrations. See the looped gif below to see how something gets built on Appsmith. It might remind you of Visual Basic.

@@ -44,10 +44,9 @@ You can try our online sandbox or deploy a Docker image on a server.
## Why Appsmith?
-When we need an internal tool, we turn to admin panels frameworks or use a bootstrap theme. Admin panels have an opinionated design
-These choices don't always work out because internal tools require iterations, maintenance, enhancements and eventually we reach a point where we're either spending a lot of time customising the admin panel or the UI terrifies users so much, they prefer [holding our hand](https://giphy.com/gifs/agentm-agent-m-1gg6pvaqHBv56/fullscreen) every time they try to use it.
+When we build internal tools today, we turn to admin panels frameworks or use a bootstrap theme. We took inspirations from the best admin panels, bootstrap themes, and brought back the easy UI builder of Visual Basic.
-Appsmith provides a better way of building internal tools by visualising them as modular blocks (**Widgets, APIs, Queries, JS**) and giving developers a simple user interface to configure them. With appsmith updating UI, changing dataflows and modifying business logic becomes a [piece of cake](https://i.kym-cdn.com/photos/images/newsfeed/001/355/125/5ca.png) because you no longer have to trudge through large undocumented code bases or **fight with HTML/CSS**. We understand that while some configurations are static and are better controlled via UI, a lot of it is dynamic and should be configured through code. Appsmith doesn't take the fun out of coding, instead it treats every block as an object and exposes it via javascript so that you can read, transform and manipulate it. Whether it's a widget, API or query, you get to decide where you need to configure and where you need to code.
+Appsmith is a quicker way of building internal tools by visualising them as modular blocks (**Widgets, APIs, Queries, JS**) and giving developers a simple user interface to configure them. New features, UI modification, changing dataflows, and modifying business logic becomes a [piece of cake](https://i.kym-cdn.com/photos/images/newsfeed/001/355/125/5ca.png) because you no longer have to trudge through large undocumented code bases or wrestle with HTML/CSS. We understand that while some configurations are static and are better controlled via UI, a lot of it is dynamic and should be configured through code. Appsmith doesn't take the fun out of coding, instead it treats every block as an object and exposes it via javascript so that you can read, transform and manipulate it. Whether it's a widget, API or query, you get to decide where you need to configure and where you need to code.
## Features
From 0543392638bcca0cff3ee9d2e1c6aff5f10200a4 Mon Sep 17 00:00:00 2001
From: areyabhishek
Date: Wed, 19 Aug 2020 00:19:07 +0530
Subject: [PATCH 08/14] Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index af4c8dbb36..00515191ea 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@
-----------------
-Appsmith is a fast, easy, and secure way to build any custom internal tools. Using Appsmith is easy.
+Appsmith is a fast, easy, and secure way to build any custom internal tools. Here's how you build something:
1. Create a page using pre-built UI components like table, charts, map viewers and forms.
2. Connect the UI components to any REST API or databases like MySQL, Postgres, and MongoDB. Write any logic in JS.
3. Deploy the interal tool to a custom URL and invite users to sign in with their Google acounts.
@@ -55,7 +55,7 @@ Appsmith is a quicker way of building internal tools by visualising them as modu
* **JS Logic**: Write snippets of business logic using JS to transform data, manipuate UI or trigger workflows. Use Lodash functions
* **Data Workflows**: Simple configuration to create flows when users interact with the UI. [Read more](https://docs.appsmith.com/core-concepts/building-the-ui/calling-apis-from-widgets)
* **Realtime Editor**: Changes in your application reflect instantly with every edit. No need to compile!
-* **Works with existing, live databases**: Connect directly to any Postgres & Mongo db
+* **Works with existing, live databases**: Connect directly to any Postgres, MySQL, & Mongo db
* **Fine-grained access control**: Control who can edit / view your applications from a single control panel
* **App management**: Build and organise multiple applications on a single platform
From 5126c4679cd2ebcdb8629e93d95a79172baf082d Mon Sep 17 00:00:00 2001
From: Nikhil Nandagopal
Date: Thu, 20 Aug 2020 12:03:08 +0530
Subject: [PATCH 09/14] Updated Links
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 00515191ea..34fe65160a 100644
--- a/README.md
+++ b/README.md
@@ -35,12 +35,12 @@ Do all this without depending on multiple UI libraries, coding authentication lo
## Example Applications
-* [Customer Support Dashboard](https://app.appsmith.com/applications/5f2aeb2580ca1f6faaed4e4a/pages/5f2aeb2580ca1f6faaed4e4c#utm_source=github&utm_medium=homepage)
+* [Customer Support Dashboard](https://bit.ly/cs-dashboard-appsmith)
## Getting Started
You can try our online sandbox or deploy a Docker image on a server.
-* [Online sandbox](https://app.appsmith.com/user/signup)
-* [Deploy with Docker](https://docs.appsmith.com/quick-start#docker)
+* [Online sandbox](https://bit.ly/appsmith-signup-github)
+* [Deploy with Docker](https://bit.ly/appsmith-docker-github)
## Why Appsmith?
From 17af152148d1a045ef8af4ad396ef5fc9258c4f4 Mon Sep 17 00:00:00 2001
From: vicky-primathon <67091118+vicky-primathon@users.noreply.github.com>
Date: Thu, 20 Aug 2020 15:00:19 +0530
Subject: [PATCH 10/14] Table Widget: Filter updates (#355)
- Show symbol signifying selected filters in table widget
- Show callout to prompt users to change column data types for accurate filter operations
---
.../appsmith/ReactTableComponent.tsx | 5 +-
.../designSystems/appsmith/Table.tsx | 6 +-
.../designSystems/appsmith/TableFilters.tsx | 141 ++++++++++++------
.../designSystems/appsmith/TableHeader.tsx | 5 +-
.../appsmith/TableStyledWrappers.tsx | 1 +
.../designSystems/appsmith/TableUtilities.tsx | 4 +-
app/client/src/constants/messages.ts | 3 +
app/client/src/widgets/TableWidget.tsx | 2 +-
8 files changed, 113 insertions(+), 54 deletions(-)
diff --git a/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx b/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
index dcbad406ed..5252b3c80e 100644
--- a/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
@@ -1,7 +1,6 @@
import React, { useEffect } from "react";
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
import Table from "components/designSystems/appsmith/Table";
-import { RenderMode, RenderModes } from "constants/WidgetConstants";
import { debounce } from "lodash";
import { getMenuOptions } from "components/designSystems/appsmith/TableUtilities";
import {
@@ -37,7 +36,7 @@ interface ReactTableComponentProps {
isDisabled?: boolean;
isVisible?: boolean;
isLoading: boolean;
- renderMode: RenderMode;
+ editMode: boolean;
width: number;
height: number;
pageSize: number;
@@ -282,7 +281,7 @@ const ReactTableComponent = (props: ReactTableComponentProps) => {
hiddenColumns={props.hiddenColumns}
updateHiddenColumns={props.updateHiddenColumns}
data={props.tableData}
- displayColumnActions={props.renderMode === RenderModes.CANVAS}
+ editMode={props.editMode}
columnNameMap={props.columnNameMap}
getColumnMenu={getColumnMenu}
handleColumnNameUpdate={handleColumnNameUpdate}
diff --git a/app/client/src/components/designSystems/appsmith/Table.tsx b/app/client/src/components/designSystems/appsmith/Table.tsx
index 0daaaba156..3aae6e6df9 100644
--- a/app/client/src/components/designSystems/appsmith/Table.tsx
+++ b/app/client/src/components/designSystems/appsmith/Table.tsx
@@ -33,7 +33,7 @@ interface TableProps {
hiddenColumns?: string[];
updateHiddenColumns: (hiddenColumns?: string[]) => void;
data: object[];
- displayColumnActions: boolean;
+ editMode: boolean;
columnNameMap?: { [key: string]: string };
getColumnMenu: (columnIndex: number) => ColumnMenuOptionProps[];
handleColumnNameUpdate: (columnIndex: number, columnName: string) => void;
@@ -142,7 +142,7 @@ export const Table = (props: TableProps) => {
updateHiddenColumns={props.updateHiddenColumns}
filters={props.filters}
applyFilter={props.applyFilter}
- displayColumnActions={props.displayColumnActions}
+ editMode={props.editMode}
compactMode={props.compactMode}
updateCompactMode={props.updateCompactMode}
tableSizes={tableSizes}
@@ -168,7 +168,7 @@ export const Table = (props: TableProps) => {
}
columnIndex={columnIndex}
isHidden={column.isHidden}
- displayColumnActions={props.displayColumnActions}
+ editMode={props.editMode}
handleColumnNameUpdate={props.handleColumnNameUpdate}
getColumnMenu={props.getColumnMenu}
handleResizeColumn={props.handleResizeColumn}
diff --git a/app/client/src/components/designSystems/appsmith/TableFilters.tsx b/app/client/src/components/designSystems/appsmith/TableFilters.tsx
index 93a61a04b0..03d6aa8d6a 100644
--- a/app/client/src/components/designSystems/appsmith/TableFilters.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableFilters.tsx
@@ -18,6 +18,13 @@ import {
Operator,
OperatorTypes,
} from "widgets/TableWidget";
+import { TABLE_FILTER_COLUMN_TYPE_CALLOUT } from "constants/messages";
+
+const TableFilterOuterWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
const TableFilerWrapper = styled.div`
display: flex;
@@ -37,6 +44,41 @@ const ButtonWrapper = styled.div`
background: transparent;
}
`;
+
+const SelectedFilterWrapper = styled.div`
+ position: absolute;
+ top: 12px;
+ right: 12px;
+ background: ${Colors.GREEN};
+ border: 0.5px solid ${Colors.WHITE};
+ box-sizing: border-box;
+ border-radius: 50%;
+ width: 10px;
+ height: 10px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-weight: bold;
+ font-size: 6px;
+ color: ${Colors.WHITE};
+`;
+
+const ColumnTypeBindingMessage = styled.div`
+ width: 100%;
+ height: 41px;
+ line-height: 41px;
+ background: ${Colors.ATHENS_GRAY_DARKER};
+ border: 1px dashed ${Colors.GEYSER_LIGHT};
+ box-sizing: border-box;
+ font-size: 12px;
+ color: ${Colors.SLATE_GRAY};
+ letter-spacing: 0.04em;
+ font-weight: 500;
+ padding: 0 16px;
+ min-width: 350px;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+`;
export interface ReactTableFilter {
column: string;
operator: Operator;
@@ -53,6 +95,7 @@ interface TableFilterProps {
columns: ReactTableColumnProps[];
filters?: ReactTableFilter[];
applyFilter: (filters: ReactTableFilter[]) => void;
+ editMode: boolean;
}
const TableFilters = (props: TableFilterProps) => {
@@ -135,51 +178,63 @@ const TableFilters = (props: TableFilterProps) => {
>
-
- e.stopPropagation()}>
- {filters.map((filter: ReactTableFilter, index: number) => {
- return (
- = 2 ? filters[1].operator : filter.operator
- }
- column={filter.column}
- condition={filter.condition}
- value={filter.value}
- columns={columns}
- applyFilter={(filter: ReactTableFilter, index: number) => {
- const updatedFilters = props.filters ? [...props.filters] : [];
- updatedFilters[index] = filter;
- props.applyFilter(updatedFilters);
- }}
- removeFilter={(index: number) => {
- const filters: ReactTableFilter[] = props.filters || [];
- if (index === 1 && filters.length > 2) {
- filters[2].operator = filters[1].operator;
- }
- const newFilters = [
- ...filters.slice(0, index),
- ...filters.slice(index + 1),
- ];
- props.applyFilter(newFilters);
- }}
- />
- );
- })}
{showAddFilter ? (
-
-
-
+ {filters.length}
) : null}
-
+
+
+ e.stopPropagation()}>
+ {filters.map((filter: ReactTableFilter, index: number) => {
+ return (
+ = 2 ? filters[1].operator : filter.operator
+ }
+ column={filter.column}
+ condition={filter.condition}
+ value={filter.value}
+ columns={columns}
+ applyFilter={(filter: ReactTableFilter, index: number) => {
+ const updatedFilters = props.filters
+ ? [...props.filters]
+ : [];
+ updatedFilters[index] = filter;
+ props.applyFilter(updatedFilters);
+ }}
+ removeFilter={(index: number) => {
+ const filters: ReactTableFilter[] = props.filters || [];
+ if (index === 1 && filters.length > 2) {
+ filters[2].operator = filters[1].operator;
+ }
+ const newFilters = [
+ ...filters.slice(0, index),
+ ...filters.slice(index + 1),
+ ];
+ props.applyFilter(newFilters);
+ }}
+ />
+ );
+ })}
+ {showAddFilter ? (
+
+
+
+ ) : null}
+
+ {props.editMode && (
+
+ {TABLE_FILTER_COLUMN_TYPE_CALLOUT}
+
+ )}
+
);
};
diff --git a/app/client/src/components/designSystems/appsmith/TableHeader.tsx b/app/client/src/components/designSystems/appsmith/TableHeader.tsx
index 71ef484f28..ab1ba8f278 100644
--- a/app/client/src/components/designSystems/appsmith/TableHeader.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableHeader.tsx
@@ -83,7 +83,7 @@ interface TableHeaderProps {
serverSidePaginationEnabled: boolean;
filters?: ReactTableFilter[];
applyFilter: (filters: ReactTableFilter[]) => void;
- displayColumnActions: boolean;
+ editMode: boolean;
compactMode?: CompactMode;
updateCompactMode: (compactMode: CompactMode) => void;
width: number;
@@ -108,13 +108,14 @@ const TableHeader = (props: TableHeaderProps) => {
columns={props.columns}
filters={props.filters}
applyFilter={props.applyFilter}
+ editMode={props.editMode}
/>
- {props.displayColumnActions && (
+ {props.editMode && (
(props.disabled ? 0.6 : 1)};
cursor: ${props => !props.disabled && "pointer"};
+ position: relative;
&:hover {
background: ${Colors.ATHENS_GRAY};
}
diff --git a/app/client/src/components/designSystems/appsmith/TableUtilities.tsx b/app/client/src/components/designSystems/appsmith/TableUtilities.tsx
index c99725ce74..3eedf66bb9 100644
--- a/app/client/src/components/designSystems/appsmith/TableUtilities.tsx
+++ b/app/client/src/components/designSystems/appsmith/TableUtilities.tsx
@@ -576,7 +576,7 @@ export const TableHeaderCell = (props: {
columnIndex: number;
isHidden: boolean;
isAscOrder?: boolean;
- displayColumnActions: boolean;
+ editMode: boolean;
handleColumnNameUpdate: (columnIndex: number, name: string) => void;
getColumnMenu: (columnIndex: number) => ColumnMenuOptionProps[];
sortTableColumn: (columnIndex: number, asc: boolean) => void;
@@ -635,7 +635,7 @@ export const TableHeaderCell = (props: {
{column.render("Header")}
)}
- {props.displayColumnActions && (
+ {props.editMode && (
) => {
diff --git a/app/client/src/constants/messages.ts b/app/client/src/constants/messages.ts
index bb171a5306..4a63e3216c 100644
--- a/app/client/src/constants/messages.ts
+++ b/app/client/src/constants/messages.ts
@@ -152,3 +152,6 @@ export const LIGHTNING_MENU_OPTION_HTML = "Write HTML";
export const CHECK_REQUEST_BODY = "Check Request body to debug?";
export const DONT_SHOW_THIS_AGAIN = "Don't show this again";
export const SHOW_REQUEST = "Show Request";
+
+export const TABLE_FILTER_COLUMN_TYPE_CALLOUT =
+ "Change column datatype to see filter operators";
diff --git a/app/client/src/widgets/TableWidget.tsx b/app/client/src/widgets/TableWidget.tsx
index 1026f5a06b..237f77d630 100644
--- a/app/client/src/widgets/TableWidget.tsx
+++ b/app/client/src/widgets/TableWidget.tsx
@@ -397,7 +397,7 @@ class TableWidget extends BaseWidget
{
widgetId={this.props.widgetId}
widgetName={this.props.widgetName}
searchKey={this.props.searchText}
- renderMode={this.props.renderMode}
+ editMode={this.props.renderMode === RenderModes.CANVAS}
hiddenColumns={hiddenColumns}
columnActions={this.props.columnActions}
columnNameMap={this.props.columnNameMap}
From b4cb37ddb867ff5fd827ebede1aaf09f7f953f04 Mon Sep 17 00:00:00 2001
From: vicky-primathon <67091118+vicky-primathon@users.noreply.github.com>
Date: Thu, 20 Aug 2020 15:01:49 +0530
Subject: [PATCH 11/14] Table Widget: debounce (#313)
* debounce method attached to search component and input field in table widget filters
* debounce used inside RenderInput component to update changed value
---
.../designSystems/appsmith/CascadeFields.tsx | 39 ++++++++++++++-----
.../appsmith/ReactTableComponent.tsx | 2 +-
.../appsmith/SearchComponent.tsx | 4 +-
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/app/client/src/components/designSystems/appsmith/CascadeFields.tsx b/app/client/src/components/designSystems/appsmith/CascadeFields.tsx
index 9cc03b0158..d200b89351 100644
--- a/app/client/src/components/designSystems/appsmith/CascadeFields.tsx
+++ b/app/client/src/components/designSystems/appsmith/CascadeFields.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useCallback } from "react";
import styled from "styled-components";
import { Icon, InputGroup } from "@blueprintjs/core";
import CustomizedDropdown from "pages/common/CustomizedDropdown";
@@ -19,6 +19,7 @@ import {
DropdownOption,
ReactTableFilter,
} from "components/designSystems/appsmith/TableFilters";
+import { debounce } from "lodash";
const StyledRemoveIcon = styled(
ControlIcons.REMOVE_CONTROL as AnyStyledComponent,
@@ -221,6 +222,30 @@ const RenderOptions = (props: {
return ;
};
+const RenderInput = (props: {
+ value: string;
+ onChange: (value: string) => void;
+}) => {
+ const debouncedOnChange = useCallback(debounce(props.onChange, 400), []);
+ const [value, setValue] = useState(props.value);
+ const onChange = (event: React.ChangeEvent) => {
+ const value = event.target.value;
+ setValue(value);
+ debouncedOnChange(value);
+ };
+ useEffect(() => {
+ setValue(props.value);
+ }, [props.value]);
+ return (
+
+ );
+};
+
type CascadeFieldProps = {
columns: DropdownOption[];
column: string;
@@ -402,10 +427,10 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
payload: condition,
});
};
- const onValueChange = (event: React.ChangeEvent) => {
+ const onValueChange = (value: string) => {
dispatch({
type: CascadeFieldActionTypes.CHANGE_VALUE,
- payload: event.target.value,
+ payload: value,
});
};
const onDateSelected = (date: string) => {
@@ -436,7 +461,6 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
payload: props,
});
}, [props]);
-
const {
operator,
column,
@@ -488,12 +512,7 @@ const Fields = (props: CascadeFieldProps & { state: CascadeFieldState }) => {
) : null}
{showInput ? (
-
+
) : null}
{showDateInput ? (
diff --git a/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx b/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
index 5252b3c80e..5190e0f925 100644
--- a/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/ReactTableComponent.tsx
@@ -305,7 +305,7 @@ const ReactTableComponent = (props: ReactTableComponentProps) => {
enableDrag={() => {
props.disableDrag(false);
}}
- searchTableData={debounce(props.searchTableData, 500)}
+ searchTableData={props.searchTableData}
filters={props.filters}
applyFilter={props.applyFilter}
compactMode={props.compactMode}
diff --git a/app/client/src/components/designSystems/appsmith/SearchComponent.tsx b/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
index 4ba4ee05f0..02b56c0036 100644
--- a/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/SearchComponent.tsx
@@ -1,6 +1,7 @@
import React from "react";
import styled from "styled-components";
import { InputGroup } from "@blueprintjs/core";
+import { debounce } from "lodash";
interface SearchProps {
onSearch: (value: any) => void;
@@ -25,6 +26,7 @@ class SearchComponent extends React.Component<
SearchProps,
{ localValue: string }
> {
+ onDebouncedSearch = debounce(this.props.onSearch, 400);
constructor(props: SearchProps) {
super(props);
this.state = {
@@ -45,7 +47,7 @@ class SearchComponent extends React.Component<
) => {
const search = event.target.value;
this.setState({ localValue: search });
- this.props.onSearch(search);
+ this.onDebouncedSearch(search);
};
render() {
return (
From 0685243534a7738b2eeb893a779a8c9c79fef573 Mon Sep 17 00:00:00 2001
From: devrk96
Date: Thu, 20 Aug 2020 16:12:45 +0530
Subject: [PATCH 12/14] tabs ui and textinput box-shadow fixed (#345)
Co-authored-by: Satbir Singh
---
app/client/src/components/ads/Tabs.tsx | 23 +++++++++++++++------
app/client/src/components/ads/TextInput.tsx | 5 ++++-
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/app/client/src/components/ads/Tabs.tsx b/app/client/src/components/ads/Tabs.tsx
index cad85e0622..c5ade3092e 100644
--- a/app/client/src/components/ads/Tabs.tsx
+++ b/app/client/src/components/ads/Tabs.tsx
@@ -10,7 +10,7 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
border-radius: 0px;
height: 100%;
.ads-icon {
- margin-right: ${props => props.theme.spaces[4]}px;
+ margin-right: ${props => props.theme.spaces[3]}px;
svg {
width: ${props => props.theme.spaces[9]}px;
height: ${props => props.theme.spaces[9]}px;
@@ -26,7 +26,8 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
.react-tabs__tab-list {
display: flex;
align-items: center;
- border-bottom: 2px solid ${props => props.theme.colors.blackShades[3]};
+ border-bottom: ${props => props.theme.spaces[1] - 2}px solid
+ ${props => props.theme.colors.blackShades[3]};
color: ${props => props.theme.colors.blackShades[6]};
path {
fill: ${props => props.theme.colors.blackShades[6]};
@@ -43,12 +44,14 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
display: flex;
align-items: center;
justify-content: flex-start;
- padding: 0 0 ${props => props.theme.spaces[2]}px 0;
+ padding: 0 0 ${props => props.theme.spaces[4]}px 0;
margin-right: ${props => props.theme.spaces[12] - 3}px;
text-align: center;
display: inline-flex;
align-items: center;
justify-content: center;
+ border-color: transparent;
+ position: relative;
}
.react-tabs__tab:hover {
color: ${props => props.theme.colors.blackShades[9]};
@@ -66,13 +69,21 @@ const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
}
.react-tabs__tab--selected {
color: ${props => props.theme.colors.blackShades[9]};
- border: 0px solid;
- border-bottom: ${props => props.theme.colors.info.main}
- ${props => props.theme.spaces[1] - 2}px solid;
background-color: transparent;
+
path {
fill: ${props => props.theme.colors.blackShades[9]};
}
+
+ &::after {
+ content: "";
+ position: absolute;
+ width: 100%;
+ bottom: ${props => props.theme.spaces[0] - 1}px;
+ left: ${props => props.theme.spaces[0]}px;
+ height: ${props => props.theme.spaces[1] - 2}px;
+ background-color: ${props => props.theme.colors.info.main};
+ }
}
.react-tabs__tab:focus:after {
content: none;
diff --git a/app/client/src/components/ads/TextInput.tsx b/app/client/src/components/ads/TextInput.tsx
index 18088dea06..05a531336a 100644
--- a/app/client/src/components/ads/TextInput.tsx
+++ b/app/client/src/components/ads/TextInput.tsx
@@ -59,7 +59,10 @@ const StyledInput = styled.input<
props.isValid
? props.theme.colors.info.main
: props.theme.colors.danger.main};
- box-shadow: 0px 0px 0px 4px rgba(203, 72, 16, 0.18);
+ box-shadow: ${props =>
+ props.isValid
+ ? "0px 0px 4px 4px rgba(203, 72, 16, 0.18)"
+ : "0px 0px 4px 4px rgba(226, 44, 44, 0.18)"};
}
&:disabled {
cursor: not-allowed;
From 3ae6c745b1791568cb102db906163d2ef20cfe17 Mon Sep 17 00:00:00 2001
From: Shrikant Sharat Kandula
Date: Thu, 20 Aug 2020 16:46:23 +0530
Subject: [PATCH 13/14] Initial implementation to import examples organization
as a migration (#290)
---
.../appsmith/server/constants/FieldName.java | 1 +
.../server/migrations/DatabaseChangelog.java | 138 +
.../main/resources/examples-organization.json | 2403 +++++++++++++++++
3 files changed, 2542 insertions(+)
create mode 100644 app/server/appsmith-server/src/main/resources/examples-organization.json
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/FieldName.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/FieldName.java
index 0658c7d52b..ea50cca00c 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/FieldName.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/FieldName.java
@@ -4,6 +4,7 @@ public class FieldName {
public static final String EMAIL = "email";
public static final String ORGANIZATION_ID = "organizationId";
public static final String DELETED = "deleted";
+ public static final String CREATED_AT = "createdAt";
public static final String DELETED_AT = "deletedAt";
public static String ORGANIZATION = "organization";
public static String ID = "id";
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java
index 24b73a6afc..e8e673a80c 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java
@@ -29,7 +29,12 @@ import com.appsmith.server.services.EncryptionService;
import com.appsmith.server.services.OrganizationService;
import com.github.cloudyrock.mongock.ChangeLog;
import com.github.cloudyrock.mongock.ChangeSet;
+import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
+import net.minidev.json.JSONObject;
+import org.apache.commons.lang.ObjectUtils;
+import org.bson.types.ObjectId;
+import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.UncategorizedMongoDbException;
@@ -38,11 +43,17 @@ import org.springframework.data.mongodb.core.index.CompoundIndexDefinition;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.util.CollectionUtils;
+import org.springframework.util.StreamUtils;
+import java.io.IOException;
+import java.nio.charset.Charset;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -653,4 +664,131 @@ public class DatabaseChangelog {
}
}
}
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @ChangeSet(order = "021", id = "examples-organization", author = "")
+ public void examplesOrganization(MongoTemplate mongoTemplate, EncryptionService encryptionService) throws IOException {
+ final Map plugins = new HashMap<>();
+
+ final List> organizationPlugins = mongoTemplate
+ .find(query(where("defaultInstall").is(true)), Plugin.class)
+ .stream()
+ .map(plugin -> {
+ assert plugin.getId() != null;
+ plugins.put(plugin.getPackageName(), plugin.getId());
+ return Map.of(
+ "pluginId", plugin.getId(),
+ "status", "FREE",
+ FieldName.DELETED, false,
+ "policies", Collections.emptyList()
+ );
+ })
+ .collect(Collectors.toList());
+ final String jsonContent = StreamUtils.copyToString(
+ new DefaultResourceLoader().getResource("examples-organization.json").getInputStream(),
+ Charset.defaultCharset()
+ );
+
+ final Map organization = new Gson().fromJson(jsonContent, HashMap.class);
+
+ final List> datasources = (List) organization.remove("$datasources");
+ final List> applications = (List) organization.remove("$applications");
+
+ organization.put("plugins", organizationPlugins);
+ organization.put(FieldName.CREATED_AT, Instant.now());
+ final Map insertedOrganization = mongoTemplate.insert(organization, mongoTemplate.getCollectionName(Organization.class));
+ final String organizationId = ((ObjectId) insertedOrganization.get("_id")).toHexString();
+
+ final Map datasourceIdsByName = new HashMap<>();
+
+ for (final Map datasource : datasources) {
+ datasource.put("pluginId", plugins.get(datasource.remove("$pluginPackageName")));
+ final Map authentication = (Map) ((Map) datasource.get("datasourceConfiguration")).get("authentication");
+ final String plainPassword = (String) authentication.get("password");
+ authentication.put("password", encryptionService.encryptString(plainPassword));
+ datasource.put(FieldName.ORGANIZATION_ID, organizationId);
+ datasource.put(FieldName.CREATED_AT, Instant.now());
+ final Map insertedDatasource = mongoTemplate.insert(datasource, mongoTemplate.getCollectionName(Datasource.class));
+ datasourceIdsByName.put((String) datasource.get("name"), ((ObjectId) insertedDatasource.get("_id")).toHexString());
+ }
+
+ for (final Map application : applications) {
+ final List> fullPages = (List) application.remove("$pages");
+ final List> embeddedPages = new ArrayList<>();
+
+ application.put(FieldName.ORGANIZATION_ID, organizationId);
+ mongoTemplate.insert(application, mongoTemplate.getCollectionName(Application.class));
+ final String applicationId = ((ObjectId) application.get("_id")).toHexString();
+
+ for (final Map fullPage : fullPages) {
+ final boolean isDefault = (boolean) fullPage.remove("$isDefault");
+
+ final List> actions = (List) ObjectUtils.defaultIfNull(
+ fullPage.remove("$actions"), Collections.emptyList());
+
+ final List> layouts = (List) fullPage.getOrDefault("layouts", Collections.emptyList());
+ for (final Map layout : layouts) {
+ layout.put("_id", new ObjectId());
+ }
+
+ fullPage.put("applicationId", applicationId);
+ fullPage.put(FieldName.CREATED_AT, Instant.now());
+ final Map insertedPage = mongoTemplate.insert(fullPage, mongoTemplate.getCollectionName(Page.class));
+ final String pageId = ((ObjectId) insertedPage.get("_id")).toHexString();
+ embeddedPages.add(Map.of(
+ "_id", pageId,
+ "isDefault", isDefault
+ ));
+
+ final Map actionIdsByName = new HashMap<>();
+ for (final Map action : actions) {
+ final Map datasource = (Map) action.get("datasource");
+ datasource.put("pluginId", plugins.get(datasource.remove("$pluginPackageName")));
+ datasource.put(FieldName.ORGANIZATION_ID, organizationId);
+ if (Boolean.FALSE.equals(datasource.remove("$isEmbedded"))) {
+ datasource.put("_id", new ObjectId(datasourceIdsByName.get(datasource.get("name"))));
+ }
+ action.put(FieldName.ORGANIZATION_ID, organizationId);
+ action.put("pageId", pageId);
+ action.put("pluginId", plugins.get(action.remove("$pluginPackageName")));
+ action.put(FieldName.CREATED_AT, Instant.now());
+ final Map insertedAction = mongoTemplate.insert(action, mongoTemplate.getCollectionName(Action.class));
+ actionIdsByName.put((String) action.get("name"), ((ObjectId) insertedAction.get("_id")).toHexString());
+ }
+
+ final List> layouts1 = (List) insertedPage.get("layouts");
+ for (Map layout : layouts1) {
+ final List>> onLoadActions = (List) layout.getOrDefault("layoutOnLoadActions", Collections.emptyList());
+ for (final List> actionSet : onLoadActions) {
+ for (final Map action : actionSet) {
+ action.put("_id", new ObjectId(actionIdsByName.get(action.get("name"))));
+ }
+ }
+ final List>> onLoadActions2 = (List) layout.getOrDefault("publishedLayoutOnLoadActions", Collections.emptyList());
+ for (final List> actionSet : onLoadActions2) {
+ for (final Map action : actionSet) {
+ action.put("_id", new ObjectId(actionIdsByName.get(action.get("name"))));
+ }
+ }
+ }
+ mongoTemplate.updateFirst(
+ query(where("_id").is(pageId)),
+ update("layouts", layouts1),
+ Page.class
+ );
+ }
+
+ application.put("pages", embeddedPages);
+ mongoTemplate.updateFirst(
+ query(where("_id").is(applicationId)),
+ update("pages", embeddedPages),
+ Application.class
+ );
+ }
+
+ Config config = new Config();
+ config.setName("template-organization");
+ config.setConfig(new JSONObject(Map.of("organizationId", organizationId)));
+ mongoTemplate.insert(config);
+ }
}
diff --git a/app/server/appsmith-server/src/main/resources/examples-organization.json b/app/server/appsmith-server/src/main/resources/examples-organization.json
new file mode 100644
index 0000000000..ef77b34cd9
--- /dev/null
+++ b/app/server/appsmith-server/src/main/resources/examples-organization.json
@@ -0,0 +1,2403 @@
+{
+ "name": "Example Apps",
+ "organizationSettings": [],
+ "slug": "example-apps",
+ "userRoles": [],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Organization",
+ "$datasources": [
+ {
+ "name": "Mock Db",
+ "$pluginPackageName": "postgres-plugin",
+ "datasourceConfiguration": {
+ "connection": {
+ "mode": "READ_WRITE"
+ },
+ "endpoints": [
+ {
+ "host": "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
+ "port": 5432
+ }
+ ],
+ "authentication": {
+ "username": "postgres",
+ "password": "Appsmith2019#",
+ "databaseName": "fakeapi"
+ },
+ "sshProxyEnabled": false
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Datasource"
+ }
+ ],
+ "$applications": [
+ {
+ "name": "Customer Support",
+ "isPublic": true,
+ "$pages": [
+ {
+ "name": "User Data",
+ "$isDefault": true,
+ "$actions": [
+ {
+ "name": "abc",
+ "datasource": {
+ "$isEmbedded": true,
+ "name": "DEFAULT_REST_DATASOURCE",
+ "$pluginPackageName": "restapi-plugin",
+ "datasourceConfiguration": {
+ "url": "http://mock-api.appsmith.com"
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": []
+ },
+ "actionConfiguration": {
+ "timeoutInMillisecond": 10000,
+ "paginationType": "NONE",
+ "path": "/user",
+ "headers": [
+ {
+ "key": "",
+ "value": ""
+ },
+ {
+ "key": "",
+ "value": ""
+ }
+ ],
+ "queryParameters": [
+ {
+ "key": "",
+ "value": ""
+ },
+ {
+ "key": "",
+ "value": ""
+ }
+ ],
+ "httpMethod": "GET"
+ },
+ "pluginType": "API",
+ "dynamicBindingPathList": [],
+ "isValid": true,
+ "invalids": [],
+ "jsonPathKeys": [],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Action"
+ },
+ {
+ "name": "approve_user",
+ "datasource": {
+ "$isEmbedded": false,
+ "name": "Mock Db",
+ "$pluginPackageName": "postgres-plugin",
+ "datasourceConfiguration": {
+ "connection": {
+ "mode": "READ_WRITE"
+ },
+ "endpoints": [
+ {
+ "host": "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
+ "port": 5432
+ }
+ ],
+ "authentication": {
+ "username": "postgres",
+ "password": "Appsmith2019#",
+ "databaseName": "fakeapi"
+ },
+ "sshProxyEnabled": false
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": []
+ },
+ "actionConfiguration": {
+ "timeoutInMillisecond": 10000,
+ "paginationType": "NONE",
+ "body": "UPDATE users\n SET status = 'APPROVED'\n WHERE id = {{usersTable.selectedRow.id}}\n"
+ },
+ "pluginType": "DB",
+ "dynamicBindingPathList": [
+ {
+ "key": "body"
+ }
+ ],
+ "isValid": true,
+ "invalids": [],
+ "jsonPathKeys": [
+ "usersTable.selectedRow.id"
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Action"
+ },
+ {
+ "name": "getUsers",
+ "datasource": {
+ "$isEmbedded": false,
+ "name": "Mock Db",
+ "$pluginPackageName": "postgres-plugin",
+ "datasourceConfiguration": {
+ "connection": {
+ "mode": "READ_WRITE"
+ },
+ "endpoints": [
+ {
+ "host": "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
+ "port": 5432
+ }
+ ],
+ "authentication": {
+ "username": "postgres",
+ "password": "Appsmith2019#",
+ "databaseName": "fakeapi"
+ },
+ "sshProxyEnabled": false
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": []
+ },
+ "actionConfiguration": {
+ "timeoutInMillisecond": 10000,
+ "paginationType": "NONE",
+ "body": "SELECT * FROM users where name ilike '%{{usersTable.searchText}}%' ORDER BY id LIMIT 10 offset {{(usersTable.pageNo - 1) * 10}}"
+ },
+ "pluginType": "DB",
+ "executeOnLoad": true,
+ "dynamicBindingPathList": [
+ {
+ "key": "body"
+ }
+ ],
+ "isValid": true,
+ "invalids": [],
+ "jsonPathKeys": [
+ "usersTable.searchText",
+ "(usersTable.pageNo - 1) * 10"
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Action"
+ },
+ {
+ "name": "reject_user",
+ "datasource": {
+ "$isEmbedded": false,
+ "name": "Mock Db",
+ "$pluginPackageName": "postgres-plugin",
+ "datasourceConfiguration": {
+ "connection": {
+ "mode": "READ_WRITE"
+ },
+ "endpoints": [
+ {
+ "host": "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
+ "port": 5432
+ }
+ ],
+ "authentication": {
+ "username": "postgres",
+ "password": "Appsmith2019#",
+ "databaseName": "fakeapi"
+ },
+ "sshProxyEnabled": false
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": []
+ },
+ "actionConfiguration": {
+ "timeoutInMillisecond": 10000,
+ "paginationType": "NONE",
+ "body": "UPDATE users\n SET status = 'REJECTED'\n WHERE id = {{usersTable.selectedRow.id}}\n"
+ },
+ "pluginType": "DB",
+ "dynamicBindingPathList": [
+ {
+ "key": "body"
+ }
+ ],
+ "isValid": true,
+ "invalids": [],
+ "jsonPathKeys": [
+ "usersTable.selectedRow.id"
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Action"
+ },
+ {
+ "name": "updateUser",
+ "datasource": {
+ "$isEmbedded": false,
+ "name": "Mock Db",
+ "$pluginPackageName": "postgres-plugin",
+ "datasourceConfiguration": {
+ "connection": {
+ "mode": "READ_WRITE"
+ },
+ "endpoints": [
+ {
+ "host": "fake-api.cvuydmurdlas.us-east-1.rds.amazonaws.com",
+ "port": 5432
+ }
+ ],
+ "authentication": {
+ "username": "postgres",
+ "password": "Appsmith2019#",
+ "databaseName": "fakeapi"
+ },
+ "sshProxyEnabled": false
+ },
+ "invalids": [],
+ "deleted": false,
+ "policies": []
+ },
+ "actionConfiguration": {
+ "timeoutInMillisecond": 10000,
+ "paginationType": "NONE",
+ "body": "UPDATE users SET name = '{{userNameInput.text}}', address = '{{userAddressDropdown.text}}', email = '{{userEmailInput.text}}', role = '{{userRoleDropdown.selectedOptionValue}}' WHERE id = {{usersTable.selectedRow.id}}"
+ },
+ "pluginType": "DB",
+ "dynamicBindingPathList": [
+ {
+ "key": "body"
+ }
+ ],
+ "isValid": true,
+ "invalids": [],
+ "jsonPathKeys": [
+ "userRoleDropdown.selectedOptionValue",
+ "userEmailInput.text",
+ "userNameInput.text",
+ "usersTable.selectedRow.id",
+ "userAddressDropdown.text"
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Action"
+ }
+ ],
+ "layouts": [
+ {
+ "viewMode": false,
+ "dsl": {
+ "widgetName": "MainContainer",
+ "backgroundColor": "none",
+ "rightColumn": 1224,
+ "snapColumns": 16,
+ "detachFromLayout": true,
+ "widgetId": "0",
+ "topRow": 0,
+ "bottomRow": 1480,
+ "containerStyle": "none",
+ "snapRows": 33,
+ "parentRowSpace": 1,
+ "type": "CANVAS_WIDGET",
+ "canExtend": true,
+ "dynamicBindings": {
+ },
+ "version": 5,
+ "minHeight": 1292,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Text1",
+ "rightColumn": 4,
+ "textAlign": "LEFT",
+ "widgetId": "weg5so2vr1",
+ "topRow": 1,
+ "bottomRow": 2,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "0",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "text": "Users ",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Modal1",
+ "rightColumn": 0,
+ "detachFromLayout": true,
+ "widgetId": "byv6k1tm4q",
+ "topRow": 0,
+ "bottomRow": 0,
+ "parentRowSpace": 1,
+ "isVisible": false,
+ "canOutsideClickClose": true,
+ "type": "MODAL_WIDGET",
+ "canEscapeKeyClose": true,
+ "dynamicBindings": {
+ },
+ "parentId": "0",
+ "shouldScrollContents": true,
+ "blueprint": {
+ "view": [
+ {
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "CANVAS_WIDGET",
+ "props": {
+ "shouldScrollContents": false,
+ "blueprint": {
+ "view": [
+ {
+ "size": {
+ "rows": 1,
+ "cols": 2
+ },
+ "position": {
+ "top": 0,
+ "left": 14
+ },
+ "type": "ICON_WIDGET",
+ "props": {
+ "color": "#040627",
+ "iconName": "cross",
+ "iconSize": 24
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 10
+ },
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "TEXT_WIDGET",
+ "props": {
+ "text": "Modal Title",
+ "textStyle": "HEADING"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 10
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "SECONDARY_BUTTON",
+ "text": "Cancel"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 13
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "PRIMARY_BUTTON",
+ "text": "Confirm"
+ }
+ }
+ ],
+ "operations": [
+ {
+ "type": "MODIFY_PROPS"
+ }
+ ]
+ },
+ "detachFromLayout": true,
+ "children": [],
+ "isVisible": true,
+ "isDisabled": false,
+ "canExtend": true
+ }
+ }
+ ]
+ },
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "size": "MODAL_LARGE",
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Canvas1",
+ "rightColumn": 0,
+ "detachFromLayout": true,
+ "widgetId": "w5pk5ifpbq",
+ "topRow": 0,
+ "bottomRow": 640,
+ "parentRowSpace": 1,
+ "isVisible": true,
+ "canExtend": true,
+ "type": "CANVAS_WIDGET",
+ "parentId": "byv6k1tm4q",
+ "shouldScrollContents": false,
+ "blueprint": {
+ "view": [
+ {
+ "size": {
+ "rows": 1,
+ "cols": 2
+ },
+ "position": {
+ "top": 0,
+ "left": 14
+ },
+ "type": "ICON_WIDGET",
+ "props": {
+ "color": "#040627",
+ "iconName": "cross",
+ "iconSize": 24
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 10
+ },
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "TEXT_WIDGET",
+ "props": {
+ "text": "Modal Title",
+ "textStyle": "HEADING"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 10
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "SECONDARY_BUTTON",
+ "text": "Cancel"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 13
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "PRIMARY_BUTTON",
+ "text": "Confirm"
+ }
+ }
+ ],
+ "operations": [
+ {
+ "type": "MODIFY_PROPS"
+ }
+ ]
+ },
+ "minHeight": 0,
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Icon1",
+ "rightColumn": 16,
+ "onClick": "{{closeModal('Modal1')}}",
+ "color": "#040627",
+ "iconName": "cross",
+ "widgetId": "3mbbjt4pzc",
+ "topRow": 0,
+ "bottomRow": 1,
+ "isVisible": true,
+ "type": "ICON_WIDGET",
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 14,
+ "iconSize": 24
+ },
+ {
+ "widgetName": "Text2",
+ "rightColumn": 10,
+ "textAlign": "LEFT",
+ "widgetId": "wcn8me2ef8",
+ "topRow": 0,
+ "bottomRow": 1,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 0,
+ "text": "{{func1}}",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Button1",
+ "rightColumn": 13,
+ "onClick": "{{closeModal('Modal1')}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "sz67dp5my1",
+ "dynamicProperties": {
+ },
+ "buttonStyle": "SECONDARY_BUTTON",
+ "topRow": 13,
+ "bottomRow": 14,
+ "isVisible": true,
+ "type": "BUTTON_WIDGET",
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 10,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Cancel",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Button2",
+ "rightColumn": 16,
+ "onClick": "{{updateUser.run(() => getUsers.run(() => { closeModal('Modal1') }), () => {})}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "tasjzaf7dn",
+ "dynamicProperties": {
+ "onClick": true
+ },
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 13,
+ "bottomRow": 14,
+ "isVisible": true,
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 13,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Update",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Text3",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "xuwf6yoz8o",
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Name",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userNameInput",
+ "rightColumn": 14,
+ "widgetId": "7w6gdpp20h",
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.name}}"
+ },
+ {
+ "widgetName": "Text4",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "ipq7sver55",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Email",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userEmailInput",
+ "rightColumn": 14,
+ "widgetId": "gmxr33ul94",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.email}}"
+ },
+ {
+ "widgetName": "Text5",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "qodaro6enw",
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Role",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userRoleDropdown",
+ "rightColumn": 14,
+ "widgetId": "ca93zv3q74",
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "DROP_DOWN_WIDGET",
+ "dynamicBindings": {
+ "defaultOptionValue": true,
+ "selectedOptionArr": true,
+ "isValid": true,
+ "selectedIndexArr": true,
+ "selectedOption": true,
+ "value": true,
+ "selectedIndex": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "defaultOptionValue": "{{usersTable.selectedRow.role}}",
+ "selectionType": "SINGLE_SELECT",
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "options": "[\n {\n \"label\": \"Admin\",\n \"value\": \"Admin\"\n },\n {\n \"label\": \"Editor\",\n \"value\": \"Editor\"\n },\n {\n \"label\": \"Viewer\",\n \"value\": \"Viewer\"\n }\n]"
+ },
+ {
+ "widgetName": "Text6",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "6kt0zxnjp2",
+ "topRow": 6,
+ "bottomRow": 7,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Address",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userAddressDropdown",
+ "rightColumn": 14,
+ "widgetId": "dvjvau3h01",
+ "topRow": 6,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.address}}"
+ },
+ {
+ "widgetName": "Text13",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "5kbrck0d80",
+ "topRow": 5,
+ "bottomRow": 6,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Gender",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Dropdown1",
+ "rightColumn": 14,
+ "widgetId": "ojpyrgnvll",
+ "topRow": 5,
+ "bottomRow": 6,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "DROP_DOWN_WIDGET",
+ "dynamicBindings": {
+ "defaultOptionValue": true,
+ "selectedOptionArr": true,
+ "isValid": true,
+ "selectedIndexArr": true,
+ "selectedOption": true,
+ "value": true,
+ "selectedIndex": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "defaultOptionValue": "{{usersTable.selectedRow.gender}}",
+ "selectionType": "SINGLE_SELECT",
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "options": "[\n {\n \"label\": \"Male\",\n \"value\": \"Male\"\n },\n {\n \"label\": \"Female\",\n \"value\": \"Female\"\n }\n]"
+ }
+ ],
+ "isDisabled": false
+ }
+ ]
+ },
+ {
+ "hiddenColumns": [
+ "updatedAt",
+ "gender",
+ "avatar",
+ "dob",
+ "address",
+ "status",
+ "createdAt"
+ ],
+ "widgetName": "usersTable",
+ "rightColumn": 10,
+ "columnOrder": [
+ "id",
+ "name",
+ "email",
+ "role",
+ "actions",
+ "createdAt",
+ "updatedAt",
+ "gender",
+ "avatar",
+ "dob"
+ ],
+ "widgetId": "4onx0po0j1",
+ "topRow": 2,
+ "bottomRow": 18,
+ "parentRowSpace": 40,
+ "onPageChange": "{{getUsers.run()}}",
+ "tableData": "{{getTable1Data.run()}}",
+ "isVisible": true,
+ "label": "Data",
+ "searchKey": "",
+ "type": "TABLE_WIDGET",
+ "dynamicBindings": {
+ "tableData": true,
+ "selectedRow": true,
+ "filteredTableData": true
+ },
+ "parentId": "0",
+ "serverSidePaginationEnabled": true,
+ "isLoading": false,
+ "onSearchTextChanged": "{{getUsers.run()}}",
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "dynamicTriggers": {
+ "onSearchTextChanged": true,
+ "onPageChange": true
+ },
+ "columnActions": [
+ {
+ "actionPayloads": [],
+ "label": "Edit",
+ "id": "inz6ivtcdt",
+ "dynamicTrigger": "{{showModal('Modal1')}}"
+ }
+ ],
+ "columnSizeMap": {
+ "address": 238,
+ "id": 91,
+ "email": 236
+ }
+ },
+ {
+ "backgroundColor": "#FFFFFF",
+ "widgetName": "Container1",
+ "rightColumn": 16,
+ "widgetId": "znedt4bss1",
+ "containerStyle": "card",
+ "topRow": 2,
+ "bottomRow": 12,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "CONTAINER_WIDGET",
+ "parentId": "0",
+ "blueprint": {
+ "view": [
+ {
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "CANVAS_WIDGET",
+ "props": {
+ "detachFromLayout": true,
+ "children": [
+ "2rv46ko5nr",
+ "6jz7n81a0w",
+ "pu5tfgbgs8",
+ "1dqi8yqken",
+ "rhjs3oqi4x",
+ "12b8ga1jyb",
+ "fow2t5em1j",
+ "95hllivp93",
+ "mme1t8c9py"
+ ],
+ "containerStyle": "none",
+ "canExtend": false
+ }
+ }
+ ]
+ },
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 10,
+ "children": [
+ {
+ "widgetName": "Canvas2",
+ "rightColumn": 592,
+ "detachFromLayout": true,
+ "widgetId": "lz32lxsbsd",
+ "containerStyle": "none",
+ "topRow": 0,
+ "bottomRow": 400,
+ "parentRowSpace": 1,
+ "isVisible": true,
+ "canExtend": false,
+ "type": "CANVAS_WIDGET",
+ "parentId": "znedt4bss1",
+ "minHeight": 400,
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "image": "{{usersTable.selectedRow.avatar}}",
+ "widgetName": "Image1",
+ "rightColumn": 6,
+ "widgetId": "2rv46ko5nr",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 0,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "IMAGE_WIDGET",
+ "dynamicBindings": {
+ "image": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "imageShape": "RECTANGLE",
+ "leftColumn": 0,
+ "defaultImage": "https://res.cloudinary.com/drako999/image/upload/v1589196259/default.png"
+ },
+ {
+ "widgetName": "Text7",
+ "rightColumn": 13,
+ "textAlign": "LEFT",
+ "widgetId": "6jz7n81a0w",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.name}}",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Text8",
+ "rightColumn": 16,
+ "textAlign": "LEFT",
+ "widgetId": "pu5tfgbgs8",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 1,
+ "bottomRow": 2,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.email}}",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Text9",
+ "rightColumn": 16,
+ "textAlign": "LEFT",
+ "widgetId": "1dqi8yqken",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.address}}",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Text11",
+ "rightColumn": 16,
+ "textAlign": "CENTER",
+ "widgetId": "rhjs3oqi4x",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 6,
+ "bottomRow": 7,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 0,
+ "text": " Status: {{usersTable.selectedRow.status === \"APPROVED\" ? \"Approved ✅\" : \nusersTable.selectedRow.status === \"REJECTED\" ? \"Rejected ❌\" : \"Pending ⌛\"}} ",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Text12",
+ "rightColumn": 11,
+ "textAlign": "LEFT",
+ "widgetId": "12b8ga1jyb",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{ (usersTable.selectedRow.gender === \"Male\" ? \"♂️\" : \"♀️\") + usersTable.selectedRow.gender}}",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Button3",
+ "rightColumn": 16,
+ "onClick": "{{approve_user.run(() => getUsers.run(), () => {})}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "fow2t5em1j",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 8,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 11,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Approve",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Button4",
+ "rightColumn": 16,
+ "onClick": "{{showModal('Modal1')}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "95hllivp93",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 13,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Edit",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Button5",
+ "rightColumn": 10,
+ "onClick": "{{reject_user.run(() => getUsers.run(), () => {})}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "4z16xr3mlu",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "buttonStyle": "SECONDARY_BUTTON",
+ "topRow": 8,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 5,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "❌Reject",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Text10",
+ "rightColumn": 16,
+ "textAlign": "CENTER",
+ "widgetId": "rz1jcja6o2",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow === undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "0",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "text": "👈🏿 Select a user ",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Text14",
+ "rightColumn": 16,
+ "textAlign": "LEFT",
+ "widgetId": "op0ououevb",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 12,
+ "text": "{{ (usersTable.selectedRow.role === \"Admin\" ? \"👮\" : usersTable.selectedRow.role === \"Editor\" ? \"🖋️\" : \"🔍\") + usersTable.selectedRow.role}}",
+ "textStyle": "LABEL"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "publishedDsl": {
+ "widgetName": "MainContainer",
+ "backgroundColor": "none",
+ "rightColumn": 1224,
+ "snapColumns": 16,
+ "detachFromLayout": true,
+ "widgetId": "0",
+ "topRow": 0,
+ "bottomRow": 1560,
+ "containerStyle": "none",
+ "snapRows": 33,
+ "parentRowSpace": 1,
+ "type": "CANVAS_WIDGET",
+ "canExtend": true,
+ "dynamicBindings": {
+ },
+ "version": 5,
+ "minHeight": 1292,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Text1",
+ "rightColumn": 4,
+ "textAlign": "LEFT",
+ "widgetId": "weg5so2vr1",
+ "topRow": 1,
+ "bottomRow": 2,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "0",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "text": "Users ",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Modal1",
+ "rightColumn": 0,
+ "detachFromLayout": true,
+ "widgetId": "byv6k1tm4q",
+ "topRow": 0,
+ "bottomRow": 0,
+ "parentRowSpace": 1,
+ "isVisible": false,
+ "canOutsideClickClose": true,
+ "type": "MODAL_WIDGET",
+ "canEscapeKeyClose": true,
+ "dynamicBindings": {
+ },
+ "parentId": "0",
+ "shouldScrollContents": true,
+ "blueprint": {
+ "view": [
+ {
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "CANVAS_WIDGET",
+ "props": {
+ "shouldScrollContents": false,
+ "blueprint": {
+ "view": [
+ {
+ "size": {
+ "rows": 1,
+ "cols": 2
+ },
+ "position": {
+ "top": 0,
+ "left": 14
+ },
+ "type": "ICON_WIDGET",
+ "props": {
+ "color": "#040627",
+ "iconName": "cross",
+ "iconSize": 24
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 10
+ },
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "TEXT_WIDGET",
+ "props": {
+ "text": "Modal Title",
+ "textStyle": "HEADING"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 10
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "SECONDARY_BUTTON",
+ "text": "Cancel"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 13
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "PRIMARY_BUTTON",
+ "text": "Confirm"
+ }
+ }
+ ],
+ "operations": [
+ {
+ "type": "MODIFY_PROPS"
+ }
+ ]
+ },
+ "detachFromLayout": true,
+ "children": [],
+ "isVisible": true,
+ "isDisabled": false,
+ "canExtend": true
+ }
+ }
+ ]
+ },
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "size": "MODAL_LARGE",
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Canvas1",
+ "rightColumn": 0,
+ "detachFromLayout": true,
+ "widgetId": "w5pk5ifpbq",
+ "topRow": 0,
+ "bottomRow": 640,
+ "parentRowSpace": 1,
+ "isVisible": true,
+ "canExtend": true,
+ "type": "CANVAS_WIDGET",
+ "parentId": "byv6k1tm4q",
+ "shouldScrollContents": false,
+ "blueprint": {
+ "view": [
+ {
+ "size": {
+ "rows": 1,
+ "cols": 2
+ },
+ "position": {
+ "top": 0,
+ "left": 14
+ },
+ "type": "ICON_WIDGET",
+ "props": {
+ "color": "#040627",
+ "iconName": "cross",
+ "iconSize": 24
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 10
+ },
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "TEXT_WIDGET",
+ "props": {
+ "text": "Modal Title",
+ "textStyle": "HEADING"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 10
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "SECONDARY_BUTTON",
+ "text": "Cancel"
+ }
+ },
+ {
+ "size": {
+ "rows": 1,
+ "cols": 3
+ },
+ "position": {
+ "top": 4,
+ "left": 13
+ },
+ "type": "BUTTON_WIDGET",
+ "props": {
+ "buttonStyle": "PRIMARY_BUTTON",
+ "text": "Confirm"
+ }
+ }
+ ],
+ "operations": [
+ {
+ "type": "MODIFY_PROPS"
+ }
+ ]
+ },
+ "minHeight": 0,
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "widgetName": "Icon1",
+ "rightColumn": 16,
+ "onClick": "{{closeModal('Modal1')}}",
+ "color": "#040627",
+ "iconName": "cross",
+ "widgetId": "3mbbjt4pzc",
+ "topRow": 0,
+ "bottomRow": 1,
+ "isVisible": true,
+ "type": "ICON_WIDGET",
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 14,
+ "iconSize": 24
+ },
+ {
+ "widgetName": "Text2",
+ "rightColumn": 10,
+ "textAlign": "LEFT",
+ "widgetId": "wcn8me2ef8",
+ "topRow": 0,
+ "bottomRow": 1,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 0,
+ "text": "User Data",
+ "textStyle": "HEADING"
+ },
+ {
+ "widgetName": "Button1",
+ "rightColumn": 13,
+ "onClick": "{{closeModal('Modal1')}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "sz67dp5my1",
+ "dynamicProperties": {
+ },
+ "buttonStyle": "SECONDARY_BUTTON",
+ "topRow": 13,
+ "bottomRow": 14,
+ "isVisible": true,
+ "type": "BUTTON_WIDGET",
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 10,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Cancel",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Button2",
+ "rightColumn": 16,
+ "onClick": "{{updateUser.run(() => getUsers.run(() => { closeModal('Modal1') }), () => {})}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "tasjzaf7dn",
+ "dynamicProperties": {
+ "onClick": true
+ },
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 13,
+ "bottomRow": 14,
+ "isVisible": true,
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "leftColumn": 13,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Update",
+ "isDisabled": false
+ },
+ {
+ "widgetName": "Text3",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "xuwf6yoz8o",
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Name",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userNameInput",
+ "rightColumn": 14,
+ "widgetId": "7w6gdpp20h",
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.name}}"
+ },
+ {
+ "widgetName": "Text4",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "ipq7sver55",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Email",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userEmailInput",
+ "rightColumn": 14,
+ "widgetId": "gmxr33ul94",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.email}}"
+ },
+ {
+ "widgetName": "Text5",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "qodaro6enw",
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Role",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userRoleDropdown",
+ "rightColumn": 14,
+ "widgetId": "ca93zv3q74",
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "DROP_DOWN_WIDGET",
+ "dynamicBindings": {
+ "defaultOptionValue": true,
+ "selectedOptionArr": true,
+ "isValid": true,
+ "selectedIndexArr": true,
+ "selectedOption": true,
+ "value": true,
+ "selectedIndex": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "defaultOptionValue": "{{usersTable.selectedRow.role}}",
+ "selectionType": "SINGLE_SELECT",
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "options": "[\n {\n \"label\": \"Admin\",\n \"value\": \"Admin\"\n },\n {\n \"label\": \"Editor\",\n \"value\": \"Editor\"\n },\n {\n \"label\": \"Viewer\",\n \"value\": \"Viewer\"\n }\n]"
+ },
+ {
+ "widgetName": "Text6",
+ "rightColumn": 4,
+ "textAlign": "RIGHT",
+ "widgetId": "6kt0zxnjp2",
+ "topRow": 6,
+ "bottomRow": 7,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 0,
+ "text": "Address",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "userAddressDropdown",
+ "rightColumn": 14,
+ "widgetId": "dvjvau3h01",
+ "topRow": 6,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "label": "",
+ "type": "INPUT_WIDGET",
+ "dynamicBindings": {
+ "isValid": true,
+ "defaultText": true,
+ "value": true
+ },
+ "parentId": "w5pk5ifpbq",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "leftColumn": 4,
+ "inputType": "TEXT",
+ "defaultText": "{{usersTable.selectedRow.address}}"
+ },
+ {
+ "isVisible": true,
+ "text": "Gender",
+ "textStyle": "LABEL",
+ "textAlign": "RIGHT",
+ "widgetName": "Text13",
+ "type": "TEXT_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "parentRowSpace": 40,
+ "leftColumn": 0,
+ "rightColumn": 4,
+ "topRow": 5,
+ "bottomRow": 6,
+ "parentId": "w5pk5ifpbq",
+ "widgetId": "5kbrck0d80",
+ "dynamicBindings": {
+ "value": true
+ }
+ },
+ {
+ "isVisible": true,
+ "label": "",
+ "selectionType": "SINGLE_SELECT",
+ "options": "[\n {\n \"label\": \"Male\",\n \"value\": \"Male\"\n },\n {\n \"label\": \"Female\",\n \"value\": \"Female\"\n }\n]",
+ "widgetName": "Dropdown1",
+ "defaultOptionValue": "{{usersTable.selectedRow.gender}}",
+ "type": "DROP_DOWN_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 30.75,
+ "parentRowSpace": 40,
+ "leftColumn": 4,
+ "rightColumn": 14,
+ "topRow": 5,
+ "bottomRow": 6,
+ "parentId": "w5pk5ifpbq",
+ "widgetId": "ojpyrgnvll",
+ "dynamicBindings": {
+ "isValid": true,
+ "selectedOption": true,
+ "selectedOptionArr": true,
+ "selectedIndex": true,
+ "selectedIndexArr": true,
+ "value": true,
+ "defaultOptionValue": true
+ }
+ }
+ ],
+ "isDisabled": false
+ }
+ ]
+ },
+ {
+ "hiddenColumns": [
+ "updatedAt",
+ "gender",
+ "avatar",
+ "dob",
+ "address",
+ "status",
+ "createdAt"
+ ],
+ "widgetName": "usersTable",
+ "rightColumn": 10,
+ "columnOrder": [
+ "id",
+ "name",
+ "email",
+ "role",
+ "actions",
+ "createdAt",
+ "updatedAt",
+ "gender",
+ "avatar",
+ "dob"
+ ],
+ "widgetId": "4onx0po0j1",
+ "topRow": 2,
+ "bottomRow": 18,
+ "parentRowSpace": 40,
+ "onPageChange": "{{getUsers.run()}}",
+ "tableData": "{{getUsers.data}}",
+ "isVisible": true,
+ "label": "Data",
+ "searchKey": "",
+ "type": "TABLE_WIDGET",
+ "dynamicBindings": {
+ "tableData": true,
+ "selectedRow": true,
+ "filteredTableData": true
+ },
+ "parentId": "0",
+ "serverSidePaginationEnabled": true,
+ "isLoading": false,
+ "onSearchTextChanged": "{{getUsers.run()}}",
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "dynamicTriggers": {
+ "onSearchTextChanged": true,
+ "onPageChange": true
+ },
+ "columnActions": [
+ {
+ "actionPayloads": [],
+ "label": "Edit",
+ "id": "inz6ivtcdt",
+ "dynamicTrigger": "{{showModal('Modal1')}}"
+ }
+ ],
+ "columnSizeMap": {
+ "address": 238,
+ "id": 91,
+ "email": 236
+ }
+ },
+ {
+ "backgroundColor": "#FFFFFF",
+ "widgetName": "Container1",
+ "rightColumn": 16,
+ "widgetId": "znedt4bss1",
+ "containerStyle": "card",
+ "topRow": 2,
+ "bottomRow": 12,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "CONTAINER_WIDGET",
+ "parentId": "0",
+ "blueprint": {
+ "view": [
+ {
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "type": "CANVAS_WIDGET",
+ "props": {
+ "detachFromLayout": true,
+ "children": [
+ "2rv46ko5nr",
+ "6jz7n81a0w",
+ "pu5tfgbgs8",
+ "1dqi8yqken",
+ "rhjs3oqi4x",
+ "12b8ga1jyb",
+ "fow2t5em1j",
+ "95hllivp93",
+ "mme1t8c9py"
+ ],
+ "containerStyle": "none",
+ "canExtend": false
+ }
+ }
+ ]
+ },
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 10,
+ "children": [
+ {
+ "widgetName": "Canvas2",
+ "rightColumn": 592,
+ "detachFromLayout": true,
+ "widgetId": "lz32lxsbsd",
+ "containerStyle": "none",
+ "topRow": 0,
+ "bottomRow": 400,
+ "parentRowSpace": 1,
+ "isVisible": true,
+ "canExtend": false,
+ "type": "CANVAS_WIDGET",
+ "parentId": "znedt4bss1",
+ "minHeight": 400,
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "leftColumn": 0,
+ "children": [
+ {
+ "image": "{{usersTable.selectedRow.avatar}}",
+ "widgetName": "Image1",
+ "rightColumn": 6,
+ "widgetId": "2rv46ko5nr",
+ "topRow": 0,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "IMAGE_WIDGET",
+ "dynamicBindings": {
+ "image": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "imageShape": "RECTANGLE",
+ "leftColumn": 0,
+ "defaultImage": "https://res.cloudinary.com/drako999/image/upload/v1589196259/default.png",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Text7",
+ "rightColumn": 13,
+ "textAlign": "LEFT",
+ "widgetId": "6jz7n81a0w",
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.name}}",
+ "textStyle": "LABEL",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Text8",
+ "rightColumn": 16,
+ "textAlign": "LEFT",
+ "widgetId": "pu5tfgbgs8",
+ "topRow": 1,
+ "bottomRow": 2,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.email}}",
+ "textStyle": "LABEL",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Text9",
+ "rightColumn": 16,
+ "textAlign": "LEFT",
+ "widgetId": "1dqi8yqken",
+ "topRow": 2,
+ "bottomRow": 3,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{usersTable.selectedRow.address}}",
+ "textStyle": "LABEL",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Text11",
+ "rightColumn": 16,
+ "textAlign": "CENTER",
+ "widgetId": "rhjs3oqi4x",
+ "topRow": 6,
+ "bottomRow": 7,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true,
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 0,
+ "text": " Status: {{usersTable.selectedRow.status === \"APPROVED\" ? \"Approved ✅\" : \nusersTable.selectedRow.status === \"REJECTED\" ? \"Rejected ❌\" : \"Pending ⌛\"}} ",
+ "textStyle": "HEADING",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Text12",
+ "rightColumn": 11,
+ "textAlign": "LEFT",
+ "widgetId": "12b8ga1jyb",
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentRowSpace": 40,
+ "isVisible": true,
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "text": true,
+ "value": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 7,
+ "text": "{{ (usersTable.selectedRow.gender === \"Male\" ? \"♂️\" : \"♀️\") + usersTable.selectedRow.gender}}",
+ "textStyle": "LABEL"
+ },
+ {
+ "widgetName": "Button3",
+ "rightColumn": 16,
+ "isDefaultClickDisabled": true,
+ "widgetId": "fow2t5em1j",
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 8,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 11,
+ "text": "Approve",
+ "isDisabled": false,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "onClick": "{{approve_user.run(() => getUsers.run(), () => {})}}",
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Button4",
+ "rightColumn": 16,
+ "onClick": "{{showModal('Modal1')}}",
+ "isDefaultClickDisabled": true,
+ "widgetId": "95hllivp93",
+ "buttonStyle": "PRIMARY_BUTTON",
+ "topRow": 0,
+ "bottomRow": 1,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 13,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "text": "Edit",
+ "isDisabled": false,
+ "dynamicProperties": {
+ "isVisible": true
+ }
+ },
+ {
+ "widgetName": "Button5",
+ "rightColumn": 10,
+ "isDefaultClickDisabled": true,
+ "widgetId": "4z16xr3mlu",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "buttonStyle": "SECONDARY_BUTTON",
+ "topRow": 8,
+ "bottomRow": 9,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow !== undefined}}",
+ "type": "BUTTON_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true
+ },
+ "parentId": "lz32lxsbsd",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "leftColumn": 5,
+ "text": "❌Reject",
+ "isDisabled": false,
+ "dynamicTriggers": {
+ "onClick": true
+ },
+ "onClick": "{{reject_user.run(() => getUsers.run(), () => {})}}"
+ },
+ {
+ "widgetName": "Text10",
+ "rightColumn": 16,
+ "textAlign": "CENTER",
+ "widgetId": "rz1jcja6o2",
+ "dynamicProperties": {
+ "isVisible": true
+ },
+ "topRow": 4,
+ "bottomRow": 5,
+ "parentRowSpace": 40,
+ "isVisible": "{{usersTable.selectedRow === undefined}}",
+ "type": "TEXT_WIDGET",
+ "dynamicBindings": {
+ "isVisible": true,
+ "value": true
+ },
+ "parentId": "0",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "leftColumn": 0,
+ "text": "👈🏿 Select a user ",
+ "textStyle": "HEADING"
+ },
+ {
+ "isVisible": true,
+ "text": "{{ (usersTable.selectedRow.role === \"Admin\" ? \"👮\" : usersTable.selectedRow.role === \"Editor\" ? \"🖋️\" : \"🔍\") + usersTable.selectedRow.role}}",
+ "textStyle": "LABEL",
+ "textAlign": "LEFT",
+ "widgetName": "Text14",
+ "type": "TEXT_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 25.25,
+ "parentRowSpace": 40,
+ "leftColumn": 12,
+ "rightColumn": 16,
+ "topRow": 3,
+ "bottomRow": 4,
+ "parentId": "lz32lxsbsd",
+ "widgetId": "op0ououevb",
+ "dynamicBindings": {
+ "text": true,
+ "value": true
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "isVisible": true,
+ "shouldScrollContents": false,
+ "widgetName": "Tabs1",
+ "tabs": [
+ {
+ "label": "Tab 1",
+ "id": "tab1"
+ },
+ {
+ "label": "Tab 2",
+ "id": "tab2"
+ }
+ ],
+ "selectedTab": "Tab 1",
+ "blueprint": {
+ "view": [
+ {
+ "type": "CANVAS_WIDGET",
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "size": {
+ "rows": 6,
+ "cols": 16
+ },
+ "props": {
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "children": [],
+ "tabId": "tab1"
+ }
+ },
+ {
+ "type": "CANVAS_WIDGET",
+ "position": {
+ "top": 0,
+ "left": 0
+ },
+ "size": {
+ "rows": 6,
+ "cols": 16
+ },
+ "props": {
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "children": [
+ "lkn2q6gati"
+ ],
+ "tabId": "tab2"
+ }
+ }
+ ]
+ },
+ "type": "TABS_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 74,
+ "parentRowSpace": 40,
+ "leftColumn": 0,
+ "rightColumn": 9,
+ "topRow": 20,
+ "bottomRow": 37,
+ "parentId": "0",
+ "widgetId": "2kmt5gdvho",
+ "children": [
+ {
+ "isVisible": true,
+ "widgetName": "Canvas3",
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "children": [],
+ "tabId": "tab1",
+ "minHeight": 280,
+ "type": "CANVAS_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "parentRowSpace": 1,
+ "leftColumn": 0,
+ "rightColumn": 592,
+ "topRow": 0,
+ "bottomRow": 280,
+ "parentId": "2kmt5gdvho",
+ "widgetId": "eo5744d1ac"
+ },
+ {
+ "isVisible": true,
+ "widgetName": "Canvas4",
+ "containerStyle": "none",
+ "canExtend": false,
+ "detachFromLayout": true,
+ "children": [
+ {
+ "isVisible": true,
+ "label": "",
+ "options": [
+ {
+ "id": "1",
+ "label": "Male",
+ "value": "M"
+ },
+ {
+ "id": "2",
+ "label": "Female",
+ "value": "F"
+ }
+ ],
+ "defaultOptionValue": "M",
+ "widgetName": "RadioGroup1",
+ "type": "RADIO_GROUP_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 39.125,
+ "parentRowSpace": 40,
+ "leftColumn": 6,
+ "rightColumn": 9,
+ "topRow": 1,
+ "bottomRow": 3,
+ "parentId": "tc29qir6tk",
+ "widgetId": "lkn2q6gati"
+ }
+ ],
+ "tabId": "tab2",
+ "minHeight": 280,
+ "type": "CANVAS_WIDGET",
+ "isLoading": false,
+ "parentColumnSpace": 1,
+ "parentRowSpace": 1,
+ "leftColumn": 0,
+ "rightColumn": 592,
+ "topRow": 0,
+ "bottomRow": 280,
+ "parentId": "2kmt5gdvho",
+ "widgetId": "tc29qir6tk"
+ }
+ ]
+ }
+ ]
+ },
+ "layoutOnLoadActions": [
+ [
+ {
+ "name": "getUsers",
+ "pluginType": "DB",
+ "jsonPathKeys": [
+ "usersTable.searchText",
+ "(usersTable.pageNo - 1) * 10"
+ ],
+ "timeoutInMillisecond": 10000
+ }
+ ]
+ ],
+ "publishedLayoutOnLoadActions": [
+ [
+ {
+ "name": "getUsers",
+ "pluginType": "DB",
+ "jsonPathKeys": [
+ "usersTable.searchText",
+ "(usersTable.pageNo - 1) * 10"
+ ],
+ "timeoutInMillisecond": 10000
+ }
+ ]
+ ],
+ "widgetNames": [
+ "Text9",
+ "Button1",
+ "Text8",
+ "Text7",
+ "Text6",
+ "Text5",
+ "Text4",
+ "Text3",
+ "userAddressDropdown",
+ "Text2",
+ "Container1",
+ "Text1",
+ "Icon1",
+ "usersTable",
+ "userNameInput",
+ "userEmailInput",
+ "userRoleDropdown",
+ "Image1",
+ "Text14",
+ "MainContainer",
+ "Text12",
+ "Text13",
+ "Text10",
+ "Text11",
+ "Modal1",
+ "Canvas1",
+ "Canvas2",
+ "Button5",
+ "Button4",
+ "Button3",
+ "Button2",
+ "Dropdown1"
+ ],
+ "deleted": false,
+ "policies": []
+ }
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Page"
+ }
+ ],
+ "deleted": false,
+ "policies": [],
+ "_class": "com.appsmith.server.domains.Application"
+ }
+ ]
+}
From 4617a87686cfa7f52a26efdcb6412a0663e5fce2 Mon Sep 17 00:00:00 2001
From: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com>
Date: Thu, 20 Aug 2020 16:48:10 +0530
Subject: [PATCH 14/14] Feature test/search delay (#369)
- Add a delay after adding a entity search text, to accommodate debounce and search computations
---
app/client/cypress/support/commands.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/app/client/cypress/support/commands.js b/app/client/cypress/support/commands.js
index f6916b3b44..87da3f2c72 100644
--- a/app/client/cypress/support/commands.js
+++ b/app/client/cypress/support/commands.js
@@ -290,6 +290,7 @@ Cypress.Commands.add("SearchEntity", (apiname1, apiname2) => {
cy.get(commonlocators.entityExplorersearch)
.clear()
.type(apiname1);
+ cy.wait(500);
cy.get(
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
).should("be.visible");
@@ -303,6 +304,7 @@ Cypress.Commands.add("GlobalSearchEntity", apiname1 => {
cy.get(commonlocators.entityExplorersearch)
.clear()
.type(apiname1);
+ cy.wait(500);
cy.get(
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
).should("be.visible");
@@ -451,6 +453,7 @@ Cypress.Commands.add("SearchEntityandOpen", apiname1 => {
cy.get(commonlocators.entityExplorersearch)
.clear()
.type(apiname1);
+ cy.wait(500);
cy.get(
commonlocators.entitySearchResult.concat(apiname1).concat("')"),
).should("be.visible");