diff --git a/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx b/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx
index 1eff3ee7c0..05feedb6c5 100644
--- a/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx
+++ b/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx
@@ -216,6 +216,10 @@ export const CurrentValueViewer = memo(
},
collapsed: 2,
collapseStringsAfterLength: 20,
+ shouldCollapse: (field: any) => {
+ const index = field.name * 1;
+ return index >= 2 ? true : false;
+ },
};
content = (
diff --git a/app/client/src/components/editorComponents/EditorContextProvider.tsx b/app/client/src/components/editorComponents/EditorContextProvider.tsx
index 98af637a72..028b03ae9f 100644
--- a/app/client/src/components/editorComponents/EditorContextProvider.tsx
+++ b/app/client/src/components/editorComponents/EditorContextProvider.tsx
@@ -1,4 +1,4 @@
-import React, { Context, createContext, ReactNode } from "react";
+import React, { Context, createContext, ReactNode, useMemo } from "react";
import { connect } from "react-redux";
import { WidgetOperation } from "widgets/BaseWidget";
@@ -65,66 +65,58 @@ function EditorContextProvider(props: EditorContextProviderProps) {
updateWidgetMetaProperty,
updateWidgetProperty,
} = props;
+
+ // Memoize the context provider to prevent
+ // unnecessary renders
+ const contextValue = useMemo(
+ () => ({
+ executeAction,
+ updateWidget,
+ updateWidgetProperty,
+ updateWidgetMetaProperty,
+ disableDrag,
+ resetChildrenMetaProperty,
+ deleteWidgetProperty,
+ batchUpdateWidgetProperty,
+ }),
+ [
+ executeAction,
+ updateWidget,
+ updateWidgetProperty,
+ updateWidgetMetaProperty,
+ disableDrag,
+ resetChildrenMetaProperty,
+ deleteWidgetProperty,
+ batchUpdateWidgetProperty,
+ ],
+ );
return (
-
+
{children}
);
}
-const mapDispatchToProps = (dispatch: any) => {
- return {
- updateWidgetProperty: (
- widgetId: string,
- propertyName: string,
- propertyValue: any,
- ) =>
- dispatch(
- updateWidgetPropertyRequest(
- widgetId,
- propertyName,
- propertyValue,
- RenderModes.CANVAS,
- ),
- ),
- executeAction: (actionPayload: ExecuteActionPayload) =>
- dispatch(executeAction(actionPayload)),
- updateWidget: (
- operation: WidgetOperation,
- widgetId: string,
- payload: any,
- ) => dispatch(updateWidget(operation, widgetId, payload)),
- updateWidgetMetaProperty: (
- widgetId: string,
- propertyName: string,
- propertyValue: any,
- ) =>
- dispatch(updateWidgetMetaProperty(widgetId, propertyName, propertyValue)),
- resetChildrenMetaProperty: (widgetId: string) =>
- dispatch(resetChildrenMetaProperty(widgetId)),
- disableDrag: (disable: boolean) => {
- dispatch(disableDragAction(disable));
- },
- deleteWidgetProperty: (widgetId: string, propertyPaths: string[]) =>
- dispatch(deletePropertyAction(widgetId, propertyPaths)),
- batchUpdateWidgetProperty: (
- widgetId: string,
- updates: BatchPropertyUpdatePayload,
- ) => {
- dispatch(batchUpdatePropertyAction(widgetId, updates));
- },
- };
+const mapDispatchToProps = {
+ updateWidgetProperty: (
+ widgetId: string,
+ propertyName: string,
+ propertyValue: any,
+ ) =>
+ updateWidgetPropertyRequest(
+ widgetId,
+ propertyName,
+ propertyValue,
+ RenderModes.CANVAS,
+ ),
+
+ executeAction,
+ updateWidget,
+ updateWidgetMetaProperty,
+ resetChildrenMetaProperty,
+ disableDrag: disableDragAction,
+ deleteWidgetProperty: deletePropertyAction,
+ batchUpdateWidgetProperty: batchUpdatePropertyAction,
};
export default connect(null, mapDispatchToProps)(EditorContextProvider);
diff --git a/app/client/src/components/editorComponents/ResizableComponent.tsx b/app/client/src/components/editorComponents/ResizableComponent.tsx
index 493e1d15e7..1b401fdbe2 100644
--- a/app/client/src/components/editorComponents/ResizableComponent.tsx
+++ b/app/client/src/components/editorComponents/ResizableComponent.tsx
@@ -43,8 +43,9 @@ export type ResizableComponentProps = WidgetProps & {
paddingOffset: number;
};
-/* eslint-disable react/display-name */
-export const ResizableComponent = memo((props: ResizableComponentProps) => {
+export const ResizableComponent = memo(function ResizableComponent(
+ props: ResizableComponentProps,
+) {
const resizableRef = useRef(null);
// Fetch information from the context
const { updateWidget } = useContext(EditorContext);
@@ -109,15 +110,18 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => {
possibleBoundingElements.length > 0
? possibleBoundingElements[0]
: undefined;
- const boundingElementClientRect = boundingElement
- ? boundingElement.getBoundingClientRect()
- : undefined;
// onResize handler
// Checks if the current resize position has any collisions
// If yes, set isColliding flag to true.
// If no, set isColliding flag to false.
const isColliding = (newDimensions: UIElementSize, position: XYCoord) => {
+ // Moving the bounding element calculations inside
+ // to make this expensive operation only whne
+ const boundingElementClientRect = boundingElement
+ ? boundingElement.getBoundingClientRect()
+ : undefined;
+
const bottom =
props.topRow +
position.y / props.parentRowSpace +
diff --git a/app/client/src/index.tsx b/app/client/src/index.tsx
index adac756b97..09b9329784 100755
--- a/app/client/src/index.tsx
+++ b/app/client/src/index.tsx
@@ -26,7 +26,11 @@ import AppErrorBoundary from "./AppErrorBoundry";
import GlobalStyles from "globalStyles";
appInitializer();
+import useRemoveSignUpCompleteParam from "utils/hooks/useRemoveSignUpCompleteParam";
+
function App() {
+ useRemoveSignUpCompleteParam();
+
return (
diff --git a/app/client/src/utils/hooks/useRemoveSignUpCompleteParam.ts b/app/client/src/utils/hooks/useRemoveSignUpCompleteParam.ts
new file mode 100644
index 0000000000..478bc5ffaf
--- /dev/null
+++ b/app/client/src/utils/hooks/useRemoveSignUpCompleteParam.ts
@@ -0,0 +1,21 @@
+import { useEffect } from "react";
+import history from "utils/history";
+
+const useRemoveSignUpCompleteParam = () => {
+ useEffect(() => {
+ if (window.location.href) {
+ const url = new URL(window.location.href);
+ const searchParams = url.searchParams;
+ if (searchParams.get("isFromSignup")) {
+ searchParams.delete("isFromSignup");
+ history.replace({
+ pathname: url.pathname,
+ search: url.search,
+ hash: url.hash,
+ });
+ }
+ }
+ }, []);
+};
+
+export default useRemoveSignUpCompleteParam;
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AnalyticsEvents.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AnalyticsEvents.java
index fdc8c2bc43..618149d21c 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AnalyticsEvents.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AnalyticsEvents.java
@@ -10,6 +10,7 @@ public enum AnalyticsEvents {
EXECUTE_ACTION("execute_ACTION_TRIGGERED"),
UPDATE_LAYOUT,
PUBLISH_APPLICATION("publish_APPLICATION"),
+ FORK
;
private final String eventName;
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java
index bf41cf3c73..b6d0e02e4e 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java
@@ -48,6 +48,9 @@ import static com.appsmith.server.acl.AclPermission.ORGANIZATION_READ_APPLICATIO
@Service
public class DatasourceServiceImpl extends BaseService implements DatasourceService {
+ private static final String LOCALHOST_STRING = "localhost";
+ private static final String LOCALHOST_IP = "127.0.0.1";
+
private final OrganizationService organizationService;
private final SessionUserService sessionUserService;
private final PluginService pluginService;
@@ -134,6 +137,19 @@ public class DatasourceServiceImpl extends BaseService populateHintMessages(Datasource datasource) {
if(datasource == null) {
@@ -157,7 +173,7 @@ public class DatasourceServiceImpl extends BaseService endpoint.getHost().contains("localhost"));
+ .anyMatch(endpoint -> endpointContainsLocalhost(endpoint));
}
if(usingLocalhostUrl) {
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java
index 6712b5e93b..ab574c8322 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java
@@ -756,12 +756,14 @@ public class NewActionServiceImpl extends BaseService Mono.zip(
Mono.just(application),
sessionUserService.getCurrentUser(),
- newPageService.getNameByPageId(actionDTO.getPageId(), viewMode)
+ newPageService.getNameByPageId(actionDTO.getPageId(), viewMode),
+ pluginService.getById(action.getPluginId())
))
.map(tuple -> {
final Application application = tuple.getT1();
final User user = tuple.getT2();
final String pageName = tuple.getT3();
+ final Plugin plugin = tuple.getT4();
final PluginType pluginType = action.getPluginType();
final Map data = new HashMap<>();
@@ -769,6 +771,7 @@ public class NewActionServiceImpl extends BaseService forkApplicationToOrganization(String applicationId, String organizationId) {
final Mono sourceApplicationMono = applicationService.findById(applicationId, AclPermission.READ_APPLICATIONS)
@@ -34,7 +40,9 @@ public class ApplicationForkingService {
final Mono targetOrganizationMono = organizationService.findById(organizationId, AclPermission.ORGANIZATION_MANAGE_APPLICATIONS)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.ACL_NO_RESOURCE_FOUND, "organization", organizationId)));
- return Mono.zip(sourceApplicationMono, targetOrganizationMono, sessionUserService.getCurrentUser())
+ Mono userMono = sessionUserService.getCurrentUser();
+
+ return Mono.zip(sourceApplicationMono, targetOrganizationMono, userMono)
.flatMap(tuple -> {
final Application application = tuple.getT1();
final Organization targetOrganization = tuple.getT2();
@@ -58,8 +66,29 @@ public class ApplicationForkingService {
})
.flatMap(applicationIds -> {
final String newApplicationId = applicationIds.get(0);
- return applicationService.getById(newApplicationId);
+ return applicationService.getById(newApplicationId)
+ .flatMap(application ->
+ sendForkApplicationAnalyticsEvent(applicationId, organizationId, application));
});
}
+ private Mono sendForkApplicationAnalyticsEvent(String applicationId, String orgId, Application application) {
+ return applicationService.findById(applicationId, AclPermission.READ_APPLICATIONS)
+ .flatMap(sourceApplication -> {
+
+ final Map data = Map.of(
+ "forkedFromAppId", applicationId,
+ "forkedToOrgId", orgId,
+ "forkedFromAppName", sourceApplication.getName()
+ );
+
+ return analyticsService.sendObjectEvent(AnalyticsEvents.FORK, application, data);
+ })
+ .onErrorResume(e -> {
+ log.warn("Error sending action execution data point", e);
+ return Mono.just(application);
+ });
+ }
+
+
}
diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java
index 20a2f4c752..9befaaf572 100644
--- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java
+++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java
@@ -984,7 +984,7 @@ public class DatasourceServiceTest {
@Test
@WithUserDetails(value = "api_user")
- public void testHintMessageOnLocalhostUrlOnUpdateEventOnNonApiDatasource() {
+ public void testHintMessageOnLocalhostIPAddressOnUpdateEventOnNonApiDatasource() {
Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())).thenReturn(Mono.just(new MockPluginExecutor()));
Datasource datasource = new Datasource();
@@ -1012,7 +1012,7 @@ public class DatasourceServiceTest {
DatasourceConfiguration datasourceConfiguration1 = new DatasourceConfiguration();
Connection connection1 = new Connection();
datasourceConfiguration1.setConnection(connection1);
- Endpoint endpoint = new Endpoint("http://localhost", 0L);
+ Endpoint endpoint = new Endpoint("http://127.0.0.1/xyz", 0L);
datasourceConfiguration1.setEndpoints(new ArrayList<>());
datasourceConfiguration1.getEndpoints().add(endpoint);
updates.setDatasourceConfiguration(datasourceConfiguration1);
@@ -1034,4 +1034,36 @@ public class DatasourceServiceTest {
})
.verifyComplete();
}
+
+ @Test
+ @WithUserDetails(value = "api_user")
+ public void testHintMessageNPE() {
+
+ Mockito.when(pluginExecutorHelper.getPluginExecutor(Mockito.any())).thenReturn(Mono.just(new MockPluginExecutor()));
+
+ Mono pluginMono = pluginService.findByName("Installed Plugin Name");
+ Datasource datasource = new Datasource();
+ datasource.setName("NPE check");
+ datasource.setOrganizationId(orgId);
+ DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration();
+ datasourceConfiguration.setEndpoints(new ArrayList<>());
+ Endpoint nullEndpoint = null;
+ datasourceConfiguration.getEndpoints().add(nullEndpoint);
+ Endpoint nullHost = new Endpoint(null, 0L);
+ datasourceConfiguration.getEndpoints().add(nullHost);
+
+ datasource.setDatasourceConfiguration(datasourceConfiguration);
+
+ Mono datasourceMono = pluginMono.map(plugin -> {
+ datasource.setPluginId(plugin.getId());
+ return datasource;
+ }).flatMap(datasourceService::create);
+
+ StepVerifier
+ .create(datasourceMono)
+ .assertNext(createdDatasource -> {
+ assertThat(createdDatasource.getMessages()).isEmpty();
+ })
+ .verifyComplete();
+ }
}
diff --git a/office_hours.md b/office_hours.md
index 7c556b0749..4ee2e13ea7 100644
--- a/office_hours.md
+++ b/office_hours.md
@@ -28,6 +28,16 @@ You can find the archives of the calls below with a brief summary of each sessio
## Archives
+Appsmith Live Demo #3, 29th May 2021: Stitching APIs together to automate workflows
+
+Video Link
+
+#### Summary
+
+Confidence shows the community how we internally use APIs from multiple services to build apps that simplifies our workflow within Appsmith. Top questions from members of our community was also discussed.
+
+------------------
+
Office Hours May 13th, 2021: Product roadmap discussion
Video Link