Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions app/client/src/actions/evaluationActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import _ from "lodash";
import { DataTree } from "../entities/DataTree/dataTreeFactory";
import { DependencyMap } from "../utils/DynamicBindingUtils";
import { Diff } from "deep-diff";
import { QueryActionConfig } from "../entities/Action";

export const FIRST_EVAL_REDUX_ACTIONS = [
// Pages
Expand Down Expand Up @@ -80,3 +81,26 @@ export const setDependencyMap = (
payload: { inverseDependencyMap },
};
};

// Called when a form is being setup, for setting up the base condition evaluations for the form
export const initFormEvaluations = (
editorConfig: any,
Comment thread
ApekshaBhosale marked this conversation as resolved.
settingConfig: any,
formId: string,
) => {
return {
type: ReduxActionTypes.INIT_FORM_EVALUATION,
payload: { editorConfig, settingConfig, formId },
};
};

// Called when there is change in the data of the form, re evaluates the whole form
export const startFormEvaluations = (
formId: string,
formData: QueryActionConfig,
) => {
return {
type: ReduxActionTypes.RUN_FORM_EVALUATION,
payload: { formId, actionConfiguration: formData },
};
};
9 changes: 8 additions & 1 deletion app/client/src/api/PluginApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@ export type PluginId = string;
export type PluginPackageName = string;
export type GenerateCRUDEnabledPluginMap = Record<PluginId, PluginPackageName>;

export enum UIComponentTypes {
DbEditorForm = "DbEditorForm",
UQIDbEditorForm = "UQIDbEditorForm",
ApiEditorForm = "ApiEditorForm",
RapidApiEditorForm = "RapidApiEditorForm",
}

export interface Plugin {
id: string;
name: string;
type: PluginType;
packageName: string;
iconLocation?: string;
uiComponent: "ApiEditorForm" | "RapidApiEditorForm" | "DbEditorForm";
uiComponent: UIComponentTypes;
datasourceComponent: "RestAPIDatasourceForm" | "AutoForm";
Comment thread
ayushpahwa marked this conversation as resolved.
Outdated
allowUserDatasources?: boolean;
templates: Record<string, string>;
Expand Down
2 changes: 2 additions & 0 deletions app/client/src/components/formControls/BaseControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface ControlBuilder<T extends ControlProps> {
}

export interface ControlProps extends ControlData, ControlFunctions {
serverLabel?: string;
key?: string;
extraData?: ControlData[];
formName: string;
Expand All @@ -49,6 +50,7 @@ export interface ControlData {
validationRegex?: string;
dataType?: InputType;
isRequired?: boolean;
conditionals: string;
hidden?: HiddenType;
placeholderText?: string;
schema?: any;
Expand Down
3 changes: 3 additions & 0 deletions app/client/src/constants/ReduxActionConstants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,9 @@ export const ReduxActionTypes = {
TOGGLE_SHOW_GLOBAL_SEARCH_MODAL: "TOGGLE_SHOW_GLOBAL_SEARCH_MODAL",
FETCH_RELEASES_SUCCESS: "FETCH_RELEASES_SUCCESS",
RESET_UNREAD_RELEASES_COUNT: "RESET_UNREAD_RELEASES_COUNT",
SET_FORM_EVALUATION: "SET_FORM_EVALUATION",
INIT_FORM_EVALUATION: "INIT_FORM_EVALUATION",
RUN_FORM_EVALUATION: "RUN_FORM_EVALUATION",
SET_LOADING_ENTITIES: "SET_LOADING_ENTITIES",
RESET_CURRENT_APPLICATION: "RESET_CURRENT_APPLICATION",
SELECT_WIDGETS_IN_AREA: "SELECT_WIDGETS_IN_AREA",
Expand Down
60 changes: 58 additions & 2 deletions app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ import { thinScrollbar } from "constants/DefaultTheme";
import ActionRightPane from "components/editorComponents/ActionRightPane";
import { SuggestedWidget } from "api/ActionAPI";
import { getActionTabsInitialIndex } from "selectors/editorSelectors";
import TooltipComponent from "components/ads/Tooltip";
import { UIComponentTypes } from "../../../api/PluginApi";
import TooltipComponent from "../../../components/ads/Tooltip";

const QueryFormContainer = styled.form`
display: flex;
Expand Down Expand Up @@ -365,6 +366,7 @@ type QueryFormProps = {
isRunning: boolean;
dataSources: Datasource[];
DATASOURCES_OPTIONS: any;
uiComponent: UIComponentTypes;
executedQueryData?: {
body: any;
isExecutionSuccess?: boolean;
Expand All @@ -386,6 +388,7 @@ type ReduxProps = {
responseType: string | undefined;
pluginId: string;
documentationLink: string | undefined;
evalState: Record<string, any>;
Comment thread
ayushpahwa marked this conversation as resolved.
Outdated
};

export type EditorJSONtoFormProps = QueryFormProps & ReduxProps;
Expand All @@ -409,6 +412,7 @@ export function EditorJSONtoForm(props: Props) {
responseType,
runErrorMessage,
settingConfig,
uiComponent,
} = props;
let error = runErrorMessage;
let output: Record<string, any>[] | null = null;
Expand Down Expand Up @@ -505,6 +509,53 @@ export function EditorJSONtoForm(props: Props) {
}
};

// V2 call to make rendering more flexible, used for UQI forms
const renderEachConfigV2 = (formName: string) => (section: any): any => {
return section.children.map(
(formControlOrSection: ControlProps, idx: number) => {
if (!!formControlOrSection && props.hasOwnProperty("evalState")) {
let allowToRender = true;
if (
formControlOrSection.hasOwnProperty("configProperty") &&
props.evalState.hasOwnProperty(formControlOrSection.configProperty)
) {
allowToRender =
props?.evalState[formControlOrSection.configProperty].visible;
} else if (
formControlOrSection.hasOwnProperty("serverLabel") &&
!!formControlOrSection.serverLabel &&
props.evalState.hasOwnProperty(formControlOrSection.serverLabel)
) {
allowToRender =
props?.evalState[formControlOrSection.serverLabel].visible;
}

if (!allowToRender) return null;
}

if (formControlOrSection.hasOwnProperty("children")) {
return renderEachConfigV2(formName)(formControlOrSection);
} else {
try {
const { configProperty } = formControlOrSection;
return (
<FieldWrapper key={`${configProperty}_${idx}`}>
<FormControl
config={formControlOrSection}
formName={formName}
/>
</FieldWrapper>
);
} catch (e) {
log.error(e);
}
}
return null;
},
);
};

// Recursive call to render forms pre UQI
const renderEachConfig = (formName: string) => (section: any): any => {
return section.children.map(
(formControlOrSection: ControlProps, idx: number) => {
Expand Down Expand Up @@ -711,8 +762,13 @@ export function EditorJSONtoForm(props: Props) {
title: "Query",
panelComponent: (
<SettingsWrapper>
{/*// Selectively rendering form based on uiComponent prop*/}
{editorConfig && editorConfig.length > 0 ? (
editorConfig.map(renderEachConfig(formName))
uiComponent === UIComponentTypes.UQIDbEditorForm ? (
editorConfig.map(renderEachConfigV2(formName))
) : (
editorConfig.map(renderEachConfig(formName))
)
Comment thread
ayushpahwa marked this conversation as resolved.
Outdated
) : (
<>
<ErrorMessage>
Expand Down
10 changes: 10 additions & 0 deletions app/client/src/pages/Editor/QueryEditor/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { EditorJSONtoForm, EditorJSONtoFormProps } from "./EditorJSONtoForm";
import { getFormValues } from "redux-form";
import { QueryAction } from "entities/Action";
import { getFormEvaluationState } from "../../../selectors/formSelectors";
Comment thread
ayushpahwa marked this conversation as resolved.
Outdated

const valueSelector = formValueSelector(QUERY_EDITOR_FORM_NAME);
const mapStateToProps = (state: AppState) => {
Expand All @@ -21,6 +22,14 @@ const mapStateToProps = (state: AppState) => {
const documentationLinks = getPluginDocumentationLinks(state);
const formData = getFormValues(QUERY_EDITOR_FORM_NAME)(state) as QueryAction;

// State to manage the evaluations for the form
let evalState = {};

// Fetching evaluations state only once the formData is populated
if (!!formData) {
evalState = getFormEvaluationState(state)[formData.id];
}

return {
actionName,
pluginId,
Expand All @@ -29,6 +38,7 @@ const mapStateToProps = (state: AppState) => {
documentationLink: documentationLinks[pluginId],
formName: QUERY_EDITOR_FORM_NAME,
formData: formData,
evalState,
};
};

Expand Down
88 changes: 85 additions & 3 deletions app/client/src/pages/Editor/QueryEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { deleteAction, runActionInit } from "actions/actionActions";
import { AppState } from "reducers";
import { getIsEditorInitialized } from "selectors/editorSelectors";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { Plugin } from "api/PluginApi";
import { Plugin, UIComponentTypes } from "api/PluginApi";
import { Datasource } from "entities/Datasource";
import {
getPluginIdsOfPackageNames,
Expand All @@ -25,14 +25,20 @@ import {
getActionResponses,
} from "selectors/entitiesSelector";
import { PLUGIN_PACKAGE_DBS } from "constants/QueryEditorConstants";
import { QueryAction } from "entities/Action";
import { QueryAction, QueryActionConfig } from "entities/Action";
import Spinner from "components/editorComponents/Spinner";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { changeQuery } from "actions/queryPaneActions";
import PerformanceTracker, {
PerformanceTransactionName,
} from "utils/PerformanceTracker";
import AnalyticsUtil from "utils/AnalyticsUtil";
import {
initFormEvaluations,
startFormEvaluations,
} from "../../../actions/evaluationActions";
Comment thread
ApekshaBhosale marked this conversation as resolved.
Outdated
import { isObject } from "lodash";
import { getUIComponent } from "../../../selectors/formSelectors";

const EmptyStateContainer = styled.div`
display: flex;
Expand All @@ -48,6 +54,12 @@ type ReduxDispatchProps = {
runAction: (actionId: string) => void;
deleteAction: (id: string, name: string) => void;
changeQueryPage: (queryId: string) => void;
runFormEvaluation: (formId: string, formData: QueryActionConfig) => void;
initFormEvaluation: (
editorConfig: any,
Comment thread
ApekshaBhosale marked this conversation as resolved.
settingConfig: any,
formId: string,
) => void;
};

type ReduxStateProps = {
Expand All @@ -64,15 +76,50 @@ type ReduxStateProps = {
editorConfig: any;
settingConfig: any;
isEditorInitialized: boolean;
uiComponent: UIComponentTypes;
};

type StateAndRouteProps = RouteComponentProps<QueryEditorRouteParams>;

type Props = StateAndRouteProps & ReduxDispatchProps & ReduxStateProps;

// Helper function to deep compare 2 objects, used to debounce calls to the eval saga
function deepEqual(object1: any, object2: any) {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);

Comment thread
ApekshaBhosale marked this conversation as resolved.
Outdated
if (keys1.length !== keys2.length) {
return false;
}

for (const key of keys1) {
const val1 = object1[key];
const val2 = object2[key];
const areObjects = isObject(val1) && isObject(val2);
if (
(areObjects && !deepEqual(val1, val2)) ||
(!areObjects && val1 !== val2)
) {
return false;
}
}

return true;
}

class QueryEditor extends React.Component<Props> {
constructor(props: Props) {
super(props);
this.props.initFormEvaluation(
this.props.editorConfig,
this.props.settingConfig,
this.props.match.params.queryId,
);
}

componentDidMount() {
this.props.changeQueryPage(this.props.match.params.queryId);

PerformanceTracker.stopTracking(PerformanceTransactionName.OPEN_ACTION, {
actionType: "QUERY",
});
Expand Down Expand Up @@ -105,6 +152,24 @@ class QueryEditor extends React.Component<Props> {
if (prevProps.match.params.queryId !== this.props.match.params.queryId) {
this.props.changeQueryPage(this.props.match.params.queryId);
}
// If statement to debounce and track changes in the formData to update evaluations
if (
this.props.uiComponent === UIComponentTypes.UQIDbEditorForm &&
!!this.props.formData &&
(!prevProps.formData ||
(this.props.formData.hasOwnProperty("actionConfiguration") &&
!!prevProps.formData &&
prevProps.formData.hasOwnProperty("actionConfiguration") &&
!deepEqual(
prevProps.formData.actionConfiguration,
this.props.formData.actionConfiguration,
)))
) {
this.props.runFormEvaluation(
this.props.formData.id,
this.props.formData.actionConfiguration,
);
}
}

render() {
Expand All @@ -123,6 +188,7 @@ class QueryEditor extends React.Component<Props> {
responses,
runErrorMessage,
settingConfig,
uiComponent,
} = this.props;
const { applicationId, pageId } = this.props.match.params;

Expand Down Expand Up @@ -165,6 +231,7 @@ class QueryEditor extends React.Component<Props> {
onRunClick={this.handleRunClick}
runErrorMessage={runErrorMessage[queryId]}
settingConfig={settingConfig}
uiComponent={uiComponent}
/>
);
}
Expand Down Expand Up @@ -196,9 +263,13 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
settingConfig = settingConfigs[pluginId];
}

const allPlugins = getPlugins(state);
let uiComponent = UIComponentTypes.DbEditorForm;
if (!!pluginId) uiComponent = getUIComponent(state, pluginId, allPlugins);

return {
pluginImages: getPluginImages(state),
plugins: getPlugins(state),
plugins: allPlugins,
runErrorMessage,
pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS),
dataSources: getDBDatasources(state),
Expand All @@ -210,6 +281,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
settingConfig,
isCreating: state.ui.apiPane.isCreating,
isEditorInitialized: getIsEditorInitialized(state),
uiComponent,
};
};

Expand All @@ -220,6 +292,16 @@ const mapDispatchToProps = (dispatch: any): ReduxDispatchProps => ({
changeQueryPage: (queryId: string) => {
dispatch(changeQuery(queryId));
},
runFormEvaluation: (formId: string, formData: QueryActionConfig) => {
dispatch(startFormEvaluations(formId, formData));
},
initFormEvaluation: (
editorConfig: any,
Comment thread
ayushpahwa marked this conversation as resolved.
settingsConfig: any,
formId: string,
) => {
dispatch(initFormEvaluations(editorConfig, settingsConfig, formId));
},
});

export default connect(mapStateToProps, mapDispatchToProps)(QueryEditor);
Loading