diff --git a/app/client/src/components/propertyControls/ActionSelector.tsx b/app/client/src/components/propertyControls/ActionSelector.tsx
index 6992664b1c..17f4c121e4 100644
--- a/app/client/src/components/propertyControls/ActionSelector.tsx
+++ b/app/client/src/components/propertyControls/ActionSelector.tsx
@@ -14,34 +14,91 @@ import { connect } from "react-redux";
import { AppState } from "../../reducers";
import { ActionDataState } from "../../reducers/entityReducers/actionsReducer";
-const DEFAULT_ACTION_TYPE = "Select Action Type";
+const DEFAULT_ACTION_TYPE = "Select Action Type" as ActionType;
+const DEFAULT_ACTION_LABEL = "Select Action";
+enum ACTION_RESOLUTION_TYPE {
+ SUCCESS,
+ ERROR,
+}
+
+function getActions(
+ actionPayloads: ActionPayload[] | undefined,
+): {
+ action: ActionPayload | undefined;
+ onSuccessAction: ActionPayload | undefined;
+ onErrorAction: ActionPayload | undefined;
+} {
+ let action: ActionPayload | undefined = actionPayloads && actionPayloads[0];
+ let onSuccessAction: ActionPayload | undefined =
+ action && action.onSuccess && action.onSuccess[0];
+ let onErrorAction: ActionPayload | undefined =
+ action && action.onError && action.onError[0];
+ return {
+ action,
+ onSuccessAction,
+ onErrorAction,
+ };
+}
class ActionSelectorControl extends BaseControl<
ControlProps & ActionDataState
> {
- getSelectionActionType(): string {
- const selectedActionTypeValue =
- this.props.propertyValue &&
- this.props.propertyValue[0] &&
- this.props.propertyValue[0].actionType;
+ getSelectionActionType(type: ACTION_RESOLUTION_TYPE | string): ActionType {
+ let selectedActionTypeValue: ActionType | undefined;
+ const { action, onSuccessAction, onErrorAction } = getActions(
+ this.props.propertyValue,
+ );
+
+ switch (type) {
+ case this.props.propertyName:
+ selectedActionTypeValue = action && action.actionType;
+ break;
+ case ACTION_RESOLUTION_TYPE.SUCCESS:
+ selectedActionTypeValue = onSuccessAction && onSuccessAction.actionType;
+ break;
+ case ACTION_RESOLUTION_TYPE.ERROR:
+ selectedActionTypeValue = onErrorAction && onErrorAction.actionType;
+ break;
+ default:
+ break;
+ }
const foundActionType = PropertyPaneActionDropdownOptions.find(
actionType => actionType.value === selectedActionTypeValue,
);
- return foundActionType ? foundActionType.label : DEFAULT_ACTION_TYPE;
+ return foundActionType
+ ? (foundActionType.label as ActionType)
+ : DEFAULT_ACTION_TYPE;
}
- getSelectionActionLabel(allActions: DropdownOption[]): string {
- const selectedActionId =
- this.props.propertyValue &&
- this.props.propertyValue[0] &&
- this.props.propertyValue[0].actionId;
+ getSelectionActionLabel(
+ type: ACTION_RESOLUTION_TYPE | string,
+ allActions: DropdownOption[],
+ ): string {
+ let selectedActionId: string | undefined = "";
+ const { action, onSuccessAction, onErrorAction } = getActions(
+ this.props.propertyValue,
+ );
+
+ switch (type) {
+ case this.props.propertyName:
+ selectedActionId = action && action.actionId;
+ break;
+ case ACTION_RESOLUTION_TYPE.SUCCESS:
+ selectedActionId = onSuccessAction && onSuccessAction.actionId;
+ break;
+ case ACTION_RESOLUTION_TYPE.ERROR:
+ selectedActionId = onErrorAction && onErrorAction.actionId;
+ break;
+ default:
+ break;
+ }
const foundAction = allActions.find(
action => action.value === selectedActionId,
);
- return foundAction ? foundAction.label : "Select Action";
+ return foundAction ? foundAction.label : DEFAULT_ACTION_LABEL;
}
render() {
const actionTypeOptions: DropdownOption[] = PropertyPaneActionDropdownOptions;
@@ -51,16 +108,98 @@ class ActionSelectorControl extends BaseControl<
value: action.id,
};
});
- const selectedActionType = this.getSelectionActionType();
- const selectedActionLabel = this.getSelectionActionLabel(allActions);
+ const selectedActionType = this.getSelectionActionType(
+ this.props.propertyName,
+ );
+ const selectedActionLabel = this.getSelectionActionLabel(
+ this.props.propertyName,
+ allActions,
+ );
+
+ const selectedSuccessActionType = this.getSelectionActionType(
+ ACTION_RESOLUTION_TYPE.SUCCESS,
+ );
+ const selectedSuccessActionLabel = this.getSelectionActionLabel(
+ ACTION_RESOLUTION_TYPE.SUCCESS,
+ allActions,
+ );
+
+ const selectedErrorActionType = this.getSelectionActionType(
+ ACTION_RESOLUTION_TYPE.ERROR,
+ );
+ const selectedErrorActionLabel = this.getSelectionActionLabel(
+ ACTION_RESOLUTION_TYPE.ERROR,
+ allActions,
+ );
return (
-
+ {this.renderActionSelector(
+ allActions,
+ actionTypeOptions,
+ selectedActionType,
+ selectedActionLabel,
+ this.props.propertyName,
+ this.props.propertyName,
+ )}
+ {selectedActionLabel !== DEFAULT_ACTION_LABEL &&
+ this.renderActionSelector(
+ allActions,
+ actionTypeOptions,
+ selectedSuccessActionType,
+ selectedSuccessActionLabel,
+ "On Success",
+ ACTION_RESOLUTION_TYPE.SUCCESS,
+ )}
+ {selectedActionLabel !== DEFAULT_ACTION_LABEL &&
+ this.renderActionSelector(
+ allActions,
+ actionTypeOptions,
+ selectedErrorActionType,
+ selectedErrorActionLabel,
+ "On Error",
+ ACTION_RESOLUTION_TYPE.ERROR,
+ )}
+
+ );
+ }
+
+ renderActionSelector(
+ allActions: DropdownOption[],
+ actionTypeOptions: DropdownOption[],
+ selectedActionType: ActionType,
+ selectedActionLabel: string,
+ label: string,
+ actionResolutionType: ACTION_RESOLUTION_TYPE | string,
+ ) {
+ let onTypeSelect = this.onActionTypeSelect;
+ switch (actionResolutionType) {
+ case ACTION_RESOLUTION_TYPE.SUCCESS:
+ onTypeSelect = this.onSuccessActionTypeSelect;
+ break;
+ case ACTION_RESOLUTION_TYPE.ERROR:
+ onTypeSelect = this.onErrorActionTypeSelect;
+ break;
+ }
+
+ let onActionSelect = this.onActionSelect;
+ switch (actionResolutionType) {
+ case ACTION_RESOLUTION_TYPE.SUCCESS:
+ onTypeSelect = this.onSuccessActionSelect;
+ break;
+ case ACTION_RESOLUTION_TYPE.ERROR:
+ onTypeSelect = this.onErrorActionSelect;
+ break;
+ }
+ return (
+
+
+
+
}
>
@@ -71,23 +210,25 @@ class ActionSelectorControl extends BaseControl<
items={allActions}
filterable={false}
itemRenderer={this.renderItem}
- onItemSelect={this.onActionSelect}
+ onItemSelect={onActionSelect}
noResults={
}
>
)}
-
+
);
}
-
- onTypeSelect = (item: DropdownOption): void => {
+ onActionTypeSelect = (item: DropdownOption) => {
const actionPayloads: ActionPayload[] = this.props.propertyValue
? this.props.propertyValue.slice()
: [];
- const actionPayload = actionPayloads[0];
- if (actionPayload) {
+ let actionPayload = actionPayloads[0];
+
+ if (actionPayload && actionPayload.actionType !== item.value) {
actionPayload.actionId = "";
+ actionPayload.onError = undefined;
+ actionPayload.onSuccess = undefined;
actionPayload.actionType = item.value as ActionType;
} else {
const actionPayload = { actionType: item.value } as ActionPayload;
@@ -95,16 +236,83 @@ class ActionSelectorControl extends BaseControl<
}
this.updateProperty(this.props.propertyName, actionPayloads);
};
+ onSuccessActionTypeSelect = (item: DropdownOption) => {
+ const actionPayloads: ActionPayload[] = this.props.propertyValue
+ ? this.props.propertyValue.slice()
+ : [];
+ let actionPayload = actionPayloads[0];
+
+ if (actionPayload) {
+ const successActionPayloads: ActionPayload[] =
+ actionPayload.onSuccess || [];
+ let successActionPayload = successActionPayloads[0];
+ if (successActionPayload) {
+ successActionPayload.actionId = "";
+ successActionPayload.actionType = item.value as ActionType;
+ } else {
+ const successActionPayload = {
+ actionType: item.value,
+ } as ActionPayload;
+ successActionPayloads.push(successActionPayload);
+ }
+ actionPayload.onSuccess = successActionPayloads;
+ }
+ this.updateProperty(this.props.propertyName, actionPayloads);
+ };
+ onErrorActionTypeSelect = (item: DropdownOption) => {
+ const actionPayloads: ActionPayload[] = this.props.propertyValue
+ ? this.props.propertyValue.slice()
+ : [];
+ let actionPayload = actionPayloads[0];
+
+ if (actionPayload) {
+ const errorActionPayloads: ActionPayload[] = actionPayload.onError || [];
+ let errorActionPayload = errorActionPayloads[0];
+ if (errorActionPayload) {
+ errorActionPayload.actionId = "";
+ errorActionPayload.actionType = item.value as ActionType;
+ } else {
+ const errorActionPayload = {
+ actionType: item.value,
+ } as ActionPayload;
+ errorActionPayloads.push(errorActionPayload);
+ }
+ actionPayload.onError = errorActionPayloads;
+ }
+ this.updateProperty(this.props.propertyName, actionPayloads);
+ };
onActionSelect = (item: DropdownOption): void => {
const actionPayloads: ActionPayload[] = this.props.propertyValue
? this.props.propertyValue.slice()
: [];
const actionPayload = actionPayloads[0];
- actionPayload.actionId = item.value as ActionType;
+ actionPayload.actionId = item.value;
this.updateProperty(this.props.propertyName, actionPayloads);
};
+ onSuccessActionSelect = (item: DropdownOption): void => {
+ const actionPayloads: ActionPayload[] = this.props.propertyValue
+ ? this.props.propertyValue.slice()
+ : [];
+ const actionPayload = actionPayloads[0];
+ const successActionPayloads: ActionPayload[] = actionPayload.onSuccess as ActionPayload[];
+ const successActionPayload = successActionPayloads[0];
+ successActionPayload.actionId = item.value;
+ actionPayload.onSuccess = successActionPayloads;
+ this.updateProperty(this.props.propertyName, actionPayloads);
+ };
+ onErrorActionSelect = (item: DropdownOption): void => {
+ const actionPayloads: ActionPayload[] = this.props.propertyValue
+ ? this.props.propertyValue.slice()
+ : [];
+ const actionPayload = actionPayloads[0];
+ const errorActionPayloads: ActionPayload[] = actionPayload.onError as ActionPayload[];
+ const errorActionPayload = errorActionPayloads[0];
+ errorActionPayload.actionId = item.value;
+ actionPayload.onError = errorActionPayloads;
+ this.updateProperty(this.props.propertyName, actionPayloads);
+ };
renderItem = (option: DropdownOption, itemProps: IItemRendererProps) => {
if (!itemProps.modifiers.matchesPredicate) {
diff --git a/app/client/src/constants/ActionConstants.tsx b/app/client/src/constants/ActionConstants.tsx
index e928c659db..9474567c66 100644
--- a/app/client/src/constants/ActionConstants.tsx
+++ b/app/client/src/constants/ActionConstants.tsx
@@ -22,16 +22,6 @@ export type ActionType =
| "SET_VALUE"
| "DOWNLOAD";
-export enum ActionType1 {
- "API",
- "QUERY",
- "NAVIGATION",
- "ALERT",
- "JS_FUNCTION",
- "SET_VALUE",
- "DOWNLOAD",
-}
-
export const PropertyPaneActionDropdownOptions: DropdownOption[] = [
{ label: "Call API", value: "API" },
// { label: "Run Query", value: "QUERY" },
@@ -41,6 +31,8 @@ export interface ActionPayload {
actionId: string;
actionType: ActionType;
contextParams: Record;
+ onSuccess?: ActionPayload[];
+ onError?: ActionPayload[];
}
export type NavigationType = "NEW_TAB" | "INLINE";
diff --git a/app/client/src/sagas/ActionSagas.ts b/app/client/src/sagas/ActionSagas.ts
index 3f9789be6d..d4dfd7336c 100644
--- a/app/client/src/sagas/ActionSagas.ts
+++ b/app/client/src/sagas/ActionSagas.ts
@@ -80,6 +80,13 @@ export function* executeAPIQueryActionSaga(apiAction: { actionId: string }) {
statusCode: response.responseMeta.error.code,
...response,
};
+ if (apiAction.onError) {
+ yield call(executeActionSaga, apiAction.onError);
+ }
+ } else {
+ if (apiAction.onSuccess) {
+ yield call(executeActionSaga, apiAction.onSuccess);
+ }
}
yield put({
type: ReduxActionTypes.EXECUTE_ACTION_SUCCESS,
@@ -88,19 +95,25 @@ export function* executeAPIQueryActionSaga(apiAction: { actionId: string }) {
return response;
}
-export function* executeActionSaga(action: ReduxAction) {
+// TODO(satbir): Refact this to not make this recursive.
+export function* executeActionSaga(actionPayloads: ActionPayload[]): any {
+ yield all(
+ _.map(actionPayloads, (actionPayload: ActionPayload) => {
+ switch (actionPayload.actionType) {
+ case "API":
+ return call(executeAPIQueryActionSaga, actionPayload);
+ case "QUERY":
+ return call(executeAPIQueryActionSaga, actionPayload);
+ default:
+ return undefined;
+ }
+ }),
+ );
+}
+
+export function* executeReduxActionSaga(action: ReduxAction) {
if (!_.isNil(action.payload)) {
- yield all(
- _.map(action.payload, (actionPayload: ActionPayload) => {
- switch (actionPayload.actionType) {
- case "API":
- return call(executeAPIQueryActionSaga, actionPayload);
- case "QUERY":
- return call(executeAPIQueryActionSaga, actionPayload);
- }
- return undefined;
- }),
- );
+ yield call(executeActionSaga, action.payload);
}
}
@@ -181,7 +194,7 @@ export function* deleteActionSaga(actionPayload: ReduxAction<{ id: string }>) {
export function* watchActionSagas() {
yield all([
takeEvery(ReduxActionTypes.FETCH_ACTIONS_INIT, fetchActionsSaga),
- takeLatest(ReduxActionTypes.EXECUTE_ACTION, executeActionSaga),
+ takeLatest(ReduxActionTypes.EXECUTE_ACTION, executeReduxActionSaga),
takeLatest(ReduxActionTypes.CREATE_ACTION_INIT, createActionSaga),
takeLatest(ReduxActionTypes.UPDATE_ACTION_INIT, updateActionSaga),
takeLatest(ReduxActionTypes.DELETE_ACTION_INIT, deleteActionSaga),
diff --git a/app/client/src/widgets/TableWidget.tsx b/app/client/src/widgets/TableWidget.tsx
index e27779ec17..b6f339c737 100644
--- a/app/client/src/widgets/TableWidget.tsx
+++ b/app/client/src/widgets/TableWidget.tsx
@@ -57,13 +57,13 @@ class TableWidget extends BaseWidget {
data={tableData}
maxHeight={height}
selectedRowIndex={
- this.props.selectedRow && this.props.selectedRow.index
+ this.props.selectedRow && this.props.selectedRow.rowIndex
}
onRowClick={(rowData: object, index: number) => {
const { widgetId, onRowSelected } = this.props;
super.updateWidgetProperty(widgetId, "selectedRow", {
- data: rowData,
- index: index,
+ ...rowData,
+ rowIndex: index,
});
super.executeAction(onRowSelected);
}}
@@ -84,6 +84,10 @@ export interface TableAction extends ActionPayload {
actionName: string;
}
+interface RowData {
+ rowIndex: number;
+}
+
export interface TableWidgetProps extends WidgetProps {
nextPageKey?: string;
prevPageKey?: string;
@@ -92,10 +96,7 @@ export interface TableWidgetProps extends WidgetProps {
recordActions?: TableAction[];
onPageChange?: ActionPayload[];
onRowSelected?: ActionPayload[];
- selectedRow?: {
- data: object;
- index: number;
- };
+ selectedRow?: object & RowData;
}
export default TableWidget;