From f89d722479f6a98d6257ff5733868e48bc93bd12 Mon Sep 17 00:00:00 2001 From: Preet Sidhu Date: Tue, 12 Apr 2022 12:31:51 -0400 Subject: [PATCH 1/8] fix: 12861 trim unnecessary re-render in select widget in server side rendering (#12865) * add debounce to search and remove state var * increase debounce time --- .../widgets/SelectWidget/component/index.tsx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/app/client/src/widgets/SelectWidget/component/index.tsx b/app/client/src/widgets/SelectWidget/component/index.tsx index 63dc24a613..7ab8a67c5e 100644 --- a/app/client/src/widgets/SelectWidget/component/index.tsx +++ b/app/client/src/widgets/SelectWidget/component/index.tsx @@ -6,7 +6,7 @@ import { IItemListRendererProps, IItemRendererProps, } from "@blueprintjs/select"; -import { debounce, findIndex, isEmpty, isNil, isNumber } from "lodash"; +import { debounce, findIndex, isEmpty, isEqual, isNil, isNumber } from "lodash"; import "../../../../node_modules/@blueprintjs/select/lib/css/blueprint-select.css"; import { FixedSizeList } from "react-window"; import { TextSize } from "constants/WidgetConstants"; @@ -39,7 +39,6 @@ const MAX_RENDER_MENU_ITEMS_HEIGHT = 300; interface SelectComponentState { activeItemIndex: number | undefined; - query?: string; isOpen?: boolean; } @@ -54,14 +53,12 @@ class SelectComponent extends React.Component< state = { // used to show focused item for keyboard up down key interection activeItemIndex: -1, - query: "", isOpen: false, }; componentDidMount = () => { // set default selectedIndex as focused index this.setState({ activeItemIndex: this.props.selectedIndex }); - this.setState({ query: this.props.filterText }); }; componentDidUpdate = (prevProps: SelectComponentProps) => { @@ -113,15 +110,10 @@ class SelectComponent extends React.Component< }); return optionIndex === this.props.selectedIndex; }; - onQueryChange = (filterValue: string) => { - this.setState({ query: filterValue }); + onQueryChange = debounce((filterValue: string) => { + if (isEqual(filterValue, this.props.filterText)) return; this.props.onFilterChange(filterValue); this.listRef?.current?.scrollTo(0); - if (!this.props.serverSideFiltering) return; - return this.serverSideSearch(filterValue); - }; - serverSideSearch = debounce((filterValue: string) => { - this.props.onFilterChange(filterValue); }, DEBOUNCE_TIMEOUT); renderSingleSelectItem = ( @@ -195,7 +187,7 @@ class SelectComponent extends React.Component< // Don't scroll if the list is filtered. const optionsCount = this.props.options.length; const scrollOffset: number = - !this.state.query && + !this.props.filterText && isNumber(activeItemIndex) && optionsCount * ITEM_SIZE > MAX_RENDER_MENU_ITEMS_HEIGHT ? activeItemIndex * ITEM_SIZE @@ -341,7 +333,7 @@ class SelectComponent extends React.Component< }, popoverClassName: `select-popover-wrapper select-popover-width-${this.props.widgetId}`, }} - query={this.state.query} + query={this.props.filterText} scrollToActiveItem value={this.props.value as string} > From 2d238a6506939e96a90436fd0702e0ba821ab390 Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Wed, 20 Apr 2022 11:32:01 +0530 Subject: [PATCH 2/8] fix: updated the condition to show expiry key (#13092) --- .../amazons3Plugin/src/main/resources/editor/list.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/list.json b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/list.json index 66b0ef0a86..74391e7262 100644 --- a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/list.json +++ b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/list.json @@ -98,7 +98,7 @@ "controlType": "QUERY_DYNAMIC_INPUT_TEXT", "initialValue": "5", "conditionals": { - "show": "{{actionConfiguration.formData.signedUrl.data === 'YES'}}" + "show": "{{actionConfiguration.formData.list.signedUrl.data === 'YES'}}" } }, { From 56998d77d520f3f92fad6cb6af55f64d1d6149e3 Mon Sep 17 00:00:00 2001 From: Abhijeet <41686026+abhvsn@users.noreply.github.com> Date: Thu, 21 Apr 2022 11:10:41 +0530 Subject: [PATCH 3/8] Add index for git (#13133) --- .../server/migrations/DatabaseChangelog.java | 6 +- .../server/migrations/DatabaseChangelog2.java | 90 +++++++++++++++++++ 2 files changed, 93 insertions(+), 3 deletions(-) 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 e7269d86a9..d9ce643c7e 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 @@ -187,7 +187,7 @@ public class DatabaseChangelog { * Also, please check out the following blog on how to best create indexes : * https://emptysqua.re/blog/optimizing-mongodb-compound-indexes/ */ - private static Index makeIndex(String... fields) { + public static Index makeIndex(String... fields) { if (fields.length == 1) { return new Index(fields[0], Sort.Direction.ASC).named(fields[0]); } else { @@ -203,14 +203,14 @@ public class DatabaseChangelog { * Given a MongockTemplate, a domain class and a bunch of Index definitions, this pure utility function will ensure * those indexes on the database behind the MongockTemplate instance. */ - private static void ensureIndexes(MongockTemplate mongoTemplate, Class entityClass, Index... indexes) { + public static void ensureIndexes(MongockTemplate mongoTemplate, Class entityClass, Index... indexes) { IndexOperations indexOps = mongoTemplate.indexOps(entityClass); for (Index index : indexes) { indexOps.ensureIndex(index); } } - private static void dropIndexIfExists(MongockTemplate mongoTemplate, Class entityClass, String name) { + public static void dropIndexIfExists(MongockTemplate mongoTemplate, Class entityClass, String name) { try { mongoTemplate.indexOps(entityClass).dropIndex(name); } catch (UncategorizedMongoDbException ignored) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java index 3a0dbbe9be..a84c51705c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java @@ -3,7 +3,12 @@ package com.appsmith.server.migrations; import com.appsmith.server.domains.Application; import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Property; +import com.appsmith.external.models.QBaseDomain; import com.appsmith.external.models.QDatasource; +import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.ActionCollection; +import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.QApplication; @@ -30,6 +35,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.appsmith.server.migrations.DatabaseChangelog.dropIndexIfExists; +import static com.appsmith.server.migrations.DatabaseChangelog.ensureIndexes; +import static com.appsmith.server.migrations.DatabaseChangelog.makeIndex; import static com.appsmith.server.repositories.BaseAppsmithRepositoryImpl.fieldName; import static java.lang.Boolean.TRUE; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -653,4 +661,86 @@ public class DatabaseChangelog2 { Application.class); } + @ChangeSet(order = "006", id = "delete-orphan-pages", author = "") + public void deleteOrphanPages(MongockTemplate mongockTemplate) { + + final Query validPagesQuery = query(where(fieldName(QApplication.application.deleted)).ne(true)); + validPagesQuery.fields().include(fieldName(QApplication.application.pages)); + validPagesQuery.fields().include(fieldName(QApplication.application.publishedPages)); + + final List applications = mongockTemplate.find(validPagesQuery, Application.class); + + final Update deletionUpdates = new Update(); + deletionUpdates.set(fieldName(QNewPage.newPage.deleted), true); + deletionUpdates.set(fieldName(QNewPage.newPage.deletedAt), Instant.now()); + + // Archive the pages which have the applicationId but the connection is missing from the application object. + for (Application application : applications) { + Set validPageIds = new HashSet<>(); + if (!CollectionUtils.isEmpty(application.getPages())) { + for (ApplicationPage applicationPage : application.getPages()) { + validPageIds.add(applicationPage.getId()); + } + } + if (!CollectionUtils.isEmpty(application.getPublishedPages())) { + for (ApplicationPage applicationPublishedPage : application.getPublishedPages()) { + validPageIds.add(applicationPublishedPage.getId()); + } + } + final Query pageQuery = query(where(fieldName(QNewPage.newPage.deleted)).ne(true)); + pageQuery.addCriteria(where(fieldName(QNewPage.newPage.applicationId)).is(application.getId())); + pageQuery.fields().include(fieldName(QNewPage.newPage.applicationId)); + + final List pages = mongockTemplate.find(pageQuery, NewPage.class); + for (NewPage newPage : pages) { + if (!validPageIds.contains(newPage.getId())) { + mongockTemplate.updateFirst( + query(where(fieldName(QNewPage.newPage.id)).is(newPage.getId())), + deletionUpdates, + NewPage.class + ); + } + } + } + } + + /** + * This migration introduces indexes on newAction, actionCollection, newPage to improve the query performance for + * queries like getResourceByDefaultAppIdAndGitSyncId which excludes the deleted entries. + */ + @ChangeSet(order = "007", id = "update-git-indexes", author = "") + public void addIndexesForGit(MongockTemplate mongockTemplate) { + + dropIndexIfExists(mongockTemplate, NewAction.class, "defaultApplicationId_gitSyncId_compound_index"); + dropIndexIfExists(mongockTemplate, ActionCollection.class, "defaultApplicationId_gitSyncId_compound_index"); + + String defaultResources = fieldName(QBaseDomain.baseDomain.defaultResources); + ensureIndexes(mongockTemplate, ActionCollection.class, + makeIndex( + defaultResources + "." + FieldName.APPLICATION_ID, + fieldName(QBaseDomain.baseDomain.gitSyncId), + fieldName(QBaseDomain.baseDomain.deleted) + ) + .named("defaultApplicationId_gitSyncId_deleted_compound_index") + ); + + ensureIndexes(mongockTemplate, NewAction.class, + makeIndex( + defaultResources + "." + FieldName.APPLICATION_ID, + fieldName(QBaseDomain.baseDomain.gitSyncId), + fieldName(QBaseDomain.baseDomain.deleted) + ) + .named("defaultApplicationId_gitSyncId_deleted_compound_index") + ); + + ensureIndexes(mongockTemplate, NewPage.class, + makeIndex( + defaultResources + "." + FieldName.APPLICATION_ID, + fieldName(QBaseDomain.baseDomain.gitSyncId), + fieldName(QBaseDomain.baseDomain.deleted) + ) + .named("defaultApplicationId_gitSyncId_deleted_compound_index") + ); + } + } From 21b6936f86a6ba806415f8b213447d2dbbc27cbf Mon Sep 17 00:00:00 2001 From: Nidhi Date: Mon, 25 Apr 2022 14:44:58 +0530 Subject: [PATCH 4/8] fix: Fixed compile time errors --- .../com/appsmith/server/migrations/DatabaseChangelog2.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java index a84c51705c..6638c7f281 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog2.java @@ -10,9 +10,11 @@ import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; import com.appsmith.server.domains.NewAction; +import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.QApplication; import com.appsmith.server.domains.QNewAction; +import com.appsmith.server.domains.QNewPage; import com.appsmith.server.domains.QPlugin; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.exceptions.AppsmithError; @@ -23,6 +25,7 @@ import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.decorator.impl import lombok.extern.slf4j.Slf4j; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.time.Instant; @@ -31,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.HashSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; From aa4c3fe9533060b491381c3da07ecb6b0d720b1e Mon Sep 17 00:00:00 2001 From: Anagh Hegde Date: Thu, 28 Apr 2022 16:43:53 +0530 Subject: [PATCH 5/8] fix: Unable to see apps in home page after git connect fails (#13387) --- .../ce/ApplicationFetcherCEImpl.java | 10 +- .../solutions/ApplicationFetcherUnitTest.java | 146 ++++++++++++++++++ 2 files changed, 154 insertions(+), 2 deletions(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ApplicationFetcherCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ApplicationFetcherCEImpl.java index 15d8e40288..0f86730f82 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ApplicationFetcherCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/ApplicationFetcherCEImpl.java @@ -112,9 +112,15 @@ public class ApplicationFetcherCEImpl implements ApplicationFetcherCE { // Collect all the applications as a map with organization id as a key Flux applicationFlux = applicationRepository .findByMultipleOrganizationIds(orgIds, READ_APPLICATIONS) + // Git connected apps will have gitApplicationMetadat .filter(application -> application.getGitApplicationMetadata() == null - || (!StringUtils.isEmpty(application.getGitApplicationMetadata().getDefaultBranchName()) - && application.getGitApplicationMetadata().getBranchName().equals(application.getGitApplicationMetadata().getDefaultBranchName())) + // 1. When the ssh key is generated by user and then the connect app fails + || (StringUtils.isEmpty(application.getGitApplicationMetadata().getDefaultBranchName()) + && StringUtils.isEmpty(application.getGitApplicationMetadata().getBranchName())) + // 2. When the DefaultBranchName is missing due to branch creation flow failures or corrupted scenarios + || (!StringUtils.isEmpty(application.getGitApplicationMetadata().getBranchName()) + && application.getGitApplicationMetadata().getBranchName().equals(application.getGitApplicationMetadata().getDefaultBranchName()) + ) ) .map(responseUtils::updateApplicationWithDefaultResources); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationFetcherUnitTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationFetcherUnitTest.java index a81f655cd6..fa42f4a5b7 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationFetcherUnitTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationFetcherUnitTest.java @@ -2,14 +2,18 @@ package com.appsmith.server.solutions; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; +import com.appsmith.server.domains.GitApplicationMetadata; +import com.appsmith.server.domains.GitAuth; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.User; import com.appsmith.server.domains.UserData; import com.appsmith.server.dtos.OrganizationApplicationsDTO; import com.appsmith.server.dtos.PageDTO; +import com.appsmith.server.dtos.UserHomepageDTO; import com.appsmith.server.helpers.ResponseUtils; import com.appsmith.server.repositories.ApplicationRepository; +import com.appsmith.server.services.ApplicationService; import com.appsmith.server.services.NewPageService; import com.appsmith.server.services.OrganizationService; import com.appsmith.server.services.SessionUserService; @@ -18,7 +22,9 @@ import com.appsmith.server.services.UserService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import reactor.core.publisher.Flux; @@ -65,6 +71,9 @@ public class ApplicationFetcherUnitTest { ApplicationFetcher applicationFetcher; + @MockBean + ApplicationService applicationService; + User testUser; final static String defaultPageId = "defaultPageId"; @@ -194,6 +203,9 @@ public class ApplicationFetcherUnitTest { .thenReturn(updateDefaultPageIdsWithinApplication(application)); } + Mockito.when(applicationService.createOrUpdateSshKeyPair(Mockito.anyString())) + .thenReturn(Mono.just(new GitAuth())); + StepVerifier.create(applicationFetcher.getAllApplications()) .assertNext(userHomepageDTO -> { List dtos = userHomepageDTO.getOrganizationApplications(); @@ -213,6 +225,140 @@ public class ApplicationFetcherUnitTest { }).verifyComplete(); } + @Test + public void getAllApplications_gitConnectedAppScenarios_OnlyTheDefaultBranchedAppIsReturned() { + initMocks(); + // mock the user data to return recently used orgs and apps + UserData userData = new UserData(); + Mockito.when(userDataService.getForCurrentUser()).thenReturn(Mono.just(userData)); + + // mock the list of applications + List applications = createDummyApplications(4,4); + List pageList = createDummyPages(4, 4); + + Mockito.when(applicationRepository.findByMultipleOrganizationIds( + testUser.getOrganizationIds(), READ_APPLICATIONS) + ).thenReturn(Flux.fromIterable(applications)); + + Mockito.when(newPageService.findPageSlugsByApplicationIds(anyList(), eq(READ_PAGES))) + .thenReturn(Flux.fromIterable(pageList)); + + for (Application application : applications) { + Mockito + .when(responseUtils.updateApplicationWithDefaultResources(application)) + .thenReturn(updateDefaultPageIdsWithinApplication(application)); + } + + Mockito.when(applicationService.createOrUpdateSshKeyPair(Mockito.anyString())) + .thenReturn(Mono.just(new GitAuth())); + + StepVerifier.create(applicationFetcher.getAllApplications()) + .assertNext(userHomepageDTO -> { + List dtos = userHomepageDTO.getOrganizationApplications(); + assertThat(dtos.size()).isEqualTo(4); + for (OrganizationApplicationsDTO dto : dtos) { + assertThat(dto.getApplications().size()).isEqualTo(4); + List applicationList = dto.getApplications(); + for (Application application : applicationList) { + application.getPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-unpublished-slug") + ); + application.getPublishedPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-published-slug") + ); + } + } + }).verifyComplete(); + + // Generate SSH keys for an app - to test if the app is visible in home page when the git connect step is aborted in middle + Mockito.when(applicationService.save(Mockito.any(Application.class))) + .thenReturn(Mono.just(new Application())); + Mono userHomepageDTOMono = applicationFetcher.getAllApplications() + .flatMap(userHomepageDTO -> { + List dtos = userHomepageDTO.getOrganizationApplications(); + List applicationList = dtos.get(0).getApplications(); + return Mono.just(applicationList.get(0)); + }) + // After choosing the any app randomly to connect to git, Generate keys and stop the process + .flatMap(application -> applicationService.createOrUpdateSshKeyPair(application.getId())) + .then(applicationFetcher.getAllApplications()); + + StepVerifier.create(userHomepageDTOMono) + .assertNext(userHomepageDTO -> { + List dtos = userHomepageDTO.getOrganizationApplications(); + assertThat(dtos.size()).isEqualTo(4); + for (OrganizationApplicationsDTO dto : dtos) { + assertThat(dto.getApplications().size()).isEqualTo(4); + List applicationList = dto.getApplications(); + for (Application application : applicationList) { + application.getPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-unpublished-slug") + ); + application.getPublishedPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-published-slug") + ); + } + } + }).verifyComplete(); + + // For connect and create branch flow scenarios where - defaultBranchName is somehow not saved in DB + userHomepageDTOMono = applicationFetcher.getAllApplications() + .flatMap(userHomepageDTO -> { + List dtos = userHomepageDTO.getOrganizationApplications(); + List applicationList = dtos.get(0).getApplications(); + return Mono.just(applicationList.get(0)); + }) + .flatMap(application -> { + // Create a new branched App resource in the same org and verify that branch App does not show up in the response. + Application branchApp = new Application(); + branchApp.setName("branched App"); + branchApp.setOrganizationId(application.getOrganizationId()); + branchApp.setId("org-" + 5 + "-app-" + 5); + GitApplicationMetadata gitApplicationMetadata = new GitApplicationMetadata(); + gitApplicationMetadata.setDefaultApplicationId(application.getId()); + gitApplicationMetadata.setBranchName("master"); + gitApplicationMetadata.setRemoteUrl("remnoteUrl"); + branchApp.setGitApplicationMetadata(gitApplicationMetadata); + + // Set dummy applicationPages + ApplicationPage unpublishedPage = new ApplicationPage(); + unpublishedPage.setId("page" + 5); + unpublishedPage.setDefaultPageId("page" + 5); + unpublishedPage.setIsDefault(true); + + ApplicationPage publishedPage = new ApplicationPage(); + publishedPage.setId("page" + 5); + publishedPage.setDefaultPageId("page" + 5); + publishedPage.setIsDefault(true); + + branchApp.setPages(List.of(unpublishedPage)); + branchApp.setPublishedPages(List.of(publishedPage)); + applications.add(branchApp); + + return applicationService.save(branchApp); + }) + .then(applicationFetcher.getAllApplications()); + + StepVerifier.create(userHomepageDTOMono) + .assertNext(userHomepageDTO -> { + List dtos = userHomepageDTO.getOrganizationApplications(); + assertThat(dtos.size()).isEqualTo(4); + for (OrganizationApplicationsDTO dto : dtos) { + assertThat(dto.getApplications().size()).isEqualTo(4); + List applicationList = dto.getApplications(); + for (Application application : applicationList) { + application.getPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-unpublished-slug") + ); + application.getPublishedPages().forEach( + page -> assertThat(page.getSlug()).isEqualTo(page.getId()+"-published-slug") + ); + } + } + }).verifyComplete(); + + } + @Test public void getAllApplications_WhenUserHasRecentOrgAndApp_RecentEntriesComeFirst() { initMocks(); From acc8e896a625db1284d3bb3356834e4d49f857d5 Mon Sep 17 00:00:00 2001 From: Shrikant Sharat Kandula Date: Fri, 29 Apr 2022 10:51:06 +0530 Subject: [PATCH 6/8] Fix Redis installation in Dockerfile (#13428) (#13430) Conflicts: Dockerfile --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8a7196860d..c06417ecba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,18 +16,15 @@ RUN apt-get update \ supervisor curl cron certbot nginx gnupg wget netcat openssh-client \ software-properties-common gettext openjdk-11-jre \ python3-pip python-setuptools git \ - && add-apt-repository ppa:redislabs/redis \ && pip install --no-cache-dir git+https://github.com/coderanger/supervisor-stdout@973ba19967cdaf46d9c1634d1675fc65b9574f6e \ - && apt-get remove -y git python3-pip \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && apt-get remove -y git python3-pip # Install MongoDB v4.0.5, Redis, NodeJS - Service Layer RUN wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add - RUN echo "deb [ arch=amd64,arm64 ]http://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list \ && apt-get remove wget -y RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \ - && apt-get -y install --no-install-recommends -y mongodb-org=4.4.6 nodejs redis build-essential \ + && apt-get install --no-install-recommends -y mongodb-org=4.4.6 nodejs redis build-essential \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -88,6 +85,9 @@ RUN chmod 0644 /etc/cron.d/* RUN chmod +x entrypoint.sh renew-certificate.sh +# Disable setuid/setgid bits for the files inside container. +RUN find / \( -path /proc -prune \) -o \( \( -perm -2000 -o -perm -4000 \) -print -exec chmod -s '{}' + \) || true + # Update path to load appsmith utils tool as default ENV PATH /opt/appsmith/utils/node_modules/.bin:$PATH From c554dcd9559ce3dd3021c3e2461265f5064af1ab Mon Sep 17 00:00:00 2001 From: Favour Ohanekwu Date: Wed, 4 May 2022 01:43:26 -0700 Subject: [PATCH 7/8] fix: only execute pageload actions after successfully fetching actions and jscollections in view mode (#13521) * prevent execution of onPageLoad actions before sucessful actions fetch * Perform url update before fetching actions and jscollections (cherry picked from commit 7261834fe539545b72d34aa75df9036f645f726d) --- .../LayoutOnLoadActions/OnLoadActions_Spec.ts | 65 ++++++++++++------- app/client/src/sagas/InitSagas.ts | 29 ++++++++- 2 files changed, 66 insertions(+), 28 deletions(-) diff --git a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/LayoutOnLoadActions/OnLoadActions_Spec.ts b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/LayoutOnLoadActions/OnLoadActions_Spec.ts index e99d7f2109..7253c75ce0 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/LayoutOnLoadActions/OnLoadActions_Spec.ts +++ b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/LayoutOnLoadActions/OnLoadActions_Spec.ts @@ -1,4 +1,4 @@ -import { ObjectsRegistry } from "../../../../support/Objects/Registry" +import { ObjectsRegistry } from "../../../../support/Objects/Registry"; let dsl: any; let agHelper = ObjectsRegistry.AggregateHelper, @@ -8,19 +8,22 @@ let agHelper = ObjectsRegistry.AggregateHelper, jsEditor = ObjectsRegistry.JSEditor, locator = ObjectsRegistry.CommonLocators; -describe("Layout OnLoad Actions tests", function () { +describe("Layout OnLoad Actions tests", function() { before(() => { cy.fixture("onPageLoadActionsDsl").then((val: any) => { dsl = val; }); }); - it("1. Bug 8595: OnPageLoad execution - when No api to run on Pageload", function () { + it("1. Bug 8595: OnPageLoad execution - when No api to run on Pageload", function() { agHelper.AddDsl(dsl); ee.SelectEntityByName("WIDGETS"); ee.SelectEntityByName("Page1"); cy.url().then((url) => { - const pageid = url.split("/")[5]?.split("-").pop(); + const pageid = url + .split("/")[5] + ?.split("-") + .pop(); cy.log(pageid + "page id"); cy.request("GET", "api/v1/pages/" + pageid).then((response) => { const respBody = JSON.stringify(response.body); @@ -31,7 +34,7 @@ describe("Layout OnLoad Actions tests", function () { }); }); - it("2. Bug 8595: OnPageLoad execution - when Query Parmas added via Params tab", function () { + it("2. Bug 8595: OnPageLoad execution - when Query Parmas added via Params tab", function() { agHelper.AddDsl(dsl, locator._imageWidget); apiPage.CreateAndFillApi( "https://source.unsplash.com/collection/1599413", @@ -43,7 +46,7 @@ describe("Layout OnLoad Actions tests", function () { //apiPage.RunAPI(); apiPage.CreateAndFillApi("https://favqs.com/api/qotd", "InspiringQuotes"); - apiPage.EnterHeader("dependency", "{{RandomUser.data}}");//via Params tab + apiPage.EnterHeader("dependency", "{{RandomUser.data}}"); //via Params tab //apiPage.RunAPI(); apiPage.CreateAndFillApi( @@ -54,7 +57,7 @@ describe("Layout OnLoad Actions tests", function () { //apiPage.RunAPI(); apiPage.CreateAndFillApi("https://api.genderize.io", "Genderize"); - apiPage.EnterParams("name", "{{RandomUser.data.results[0].name.first}}");//via Params tab + apiPage.EnterParams("name", "{{RandomUser.data.results[0].name.first}}"); //via Params tab //apiPage.RunAPI(); //Adding dependency in right order matters! @@ -63,13 +66,25 @@ describe("Layout OnLoad Actions tests", function () { jsEditor.EnterJSContext("Image", `{{RandomFlora.data}}`, true); ee.SelectEntityByName("Image2"); - jsEditor.EnterJSContext("Image", `{{RandomUser.data.results[0].picture.large}}`, true); + jsEditor.EnterJSContext( + "Image", + `{{RandomUser.data.results[0].picture.large}}`, + true, + ); ee.SelectEntityByName("Text1"); - jsEditor.EnterJSContext("Text", `{{InspiringQuotes.data.quote.body}}\n--\n{{InspiringQuotes.data.quote.author}}\n`, true); + jsEditor.EnterJSContext( + "Text", + `{{InspiringQuotes.data.quote.body}}\n--\n{{InspiringQuotes.data.quote.author}}\n`, + true, + ); ee.SelectEntityByName("Text2"); - jsEditor.EnterJSContext("Text", `Hi, here is {{RandomUser.data.results[0].name.first}} & I'm {{RandomUser.data.results[0].dob.age}}'yo\nI live in {{RandomUser.data.results[0].location.country}}\nMy Suggestion : {{Suggestions.data.activity}}\n\nI'm {{Genderize.data.gender}}`, true); + jsEditor.EnterJSContext( + "Text", + `Hi, here is {{RandomUser.data.results[0].name.first}} & I'm {{RandomUser.data.results[0].dob.age}}'yo\nI live in {{RandomUser.data.results[0].location.country}}\nMy Suggestion : {{Suggestions.data.activity}}\n\nI'm {{Genderize.data.gender}}`, + true, + ); // cy.url().then((url) => { // const pageid = url.split("/")[4]?.split("-").pop(); @@ -110,10 +125,10 @@ describe("Layout OnLoad Actions tests", function () { // }); // }); - agHelper.DeployApp() - agHelper.Sleep()//waiting for error toast - incase it wants to appear! - agHelper.AssertElementAbsence(locator._toastMsg) - agHelper.Sleep(5000)//for all api's to ccomplete call! + agHelper.DeployApp(); + agHelper.Sleep(); //waiting for error toast - incase it wants to appear! + agHelper.AssertElementAbsence(locator._toastMsg); + agHelper.Sleep(5000); //for all api's to ccomplete call! cy.wait("@viewPage").then(($response) => { const respBody = JSON.stringify($response.response?.body); @@ -147,14 +162,14 @@ describe("Layout OnLoad Actions tests", function () { expect(JSON.parse(JSON.stringify(_suggestions))[0]["name"]).to.eq( "Suggestions", ); - }) + }); - agHelper.NavigateBacktoEditor() + agHelper.NavigateBacktoEditor(); }); - it("3. Bug 10049, 10055: Dependency not executed in expected order in layoutOnLoadActions when dependency added via URL", function () { - ee.SelectEntityByName('Genderize', 'QUERIES/JS') - ee.ActionContextMenuByEntityName('Genderize', 'Delete', 'Are you sure?') + it("3. Bug 10049, 10055: Dependency not executed in expected order in layoutOnLoadActions when dependency added via URL", function() { + ee.SelectEntityByName("Genderize", "QUERIES/JS"); + ee.ActionContextMenuByEntityName("Genderize", "Delete", "Are you sure?"); apiPage.CreateAndFillApi( "https://api.genderize.io?name={{RandomUser.data.results[0].name.first}}", @@ -164,11 +179,11 @@ describe("Layout OnLoad Actions tests", function () { key: "name", value: "{{RandomUser.data.results[0].name.first}}", }); // verifies Bug 10055 - - agHelper.DeployApp() - agHelper.Sleep()//waiting for error toast - incase it wants to appear! - agHelper.AssertElementAbsence(locator._toastMsg) - agHelper.Sleep(5000)//for all api's to ccomplete call! + + agHelper.DeployApp(); + agHelper.Sleep(); //waiting for error toast - incase it wants to appear! + agHelper.AssertElementAbsence(locator._toastMsg); + agHelper.Sleep(5000); //for all api's to ccomplete call! cy.wait("@viewPage").then(($response) => { const respBody = JSON.stringify($response.response?.body); const _randomFlora = JSON.parse(respBody).data.layouts[0] @@ -197,6 +212,6 @@ describe("Layout OnLoad Actions tests", function () { expect(JSON.parse(JSON.stringify(_suggestions))[0]["name"]).to.eq( "Suggestions", ); - }) + }); }); }); diff --git a/app/client/src/sagas/InitSagas.ts b/app/client/src/sagas/InitSagas.ts index a9fb56deb8..0a245f538c 100644 --- a/app/client/src/sagas/InitSagas.ts +++ b/app/client/src/sagas/InitSagas.ts @@ -412,22 +412,45 @@ export function* initializeAppViewerSaga( [ fetchActionsForView({ applicationId }), fetchJSCollectionsForView({ applicationId }), - fetchPublishedPage(toLoadPageId, true), ], [ ReduxActionTypes.FETCH_ACTIONS_VIEW_MODE_SUCCESS, ReduxActionTypes.FETCH_JS_ACTIONS_VIEW_MODE_SUCCESS, - ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS, ], [ ReduxActionErrorTypes.FETCH_ACTIONS_VIEW_MODE_ERROR, ReduxActionErrorTypes.FETCH_JS_ACTIONS_VIEW_MODE_ERROR, - ReduxActionErrorTypes.FETCH_PUBLISHED_PAGE_ERROR, ], ); if (!resultOfPrimaryCalls) return; + if (toLoadPageId) { + yield put(fetchPublishedPage(toLoadPageId, true)); + + const resultOfFetchPage: { + success: boolean; + failure: boolean; + } = yield race({ + success: take(ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS), + failure: take(ReduxActionErrorTypes.FETCH_PUBLISHED_PAGE_ERROR), + }); + + if (resultOfFetchPage.failure) { + yield put({ + type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST, + payload: { + code: get( + resultOfFetchPage, + "failure.payload.error.code", + ERROR_CODES.SERVER_ERROR, + ), + }, + }); + return; + } + } + yield put(fetchCommentThreadsInit()); yield put({ From ea80a6028c44f846397c78368ba7646557fae821 Mon Sep 17 00:00:00 2001 From: Trisha Anand Date: Tue, 17 May 2022 13:49:41 +0530 Subject: [PATCH 8/8] fix: NPE check when datasource createdAt is null (cherry picked from commit beafb371b24180dce2e351f1dea6d9d34db2a204) --- .../server/services/ce/NewActionServiceCEImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java index d2d7d7fa7c..b7bb5342c4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/NewActionServiceCEImpl.java @@ -1043,6 +1043,11 @@ public class NewActionServiceCEImpl extends BaseService