diff --git a/README.md b/README.md index 2773d678c6..f66b49a150 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,6 @@

-

- Built with empathy, not just ❤︎ -

----------------- diff --git a/app/client/cypress/fixtures/Js_toggle_dsl.json b/app/client/cypress/fixtures/Js_toggle_dsl.json new file mode 100644 index 0000000000..4db1c4d77e --- /dev/null +++ b/app/client/cypress/fixtures/Js_toggle_dsl.json @@ -0,0 +1,79 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 1224, + "snapColumns": 16, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 1280, + "containerStyle": "none", + "snapRows": 33, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "dynamicBindings": {}, + "version": 6, + "minHeight": 1292, + "parentColumnSpace": 1, + "leftColumn": 0, + "children": [ + { + "isVisible": true, + "text": "Submit", + "buttonStyle": "PRIMARY_BUTTON", + "widgetName": "Button1", + "isDisabled": false, + "isDefaultClickDisabled": true, + "type": "BUTTON_WIDGET", + "isLoading": false, + "parentColumnSpace": 74, + "parentRowSpace": 40, + "leftColumn": 1, + "rightColumn": 3, + "topRow": 1, + "bottomRow": 2, + "parentId": "0", + "widgetId": "p4777z9d4u", + "dynamicProperties": {} + }, + { + "isVisible": true, + "inputType": "TEXT", + "label": "", + "widgetName": "Input1", + "type": "INPUT_WIDGET", + "isLoading": false, + "parentColumnSpace": 74, + "parentRowSpace": 40, + "leftColumn": 4, + "rightColumn": 9, + "topRow": 1, + "bottomRow": 2, + "parentId": "0", + "widgetId": "8pdmbhmd1p" + }, + { + "isVisible": true, + "label": "", + "selectionType": "SINGLE_SELECT", + "options": "[{'label':'Vegetarian','value':'VEG'},{'label':'Non-Vegetarian','value':'NON_VEG'},{'label':'Vegan','value':'VEGAN'}]", + "widgetName": "Dropdown1", + "defaultOptionValue": "VEG", + "type": "DROP_DOWN_WIDGET", + "isLoading": false, + "parentColumnSpace": 74, + "parentRowSpace": 40, + "leftColumn": 10, + "rightColumn": 15, + "topRow": 1, + "bottomRow": 2, + "parentId": "0", + "widgetId": "cxum96myhf", + "dynamicBindings": {} + } + ] + }, + "layoutOnLoadActions": [] +} diff --git a/app/client/cypress/fixtures/PageLoadDsl.json b/app/client/cypress/fixtures/PageLoadDsl.json new file mode 100644 index 0000000000..20745bcd98 --- /dev/null +++ b/app/client/cypress/fixtures/PageLoadDsl.json @@ -0,0 +1,43 @@ +{ + "dsl": { + "widgetName": "MainContainer", + "backgroundColor": "none", + "rightColumn": 1224, + "snapColumns": 16, + "detachFromLayout": true, + "widgetId": "0", + "topRow": 0, + "bottomRow": 1280, + "containerStyle": "none", + "snapRows": 33, + "parentRowSpace": 1, + "type": "CANVAS_WIDGET", + "canExtend": true, + "dynamicBindings": {}, + "version": 6, + "minHeight": 1292, + "parentColumnSpace": 1, + "leftColumn": 0, + "children": [ + { + "isVisible": true, + "text": "This is Page 1", + "textStyle": "HEADING", + "textAlign": "LEFT", + "widgetName": "Text1", + "type": "TEXT_WIDGET", + "isLoading": false, + "parentColumnSpace": 74, + "parentRowSpace": 40, + "leftColumn": 6, + "rightColumn": 10, + "topRow": 2, + "bottomRow": 4, + "parentId": "0", + "widgetId": "g338165fyp", + "dynamicBindings": {} + } + ] + }, + "layoutOnLoadActions": [] +} diff --git a/app/client/cypress/fixtures/example.json b/app/client/cypress/fixtures/example.json index ce5bfcd2b5..9185329078 100644 --- a/app/client/cypress/fixtures/example.json +++ b/app/client/cypress/fixtures/example.json @@ -110,7 +110,7 @@ "RichTextEditorName": "RichtextEditor", "HtmlText": "This is the initialcontent

This is a Heading

This is a paragraph.

", "RichTexteditorBody": "Here is the text area to edit html", - "userApi": "http://postgrest.appsmith.com:3000", + "userApi": "http://mock-api.appsmith.com", "validateImage": "https://cdn.dribbble.com/users/1787323/screenshots/4563995/dribbbe_hammer-01.png", "defaultdata": "TestData", "label": "one", @@ -174,4 +174,4 @@ ], "paginationUrl": "https://mock-api.appsmith.com/", "paginationParam": "users?page={{Table1.pageNo}}&size={{Table1.pageSize }}" -} \ No newline at end of file +} diff --git a/app/client/cypress/integration/Smoke_TestSuite/Binding/Bind_tableApi_spec.js b/app/client/cypress/integration/Smoke_TestSuite/Binding/Bind_tableApi_spec.js index d833b0b01f..bb5df992a9 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/Binding/Bind_tableApi_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/Binding/Bind_tableApi_spec.js @@ -29,7 +29,7 @@ describe("Test Create Api and Bind to Table widget", function() { it("Test_Validate the Api data is updated on Table widget", function() { cy.SearchEntityandOpen("Table1"); //cy.openPropertyPane("tablewidget"); - cy.testJsontext("tabledata", "{{Api1.data}}"); + cy.testJsontext("tabledata", "{{Api1.data.users}}"); cy.get(commonlocators.editPropCrossButton).click(); /** diff --git a/app/client/cypress/integration/Smoke_TestSuite/Binding/JS_Toggle_spec.js b/app/client/cypress/integration/Smoke_TestSuite/Binding/JS_Toggle_spec.js new file mode 100644 index 0000000000..012e1dbac5 --- /dev/null +++ b/app/client/cypress/integration/Smoke_TestSuite/Binding/JS_Toggle_spec.js @@ -0,0 +1,34 @@ +const dsl = require("../../../fixtures/Js_toggle_dsl.json"); + +describe("JS Toggle tests", () => { + before(() => { + cy.addDsl(dsl); + }); + + it("switches the toggle to Button widget", () => { + cy.openPropertyPane("buttonwidget"); + cy.get(".t--property-control-visible") + .find(".t--js-toggle") + .click(); + + cy.get(".t--property-control-visible") + .find(".t--js-toggle") + .should("have.class", "is-active"); + + cy.testJsontext("visible", "false"); + + cy.wait(1000); + + cy.get(".t--property-control-visible") + .find(".t--js-toggle") + .click(); + + cy.get(".t--property-control-visible") + .find(".t--js-toggle") + .should("not.have.class", "is-active"); + + cy.get(".t--property-control-visible") + .find("input") + .should("not.have.attr", "checked"); + }); +}); diff --git a/app/client/cypress/integration/Smoke_TestSuite/Pages/Page_Load_Spec.js b/app/client/cypress/integration/Smoke_TestSuite/Pages/Page_Load_Spec.js new file mode 100644 index 0000000000..583fbe9fcd --- /dev/null +++ b/app/client/cypress/integration/Smoke_TestSuite/Pages/Page_Load_Spec.js @@ -0,0 +1,57 @@ +const dsl = require("../../../fixtures/PageLoadDsl.json"); +const commonlocators = require("../../../locators/commonlocators.json"); + +describe("Page Load tests", () => { + before(() => { + cy.addDsl(dsl); + cy.get("div") + .contains("Pages") + .next() + .click(); + cy.get("h2").contains("Drag and drop a widget here"); + cy.addDsl(dsl); + }); + it("Published page loads correctly", () => { + // Update the text to be asserted later + cy.openPropertyPane("textwidget"); + cy.testCodeMirror("This is Page 2"); + // Publish + cy.PublishtheApp(); + // Assert active page tab + cy.get(".t--page-switch-tab") + .contains("Page2") + .parent() + .should("have.class", "is-active"); + // Assert active page DSL + cy.get(commonlocators.headingTextStyle).should( + "have.text", + "This is Page 2", + ); + // Test after reload + cy.reload(); + // Assert active page tab + cy.get(".t--page-switch-tab") + .contains("Page2") + .parent() + .should("have.class", "is-active"); + // Assert active page DSL + cy.get(commonlocators.headingTextStyle).should( + "have.text", + "This is Page 2", + ); + // Switch page + cy.get(".t--page-switch-tab") + .contains("Page1") + .click({ force: true }); + // Assert active page tab + cy.get(".t--page-switch-tab") + .contains("Page1") + .parent() + .should("have.class", "is-active"); + // Assert active page DSL + cy.get(commonlocators.headingTextStyle).should( + "have.text", + "This is Page 1", + ); + }); +}); diff --git a/app/client/src/AppRouter.tsx b/app/client/src/AppRouter.tsx index 6a71c3413c..2b9daf0615 100644 --- a/app/client/src/AppRouter.tsx +++ b/app/client/src/AppRouter.tsx @@ -10,6 +10,7 @@ import { BASE_SIGNUP_URL, BASE_URL, BUILDER_URL, + getApplicationViewerPageURL, ORG_URL, PAGE_NOT_FOUND_URL, SERVER_ERROR_URL, @@ -88,6 +89,10 @@ class AppRouter extends React.Component { component={ApplicationListLoader} /> + void; isInitialized: boolean; executeAction: (actionPayload: ExecuteActionPayload) => void; updateWidgetProperty: ( @@ -61,9 +61,10 @@ class AppViewer extends Component< editorInitializer().then(() => { this.setState({ registered: true }); }); - const { applicationId } = this.props.match.params; - if (this.props.match.params.applicationId) { - this.props.initializeAppViewer(applicationId); + const { applicationId, pageId } = this.props.match.params; + console.log({ applicationId, pageId }); + if (applicationId) { + this.props.initializeAppViewer(applicationId, pageId); } } @@ -125,11 +126,12 @@ const mapDispatchToProps = (dispatch: any) => ({ dispatch(updateWidgetMetaProperty(widgetId, propertyName, propertyValue)), resetChildrenMetaProperty: (widgetId: string) => dispatch(resetChildrenMetaProperty(widgetId)), - initializeAppViewer: (applicationId: string) => + initializeAppViewer: (applicationId: string, pageId?: string) => { dispatch({ type: ReduxActionTypes.INITIALIZE_PAGE_VIEWER, - payload: { applicationId }, - }), + payload: { applicationId, pageId }, + }); + }, }); export default withRouter( diff --git a/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx b/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx index 4a6c0a862a..fb1f5953b5 100644 --- a/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx +++ b/app/client/src/pages/AppViewer/viewer/AppViewerHeader.tsx @@ -249,6 +249,7 @@ export const AppViewerHeader = (props: AppViewerHeaderProps) => { page.pageId, )} activeClassName="is-active" + className="t--page-switch-tab" > {page.pageName} diff --git a/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx b/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx index 83c227a114..157e0c29ed 100644 --- a/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx +++ b/app/client/src/pages/Editor/PropertyPane/PropertyControl.tsx @@ -107,6 +107,7 @@ const PropertyControl = (props: Props) => { toggleDynamicProperty(propertyName, isDynamic)} + className={`t--js-toggle ${isDynamic ? "is-active" : ""}`} > diff --git a/app/client/src/sagas/InitSagas.ts b/app/client/src/sagas/InitSagas.ts index 639efc74ca..f10d4ce8c6 100644 --- a/app/client/src/sagas/InitSagas.ts +++ b/app/client/src/sagas/InitSagas.ts @@ -149,9 +149,9 @@ export function* populatePageDSLsSaga() { } export function* initializeAppViewerSaga( - action: ReduxAction<{ applicationId: string }>, + action: ReduxAction<{ applicationId: string; pageId: string }>, ) { - const { applicationId } = action.payload; + const { applicationId, pageId } = action.payload; yield put({ type: ReduxActionTypes.START_EVALUATION }); yield all([ put(fetchActionsForView(applicationId)), @@ -164,10 +164,11 @@ export function* initializeAppViewerSaga( take(ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS), ]); - const pageId = yield select(getDefaultPageId); + const defaultPageId = yield select(getDefaultPageId); + const toLoadPageId = pageId || defaultPageId; - if (pageId) { - yield put(fetchPublishedPage(pageId, true)); + if (toLoadPageId) { + yield put(fetchPublishedPage(toLoadPageId, true)); yield take(ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS); yield put(setAppMode(APP_MODE.PUBLISHED)); diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index a49ab260b7..0cad51f10c 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -634,7 +634,6 @@ function* setWidgetDynamicPropertySaga( yield put(updateWidgetProperty(widgetId, propertyName, value)); } else { delete dynamicProperties[propertyName]; - // TODO (hetu) can we eliminate this use of validation const { parsed } = yield call( validateProperty, widget.type, diff --git a/app/client/src/sagas/evaluationsSaga.ts b/app/client/src/sagas/evaluationsSaga.ts index 1d075a431e..a5d0ac953f 100644 --- a/app/client/src/sagas/evaluationsSaga.ts +++ b/app/client/src/sagas/evaluationsSaga.ts @@ -13,10 +13,7 @@ import { ReduxActionErrorTypes, ReduxActionTypes, } from "constants/ReduxActionConstants"; -import { - getDataTree, - getUnevaluatedDataTree, -} from "selectors/dataTreeSelectors"; +import { getUnevaluatedDataTree } from "selectors/dataTreeSelectors"; import WidgetFactory, { WidgetTypeConfigMap } from "../utils/WidgetFactory"; import Worker from "worker-loader!../workers/evaluation.worker"; import { @@ -147,7 +144,8 @@ export function* validateProperty( value, props, }); - return yield take(workerChannel); + const response = yield take(workerChannel); + return response.data; } return { isValid: true, parsed: value }; } diff --git a/app/client/src/workers/evaluation.worker.ts b/app/client/src/workers/evaluation.worker.ts index e8b377fbb9..8d0337d295 100644 --- a/app/client/src/workers/evaluation.worker.ts +++ b/app/client/src/workers/evaluation.worker.ts @@ -95,6 +95,15 @@ ctx.addEventListener("message", e => { ctx.postMessage(true); break; } + case EVAL_WORKER_ACTIONS.VALIDATE_PROPERTY: { + const { widgetType, property, value, props } = rest; + const result = validateWidgetProperty(widgetType, property, value, props); + ctx.postMessage(result); + break; + } + default: { + console.error("Action not registered on worker", action); + } } });