Merge branch 'feature/actions' into 'release'

Feature/actions

See merge request theappsmith/internal-tools-client!22
This commit is contained in:
Abhinav Jha 2019-09-17 10:31:26 +00:00
commit d19c747228
17 changed files with 322 additions and 163 deletions

View File

@ -77,9 +77,11 @@
"@typescript-eslint/eslint-plugin": "^2.0.0", "@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0", "@typescript-eslint/parser": "^2.0.0",
"dotenv": "^8.1.0", "dotenv": "^8.1.0",
"eslint": "^6.4.0",
"eslint-config-prettier": "^6.1.0", "eslint-config-prettier": "^6.1.0",
"eslint-config-react": "^1.1.7", "eslint-config-react": "^1.1.7",
"eslint-plugin-prettier": "^3.1.0", "eslint-plugin-prettier": "^3.1.0",
"eslint-plugin-react": "^7.14.3",
"icon-font-generator": "^2.1.10", "icon-font-generator": "^2.1.10",
"redux-devtools": "^3.5.0" "redux-devtools": "^3.5.0"
}, },

View File

@ -0,0 +1,14 @@
import {
ReduxActionTypes,
ReduxAction,
} from "../constants/ReduxActionConstants";
import { ActionPayload } from "../constants/ActionConstants";
export const executeAction = (
actionPayloads?: ActionPayload[],
): ReduxAction<ActionPayload[] | undefined> => {
return {
type: ReduxActionTypes.EXECUTE_ACTION,
payload: actionPayloads,
};
};

View File

@ -1,71 +1,120 @@
import Api, { HttpMethod } from "./Api" import API, { HttpMethod } from "./Api";
import { ApiResponse } from "./ApiResponses" import { ApiResponse } from "./ApiResponses";
import { APIRequest } from './ApiRequests'; import { APIRequest } from "./ApiRequests";
import _ from "lodash";
export interface CreateActionRequest<T> extends APIRequest { export interface CreateActionRequest<T> extends APIRequest {
resourceId: string resourceId: string;
actionConfiguration: T actionName: string;
actionConfiguration: T;
} }
export interface UpdateActionRequest<T> extends CreateActionRequest<T> { export interface UpdateActionRequest<T> extends CreateActionRequest<T> {
actionId: string actionId: string;
} }
export interface APIConfig { export interface APIConfig {
requestHeaders: Record<string, string> resourceId: string;
method: HttpMethod actionName: string;
path: string requestHeaders: Record<string, string>;
APIName: string method: HttpMethod;
body: JSON path: string;
queryParams: Record<string, string> body: JSON;
queryParams: Record<string, string>;
actionId: string;
}
export interface Property {
key: string;
value: string;
}
export interface APIConfigRequest {
headers: Property[];
httpMethod: HttpMethod;
path: string;
body: JSON;
queryParameters: Property[];
} }
export interface QueryConfig { export interface QueryConfig {
queryString: string queryString: string;
} }
export interface ActionCreatedResponse extends ApiResponse { export interface ActionCreateUpdateResponse extends ApiResponse {
actionId: string actionId: string;
dynamicBindingMap: Record<string, string> dynamicBindingMap: Record<string, string>;
}
export interface ActionUpdatedResponse extends ActionCreatedResponse {
} }
export interface ExecuteActionRequest extends APIRequest { export interface ExecuteActionRequest extends APIRequest {
actionId: string actionId: string;
dynamicBindingMap: Record<string, any> dynamicBindingMap: Record<string, any>;
} }
export interface ExecuteActionResponse extends ApiResponse { export interface ExecuteActionResponse extends ApiResponse {
actionId: string actionId: string;
data: any data: any;
} }
class ActionAPI extends Api { class ActionAPI extends API {
static url = "/actions" static url = "v1/actions";
static createAPI(createAPI: CreateActionRequest<APIConfig>): Promise<ActionCreatedResponse> { static createAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
return Api.post(ActionAPI.url, createAPI) const createAPI: CreateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: _.map(apiConfig.requestHeaders, (value, key) => {
return { key: key, value: value };
}),
queryParameters: _.map(apiConfig.queryParams, (value, key) => {
return { key: key, value: value };
}),
},
};
return API.post(ActionAPI.url, createAPI);
} }
static updateAPI(updateAPI: UpdateActionRequest<APIConfig>): Promise<ActionUpdatedResponse> { static updateAPI(apiConfig: APIConfig): Promise<ActionCreateUpdateResponse> {
return Api.post(ActionAPI.url, updateAPI) const updateAPI: UpdateActionRequest<APIConfigRequest> = {
resourceId: apiConfig.resourceId,
actionName: apiConfig.actionName,
actionId: apiConfig.actionId,
actionConfiguration: {
httpMethod: apiConfig.method,
path: apiConfig.path,
body: apiConfig.body,
headers: _.map(apiConfig.requestHeaders, (value, key) => {
return { key: key, value: value };
}),
queryParameters: _.map(apiConfig.queryParams, (value, key) => {
return { key: key, value: value };
}),
},
};
return API.post(ActionAPI.url, updateAPI);
} }
static createQuery(createQuery: CreateActionRequest<QueryConfig>): Promise<ActionCreatedResponse> { static createQuery(
return Api.post(ActionAPI.url, createQuery) createQuery: CreateActionRequest<QueryConfig>,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, createQuery);
} }
static updateQuery(updateQuery: UpdateActionRequest<QueryConfig>): Promise<ActionUpdatedResponse> { static updateQuery(
return Api.post(ActionAPI.url, updateQuery) updateQuery: UpdateActionRequest<QueryConfig>,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, updateQuery);
} }
static executeAction(executeAction: ExecuteActionRequest): Promise<ActionUpdatedResponse> { static executeAction(
return Api.post(ActionAPI.url, executeAction) executeAction: ExecuteActionRequest,
): Promise<ActionCreateUpdateResponse> {
return API.post(ActionAPI.url, executeAction);
} }
} }
export default ActionAPI export default ActionAPI;

View File

@ -10,7 +10,7 @@ export type EventType =
| "ON_CHECK_CHANGE" | "ON_CHECK_CHANGE"
| "ON_SELECT" | "ON_SELECT"
| "ON_DATE_SELECTED" | "ON_DATE_SELECTED"
| "ON_DATE_RANGE_SELECTED" | "ON_DATE_RANGE_SELECTED";
export type ActionType = export type ActionType =
| "API" | "API"
@ -19,57 +19,57 @@ export type ActionType =
| "ALERT" | "ALERT"
| "JS_FUNCTION" | "JS_FUNCTION"
| "SET_VALUE" | "SET_VALUE"
| "DOWNLOAD" | "DOWNLOAD";
export interface ActionPayload { export interface ActionPayload {
actionType: ActionType actionType: ActionType;
contextParams: Record<string, string> contextParams: Record<string, string>;
} }
export interface APIActionPayload extends ActionPayload { export interface APIActionPayload extends ActionPayload {
apiId: string apiId: string;
} }
export interface QueryActionPayload extends ActionPayload { export interface QueryActionPayload extends ActionPayload {
queryId: string queryId: string;
} }
export type NavigationType = "NEW_TAB" | "INLINE" export type NavigationType = "NEW_TAB" | "INLINE";
export interface NavigateActionPayload extends ActionPayload { export interface NavigateActionPayload extends ActionPayload {
pageUrl: string pageUrl: string;
navigationType: NavigationType navigationType: NavigationType;
} }
export interface ShowAlertActionPayload extends ActionPayload { export interface ShowAlertActionPayload extends ActionPayload {
header: string header: string;
message: string message: string;
alertType: AlertType alertType: AlertType;
intent: MessageIntent intent: MessageIntent;
} }
export interface SetValueActionPayload extends ActionPayload { export interface SetValueActionPayload extends ActionPayload {
header: string header: string;
message: string message: string;
alertType: AlertType alertType: AlertType;
intent: MessageIntent intent: MessageIntent;
} }
export interface ExecuteJSActionPayload extends ActionPayload { export interface ExecuteJSActionPayload extends ActionPayload {
jsFunctionId: string jsFunctionId: string;
} }
export type DownloadFiletype = "CSV" | "XLS" | "JSON" | "TXT" export type DownloadFiletype = "CSV" | "XLS" | "JSON" | "TXT";
export interface DownloadDataActionPayload extends ActionPayload { export interface DownloadDataActionPayload extends ActionPayload {
data: JSON data: JSON;
fileName: string fileName: string;
fileType: DownloadFiletype fileType: DownloadFiletype;
} }
export interface PageAction { export interface PageAction {
actionId: string actionId: string;
actionType: ActionType actionType: ActionType;
actionName: string actionName: string;
dynamicBindings: string[] dynamicBindings: string[];
} }

View File

@ -7,7 +7,9 @@ class ButtonComponent extends React.Component<ButtonComponentProps> {
render() { render() {
return ( return (
<Container {...this.props}> <Container {...this.props}>
<Button icon={this.props.icon}>{this.props.text}</Button> <Button icon={this.props.icon} onClick={this.props.onClick}>
{this.props.text}
</Button>
</Container> </Container>
); );
} }
@ -15,6 +17,7 @@ class ButtonComponent extends React.Component<ButtonComponentProps> {
interface ButtonComponentProps extends TextComponentProps { interface ButtonComponentProps extends TextComponentProps {
icon?: MaybeElement; icon?: MaybeElement;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
} }
export default ButtonComponent; export default ButtonComponent;

View File

@ -1,7 +1,8 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import WidgetFactory from "../../utils/WidgetFactory"; import WidgetFactory from "../../utils/WidgetFactory";
import { WidgetTypes } from "../../constants/WidgetConstants"; import { WidgetTypes, RenderModes } from "../../constants/WidgetConstants";
import { WidgetFunctions } from "../../widgets/BaseWidget";
import { useDrop } from "react-dnd"; import { useDrop } from "react-dnd";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
@ -15,6 +16,7 @@ const ArtBoard = styled.div`
interface CanvasProps { interface CanvasProps {
pageWidget: ContainerWidgetProps<any>; pageWidget: ContainerWidgetProps<any>;
addWidget: Function; addWidget: Function;
widgetFunctions: WidgetFunctions;
} }
const Canvas = (props: CanvasProps) => { const Canvas = (props: CanvasProps) => {
@ -25,7 +27,12 @@ const Canvas = (props: CanvasProps) => {
return ( return (
<React.Fragment> <React.Fragment>
<ArtBoard ref={drop}> <ArtBoard ref={drop}>
{props.pageWidget && WidgetFactory.createWidget(props.pageWidget)} {props.pageWidget &&
WidgetFactory.createWidget(
props.pageWidget,
props.widgetFunctions,
RenderModes.CANVAS,
)}
</ArtBoard> </ArtBoard>
</React.Fragment> </React.Fragment>
); );

View File

@ -4,6 +4,7 @@ import { XYCoord, useDragLayer } from "react-dnd";
import snapToGrid from "./snapToGrid"; import snapToGrid from "./snapToGrid";
import WidgetFactory from "../../utils/WidgetFactory"; import WidgetFactory from "../../utils/WidgetFactory";
import { RenderModes, WidgetType } from "../../constants/WidgetConstants"; import { RenderModes, WidgetType } from "../../constants/WidgetConstants";
import { ActionPayload } from "../../constants/ActionConstants";
const WrappedDragLayer = styled.div` const WrappedDragLayer = styled.div`
position: absolute; position: absolute;
@ -57,18 +58,21 @@ const EditorDragLayer: React.FC = () => {
})); }));
function renderItem() { function renderItem() {
return WidgetFactory.createWidget({ return WidgetFactory.createWidget(
widgetType: itemType as WidgetType, {
widgetName: "", widgetType: itemType as WidgetType,
widgetId: item.key, widgetName: "",
topRow: 10, widgetId: item.key,
leftColumn: 10, topRow: 10,
bottomRow: 14, leftColumn: 10,
rightColumn: 20, bottomRow: 14,
parentColumnSpace: 1, rightColumn: 20,
parentRowSpace: 1, parentColumnSpace: 1,
renderMode: RenderModes.CANVAS, parentRowSpace: 1,
}); },
{ executeAction: (actionPayload?: ActionPayload[]) => {} },
RenderModes.CANVAS,
);
} }
if (!isDragging) { if (!isDragging) {

View File

@ -10,7 +10,9 @@ import EditorHeader from "./EditorHeader";
import CanvasWidgetsNormalizer from "../../normalizers/CanvasWidgetsNormalizer"; import CanvasWidgetsNormalizer from "../../normalizers/CanvasWidgetsNormalizer";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
import { fetchPage, addWidget } from "../../actions/pageActions"; import { fetchPage, addWidget } from "../../actions/pageActions";
import { executeAction } from "../../actions/widgetActions";
import { RenderModes } from "../../constants/WidgetConstants"; import { RenderModes } from "../../constants/WidgetConstants";
import { ActionPayload } from "../../constants/ActionConstants";
const CanvasContainer = styled.section` const CanvasContainer = styled.section`
height: 100%; height: 100%;
@ -44,6 +46,7 @@ const EditorWrapper = styled.div`
type EditorProps = { type EditorProps = {
pageWidget: ContainerWidgetProps<any> | any; pageWidget: ContainerWidgetProps<any> | any;
fetchCanvasWidgets: Function; fetchCanvasWidgets: Function;
executeAction: (actionPayloads?: ActionPayload[]) => void;
cards: { [id: string]: WidgetCardProps[] } | any; cards: { [id: string]: WidgetCardProps[] } | any;
addPageWidget: Function; addPageWidget: Function;
page: string; page: string;
@ -66,6 +69,7 @@ class Editor extends Component<EditorProps> {
<Canvas <Canvas
pageWidget={this.props.pageWidget} pageWidget={this.props.pageWidget}
addWidget={this.addWidgetToCanvas} addWidget={this.addWidgetToCanvas}
widgetFunctions={{ executeAction: this.props.executeAction }}
/> />
</CanvasContainer> </CanvasContainer>
</EditorWrapper> </EditorWrapper>
@ -87,6 +91,8 @@ const mapStateToProps = (state: AppState): EditorReduxState => {
const mapDispatchToProps = (dispatch: any) => { const mapDispatchToProps = (dispatch: any) => {
return { return {
executeAction: (actionPayloads?: ActionPayload[]) =>
dispatch(executeAction(actionPayloads)),
fetchCanvasWidgets: (pageId: string) => fetchCanvasWidgets: (pageId: string) =>
dispatch(fetchPage(pageId, RenderModes.CANVAS)), dispatch(fetchPage(pageId, RenderModes.CANVAS)),
addPageWidget: (pageId: string, widgetProps: WidgetProps) => addPageWidget: (pageId: string, widgetProps: WidgetProps) =>

View File

@ -1,28 +1,28 @@
import { createReducer } from "../../utils/AppsmithUtils" import { createReducer } from "../../utils/AppsmithUtils";
import { import {
ReduxActionTypes, ReduxActionTypes,
ReduxAction, ReduxAction,
} from "../../constants/ReduxActionConstants" } from "../../constants/ReduxActionConstants";
import _ from "lodash" import _ from "lodash";
import { ActionCreatedResponse } from '../../api/ActionAPI' import { ActionCreateUpdateResponse } from "../../api/ActionAPI";
import { PageAction } from '../../constants/ActionConstants'; import { PageAction } from "../../constants/ActionConstants";
const initialState: ActionDataState = { const initialState: ActionDataState = {};
}
export interface ActionDataState { export interface ActionDataState {
[name: string]: ActionCreatedResponse [name: string]: ActionCreateUpdateResponse;
} }
const actionsReducer = createReducer(initialState, { const actionsReducer = createReducer(initialState, {
[ReduxActionTypes.LOAD_CANVAS_ACTIONS]: ( [ReduxActionTypes.LOAD_CANVAS_ACTIONS]: (
state: ActionDataState, state: ActionDataState,
action: ReduxAction<PageAction[]> action: ReduxAction<PageAction[]>,
) => { ) => {
const actionMap = _.mapKeys(action.payload, (action: PageAction) => { return action.actionId }) const actionMap = _.mapKeys(action.payload, (action: PageAction) => {
return { ...state, ...actionMap } return action.actionId;
} });
}) return { ...state, ...actionMap };
},
});
export default actionsReducer export default actionsReducer;

View File

@ -1,17 +1,15 @@
import CanvasWidgetsNormalizer from "../normalizers/CanvasWidgetsNormalizer";
import { import {
ReduxActionTypes, ReduxActionTypes,
ReduxAction, ReduxAction,
} from "../constants/ReduxActionConstants"; } from "../constants/ReduxActionConstants";
import PageApi, { PageResponse, PageRequest } from "../api/PageApi"; import { call, takeEvery, select, all } from "redux-saga/effects";
import { call, put, takeEvery, select, all } from "redux-saga/effects";
import { RenderModes } from "../constants/WidgetConstants";
import { import {
APIActionPayload, APIActionPayload,
QueryActionPayload, QueryActionPayload,
PageAction, PageAction,
ActionPayload,
} from "../constants/ActionConstants"; } from "../constants/ActionConstants";
import ActionAPI, { ActionCreatedResponse } from "../api/ActionAPI"; import ActionAPI, { ActionCreateUpdateResponse } from "../api/ActionAPI";
import { AppState } from "../reducers"; import { AppState } from "../reducers";
import { JSONPath } from "jsonpath-plus"; import { JSONPath } from "jsonpath-plus";
import _ from "lodash"; import _ from "lodash";
@ -23,21 +21,21 @@ const getDataTree = (state: AppState) => {
const getAction = ( const getAction = (
state: AppState, state: AppState,
actionId: string, actionId: string,
): ActionCreatedResponse => { ): ActionCreateUpdateResponse => {
return state.entities.actions[actionId]; return state.entities.actions[actionId];
}; };
export function* evaluateJSONPath(jsonPath: string): any { export function* evaluateJSONPathSaga(jsonPath: string): any {
const dataTree = yield select(getDataTree); const dataTree = yield select(getDataTree);
const result = JSONPath({ path: jsonPath, json: dataTree }); const result = JSONPath({ path: jsonPath, json: dataTree });
return result; return result;
} }
export function* executeAPIAction(apiAction: APIActionPayload) { export function* executeAPIActionSaga(apiAction: APIActionPayload) {
const api: PageAction = yield select(getAction, apiAction.apiId); const api: PageAction = yield select(getAction, apiAction.apiId);
const responses: any = yield all( const responses: any = yield all(
api.dynamicBindings.map((jsonPath: string) => { api.dynamicBindings.map((jsonPath: string) => {
return call(evaluateJSONPath, jsonPath); return call(evaluateJSONPathSaga, jsonPath);
}), }),
); );
const dynamicBindingMap: Record<string, any> = _.keyBy( const dynamicBindingMap: Record<string, any> = _.keyBy(
@ -52,11 +50,11 @@ export function* executeAPIAction(apiAction: APIActionPayload) {
}); });
} }
export function* executeQueryAction(queryAction: QueryActionPayload) { export function* executeQueryActionSaga(queryAction: QueryActionPayload) {
const query: PageAction = yield select(getAction, queryAction.queryId); const query: PageAction = yield select(getAction, queryAction.queryId);
const responses: any = yield all( const responses: any = yield all(
query.dynamicBindings.map((jsonPath: string) => { query.dynamicBindings.map((jsonPath: string) => {
return call(evaluateJSONPath, jsonPath); return call(evaluateJSONPathSaga, jsonPath);
}), }),
); );
const dynamicBindingMap: Record<string, any> = _.keyBy( const dynamicBindingMap: Record<string, any> = _.keyBy(
@ -71,28 +69,21 @@ export function* executeQueryAction(queryAction: QueryActionPayload) {
}); });
} }
export function* executeAction(pageRequestAction: ReduxAction<PageRequest>) { export function* executeActionSaga(action: ReduxAction<ActionPayload[]>) {
const pageRequest = pageRequestAction.payload; if (!_.isNil(action.payload)) {
try { yield all(
const pageResponse: PageResponse = yield call( action.payload.map((actionPayload: ActionPayload) => {
PageApi.fetchPage, switch (actionPayload.actionType) {
pageRequest, case "API":
const apiActionPaylod: APIActionPayload = actionPayload as APIActionPayload;
return call(executeAPIActionSaga, apiActionPaylod);
}
return undefined;
}),
); );
if (pageRequest.renderMode === RenderModes.CANVAS) {
const normalizedResponse = CanvasWidgetsNormalizer.normalize(
pageResponse,
);
const payload = {
pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets,
};
yield put({ type: ReduxActionTypes.UPDATE_CANVAS, payload });
}
} catch (err) {
//TODO(abhinav): REFACTOR THIS
} }
} }
export function* watchExecuteAction() { export function* watchExecuteActionSaga() {
yield takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeAction); yield takeEvery(ReduxActionTypes.EXECUTE_ACTION, executeActionSaga);
} }

View File

@ -36,6 +36,6 @@ export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) {
} }
} }
export function* watchFetchPage() { export function* watchFetchPageSaga() {
yield takeEvery(ReduxActionTypes.FETCH_PAGE, fetchPageSaga); yield takeEvery(ReduxActionTypes.FETCH_PAGE, fetchPageSaga);
} }

View File

@ -1,12 +1,12 @@
import { all, spawn } from "redux-saga/effects"; import { all, spawn } from "redux-saga/effects";
import { watchFetchPage } from "../sagas/PageSagas"; import { watchFetchPageSaga } from "../sagas/PageSagas";
import { fetchWidgetCardsSaga } from "./WidgetCardsPaneSagas"; import { fetchWidgetCardsSaga } from "./WidgetCardsPaneSagas";
import { watchExecuteAction } from "./ActionSagas"; import { watchExecuteActionSaga } from "./ActionSagas";
export function* rootSaga() { export function* rootSaga() {
yield all([ yield all([
spawn(watchFetchPage), spawn(watchFetchPageSaga),
spawn(fetchWidgetCardsSaga), spawn(fetchWidgetCardsSaga),
spawn(watchExecuteAction), spawn(watchExecuteActionSaga),
]); ]);
} }

View File

@ -1,5 +1,10 @@
import { WidgetType } from "../constants/WidgetConstants"; import { WidgetType, RenderMode } from "../constants/WidgetConstants";
import { WidgetBuilder, WidgetProps } from "../widgets/BaseWidget"; import {
WidgetBuilder,
WidgetProps,
WidgetFunctions,
WidgetDataProps,
} from "../widgets/BaseWidget";
class WidgetFactory { class WidgetFactory {
static widgetMap: Map<WidgetType, WidgetBuilder<WidgetProps>> = new Map(); static widgetMap: Map<WidgetType, WidgetBuilder<WidgetProps>> = new Map();
@ -11,11 +16,22 @@ class WidgetFactory {
this.widgetMap.set(widgetType, widgetBuilder); this.widgetMap.set(widgetType, widgetBuilder);
} }
static createWidget(widgetData: WidgetProps): JSX.Element { static createWidget(
widgetData.key = widgetData.widgetId; widgetData: WidgetDataProps,
widgetFunctions: WidgetFunctions,
renderMode: RenderMode,
): JSX.Element {
const widgetProps: WidgetProps = {
key: widgetData.widgetId,
renderMode: renderMode,
...widgetData,
...widgetFunctions,
};
const widgetBuilder = this.widgetMap.get(widgetData.widgetType); const widgetBuilder = this.widgetMap.get(widgetData.widgetType);
if (widgetBuilder) return widgetBuilder.buildWidget(widgetData); if (widgetBuilder) {
else { const widget = widgetBuilder.buildWidget(widgetProps);
return widget;
} else {
const ex: WidgetCreationException = { const ex: WidgetCreationException = {
message: message:
"Widget Builder not registered for widget type" + "Widget Builder not registered for widget type" +

View File

@ -14,9 +14,10 @@ import { BaseStyle } from "../editorComponents/BaseComponent";
import _ from "lodash"; import _ from "lodash";
import React from "react"; import React from "react";
import DraggableComponent from "../editorComponents/DraggableComponent"; import DraggableComponent from "../editorComponents/DraggableComponent";
import { ActionPayload } from "../constants/ActionConstants";
abstract class BaseWidget< abstract class BaseWidget<
T extends WidgetProps, T extends WidgetProps & WidgetFunctions,
K extends WidgetState K extends WidgetState
> extends Component<T, K> { > extends Component<T, K> {
constructor(props: T) { constructor(props: T) {
@ -147,24 +148,31 @@ export interface DraggableWidget {
} }
export interface WidgetBuilder<T extends WidgetProps> { export interface WidgetBuilder<T extends WidgetProps> {
buildWidget(data: T): JSX.Element; buildWidget(widgetProps: T): JSX.Element;
} }
export interface WidgetProps { export interface WidgetProps extends WidgetFunctions, WidgetDataProps {
key?: string;
renderMode: RenderMode;
}
export interface WidgetDataProps {
widgetId: string; widgetId: string;
widgetType: WidgetType; widgetType: WidgetType;
widgetName: string; widgetName: string;
key?: string;
topRow: number; topRow: number;
leftColumn: number; leftColumn: number;
bottomRow: number; bottomRow: number;
rightColumn: number; rightColumn: number;
parentColumnSpace: number; parentColumnSpace: number;
parentRowSpace: number; parentRowSpace: number;
renderMode: RenderMode;
isVisible?: boolean; isVisible?: boolean;
} }
export interface WidgetFunctions {
executeAction: (actionPayloads?: ActionPayload[]) => void;
}
export interface WidgetCardProps { export interface WidgetCardProps {
widgetType: WidgetType; widgetType: WidgetType;
key?: string; key?: string;

View File

@ -5,13 +5,20 @@ import ButtonComponent from "../editorComponents/ButtonComponent";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> { class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
onButtonClick() {
this.props.executeAction(this.props.onClick);
}
getPageView() { getPageView() {
return ( return (
<ButtonComponent <ButtonComponent
style={this.getPositionStyle()} style={this.getPositionStyle()}
widgetId={this.props.widgetId} widgetId={this.props.widgetId}
key={this.props.widgetId} key={this.props.widgetId}
text={this.props.text || "Button"} text={this.props.text}
onClick={() => {
this.onButtonClick();
}}
/> />
); );
} }

View File

@ -1,5 +1,9 @@
import React from "react"; import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget"; import BaseWidget, {
WidgetProps,
WidgetState,
WidgetFunctions,
} from "./BaseWidget";
import ContainerComponent from "../editorComponents/ContainerComponent"; import ContainerComponent from "../editorComponents/ContainerComponent";
import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants"; import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants";
import WidgetFactory from "../utils/WidgetFactory"; import WidgetFactory from "../utils/WidgetFactory";
@ -49,7 +53,12 @@ class ContainerWidget extends BaseWidget<
renderChildWidget(childWidgetData: WidgetProps) { renderChildWidget(childWidgetData: WidgetProps) {
childWidgetData.parentColumnSpace = this.state.snapColumnSpace; childWidgetData.parentColumnSpace = this.state.snapColumnSpace;
childWidgetData.parentRowSpace = this.state.snapRowSpace; childWidgetData.parentRowSpace = this.state.snapRowSpace;
return WidgetFactory.createWidget(childWidgetData); const widgetFunctions: WidgetFunctions = this.props as WidgetFunctions;
return WidgetFactory.createWidget(
childWidgetData,
widgetFunctions,
this.props.renderMode,
);
} }
getPageView() { getPageView() {

View File

@ -4411,7 +4411,7 @@ eslint-plugin-react-hooks@^1.6.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA== integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==
eslint-plugin-react@7.14.3: eslint-plugin-react@7.14.3, eslint-plugin-react@^7.14.3:
version "7.14.3" version "7.14.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13"
integrity sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA== integrity sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==
@ -4505,6 +4505,49 @@ eslint@^6.1.0, eslint@^6.4.0:
text-table "^0.2.0" text-table "^0.2.0"
v8-compile-cache "^2.0.3" v8-compile-cache "^2.0.3"
eslint@^6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a"
integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==
dependencies:
"@babel/code-frame" "^7.0.0"
ajv "^6.10.0"
chalk "^2.1.0"
cross-spawn "^6.0.5"
debug "^4.0.1"
doctrine "^3.0.0"
eslint-scope "^5.0.0"
eslint-utils "^1.4.2"
eslint-visitor-keys "^1.1.0"
espree "^6.1.1"
esquery "^1.0.1"
esutils "^2.0.2"
file-entry-cache "^5.0.1"
functional-red-black-tree "^1.0.1"
glob-parent "^5.0.0"
globals "^11.7.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
inquirer "^6.4.1"
is-glob "^4.0.0"
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0"
lodash "^4.17.14"
minimatch "^3.0.4"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
progress "^2.0.0"
regexpp "^2.0.1"
semver "^6.1.2"
strip-ansi "^5.2.0"
strip-json-comments "^3.0.1"
table "^5.2.3"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^6.1.1: espree@^6.1.1:
version "6.1.1" version "6.1.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de"