WIP: Fix fetch page. Add save page boilerplate. Add widget property change boilerplate.

This commit is contained in:
Abhinav Jha 2019-09-17 20:39:55 +05:30
parent 20a3e19ad3
commit 703081154c
22 changed files with 230 additions and 206 deletions

View File

@ -1,15 +1,23 @@
import { PageRequest } from "../api/PageApi"; import { FetchPageRequest } from "../api/PageApi";
import { RenderMode } from "../constants/WidgetConstants"; import { RenderMode } from "../constants/WidgetConstants";
import { WidgetProps } from "../widgets/BaseWidget"; import {
WidgetProps,
WidgetDynamicProperty,
WidgetDynamicProperties,
} from "../widgets/BaseWidget";
import { import {
ReduxActionTypes, ReduxActionTypes,
ReduxAction, ReduxAction,
LoadCanvasWidgetsPayload,
SavePagePayload,
SavePageErrorPayload,
SavePageSuccessPayload,
} from "../constants/ReduxActionConstants"; } from "../constants/ReduxActionConstants";
export const fetchPage = ( export const fetchPage = (
pageId: string, pageId: string,
renderMode: RenderMode, renderMode: RenderMode,
): ReduxAction<PageRequest> => { ): ReduxAction<FetchPageRequest> => {
return { return {
type: ReduxActionTypes.FETCH_PAGE, type: ReduxActionTypes.FETCH_PAGE,
payload: { payload: {
@ -44,3 +52,50 @@ export const removeWidget = (
}, },
}; };
}; };
export const loadCanvasWidgets = (
payload: LoadCanvasWidgetsPayload,
): ReduxAction<LoadCanvasWidgetsPayload> => {
return {
type: ReduxActionTypes.LOAD_CANVAS_WIDGETS,
payload,
};
};
export const savePage = (payload: SavePagePayload) => {
return {
type: ReduxActionTypes.SAVE_PAGE_INIT,
payload,
};
};
export const savePageSuccess = (payload: SavePageSuccessPayload) => {
return {
type: ReduxActionTypes.SAVE_PAGE_SUCCESS,
payload,
};
};
export const savePageError = (payload: SavePageErrorPayload) => {
return {
type: ReduxActionTypes.SAVE_PAGE_ERROR,
payload,
};
};
export const updateWidget = (
property: WidgetDynamicProperty,
widget: WidgetProps,
payload: any,
) => {
switch (property) {
case WidgetDynamicProperties.CHILDREN:
return;
case WidgetDynamicProperties.EXISTENCE:
return;
case WidgetDynamicProperties.POSITION:
return;
case WidgetDynamicProperties.SIZE:
return;
}
};

View File

@ -1,16 +1,17 @@
import Api from "./Api"; import Api from "./Api";
import { ContainerWidgetProps } from "../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../widgets/ContainerWidget";
import { ApiResponse } from "./ApiResponses"; import { ApiResponse } from "./ApiResponses";
import { WidgetProps } from "../widgets/BaseWidget";
import { RenderMode } from "../constants/WidgetConstants"; import { RenderMode } from "../constants/WidgetConstants";
import { PageAction } from "../constants/ActionConstants"; import { PageAction } from "../constants/ActionConstants";
export interface PageRequest { export interface FetchPageRequest {
pageId: string; pageId: string;
renderMode: RenderMode; renderMode: RenderMode;
} }
export interface SavePageRequest { export interface SavePageRequest {
pageWidget: ContainerWidgetProps<any>; pageWidget: ContainerWidgetProps<WidgetProps>;
} }
export interface PageLayout { export interface PageLayout {
@ -18,7 +19,7 @@ export interface PageLayout {
actions: PageAction[]; actions: PageAction[];
} }
export interface PageResponse extends ApiResponse { export interface FetchPageResponse extends ApiResponse {
layout: PageLayout; layout: PageLayout;
} }
@ -29,11 +30,11 @@ export interface SavePageResponse {
class PageApi extends Api { class PageApi extends Api {
static url = "/page"; static url = "/page";
static fetchPage(pageRequest: PageRequest): Promise<PageResponse> { static fetchPage(pageRequest: FetchPageRequest): Promise<FetchPageResponse> {
return Api.get(PageApi.url + "/" + pageRequest.pageId, pageRequest); return Api.get(PageApi.url + "/" + pageRequest.pageId, pageRequest);
} }
static savePage(savePageRequest: SavePageRequest): Promise<PageResponse> { static savePage(savePageRequest: SavePageRequest): Promise<SavePageResponse> {
return Api.post(PageApi.url, undefined, savePageRequest); return Api.post(PageApi.url, undefined, savePageRequest);
} }
} }

View File

@ -1,31 +1,32 @@
// import ContainerWidget from "../widgets/ContainerWidget" // import ContainerWidget from "../widgets/ContainerWidget"
import { WidgetProps, WidgetCardProps } from "../widgets/BaseWidget"; import { WidgetProps, WidgetCardProps } from "../widgets/BaseWidget";
export type ReduxActionType = // export type ReduxActionType =
| "LOAD_CANVAS_WIDGETS" // | "LOAD_CANVAS_WIDGETS"
| "FETCH_CANVAS" // | "UPDATE_CANVAS"
| "CLEAR_CANVAS" // | "FETCH_CANVAS"
| "DROP_WIDGET_CANVAS" // | "CLEAR_CANVAS"
| "REMOVE_WIDGET_CANVAS" // | "DROP_WIDGET_CANVAS"
| "LOAD_WIDGET_PANE" // | "REMOVE_WIDGET_CANVAS"
| "FETCH_PAGE" // | "LOAD_WIDGET_PANE"
| "ZOOM_IN_CANVAS" // | "FETCH_PAGE"
| "ZOOM_OUT_CANVAS" // | "ZOOM_IN_CANVAS"
| "PUBLISH" // | "ZOOM_OUT_CANVAS"
| "UNDO_CANVAS_ACTION" // | "PUBLISH"
| "REDO_CANVAS_ACTION" // | "UNDO_CANVAS_ACTION"
| "FETCH_WIDGET_CARDS" // | "REDO_CANVAS_ACTION"
| "SUCCESS_FETCHING_WIDGET_CARDS" // | "FETCH_WIDGET_CARDS"
| "ERROR_FETCHING_WIDGET_CARDS" // | "SUCCESS_FETCHING_WIDGET_CARDS"
| "ADD_PAGE_WIDGET" // | "ERROR_FETCHING_WIDGET_CARDS"
| "REMOVE_PAGE_WIDGET" // | "ADD_PAGE_WIDGET"
| "LOAD_WIDGET_CONFIG" // | "REMOVE_PAGE_WIDGET"
| "LOAD_API_RESPONSE" // | "LOAD_WIDGET_CONFIG"
| "LOAD_QUERY_RESPONSE" // | "LOAD_API_RESPONSE"
| "EXECUTE_ACTION" // | "LOAD_QUERY_RESPONSE"
| "LOAD_CANVAS_ACTIONS"; // | "EXECUTE_ACTION"
// | "LOAD_CANVAS_ACTIONS";
export const ReduxActionTypes: { [id: string]: ReduxActionType } = { export const ReduxActionTypes = {
LOAD_CANVAS_WIDGETS: "LOAD_CANVAS_WIDGETS", LOAD_CANVAS_WIDGETS: "LOAD_CANVAS_WIDGETS",
FETCH_CANVAS: "FETCH_CANVAS", FETCH_CANVAS: "FETCH_CANVAS",
CLEAR_CANVAS: "CLEAR_CANVAS", CLEAR_CANVAS: "CLEAR_CANVAS",
@ -48,8 +49,13 @@ export const ReduxActionTypes: { [id: string]: ReduxActionType } = {
LOAD_QUERY_RESPONSE: "LOAD_QUERY_RESPONSE", LOAD_QUERY_RESPONSE: "LOAD_QUERY_RESPONSE",
EXECUTE_ACTION: "EXECUTE_ACTION", EXECUTE_ACTION: "EXECUTE_ACTION",
LOAD_CANVAS_ACTIONS: "LOAD_CANVAS_ACTIONS", LOAD_CANVAS_ACTIONS: "LOAD_CANVAS_ACTIONS",
SAVE_PAGE_INIT: "SAVE_PAGE_INIT",
SAVE_PAGE_SUCCESS: "SAVE_PAGE_SUCCESS",
SAVE_PAGE_ERROR: "SAVE_PAGE_ERROR",
}; };
export type ReduxActionType = (typeof ReduxActionTypes)[keyof typeof ReduxActionTypes];
export interface ReduxAction<T> { export interface ReduxAction<T> {
type: ReduxActionType; type: ReduxActionType;
payload: T; payload: T;
@ -75,3 +81,7 @@ export interface LoadWidgetPanePayload {
export interface LoadWidgetCardsPanePayload { export interface LoadWidgetCardsPanePayload {
cards: { [id: string]: WidgetCardProps[] }; cards: { [id: string]: WidgetCardProps[] };
} }
export type SavePagePayload = {};
export type SavePageErrorPayload = {};
export type SavePageSuccessPayload = {};

View File

@ -7,7 +7,7 @@ import { ContainerProps } from "./ContainerComponent";
type DraggableComponentProps = WidgetProps & ContainerProps; type DraggableComponentProps = WidgetProps & ContainerProps;
const DraggableComponent = (props: DraggableComponentProps) => { const DraggableComponent = (props: DraggableComponentProps) => {
const [{ isDragging }, drag, preview] = useDrag({ const [, drag, preview] = useDrag({
item: props, item: props,
collect: (monitor: DragSourceMonitor) => ({ collect: (monitor: DragSourceMonitor) => ({
isDragging: monitor.isDragging(), isDragging: monitor.isDragging(),
@ -17,6 +17,7 @@ const DraggableComponent = (props: DraggableComponentProps) => {
<React.Fragment> <React.Fragment>
<DragPreviewImage connect={preview} src={blankImage} /> <DragPreviewImage connect={preview} src={blankImage} />
<div <div
ref={drag}
style={{ style={{
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
@ -34,36 +35,4 @@ const DraggableComponent = (props: DraggableComponentProps) => {
); );
}; };
// class DraggableComponent extends React.Component<DraggableProps, WidgetState> {
// render() {
// return props.connectDragSource(
// ,
// );
// }
// }
// const widgetSource = {
// beginDrag(props: WidgetProps) {
// return {
// widgetId: props.widgetId,
// widgetType: props.type,
// };
// },
// };
const widgetType = (props: WidgetProps) => {
return props.type;
};
// function collect(connect: DragSourceConnector, monitor: DragSourceMonitor) {
// return {
// connectDragSource: connect.dragSource(),
// isDragging: monitor.isDragging(),
// };
// }
// export default DragSource(widgetType, widgetSource, collect)(
// DraggableComponent,
// );
export default DraggableComponent; export default DraggableComponent;

View File

@ -1,9 +1,11 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { WidgetProps } from "../widgets/BaseWidget"; import { WidgetProps, WidgetDynamicProperties } from "../widgets/BaseWidget";
import { useDrop, XYCoord } from "react-dnd"; import { useDrop, XYCoord } from "react-dnd";
import { ContainerProps } from "./ContainerComponent"; import { ContainerProps } from "./ContainerComponent";
import WidgetFactory from "../utils/WidgetFactory"; import WidgetFactory from "../utils/WidgetFactory";
type DropTargetComponentProps = ContainerProps & { onDrop: Function }; type DropTargetComponentProps = ContainerProps & {
onPropertyChange?: Function;
};
export const DropTargetComponent = (props: DropTargetComponentProps) => { export const DropTargetComponent = (props: DropTargetComponentProps) => {
const [isOver, setIsOver] = useState(false); const [isOver, setIsOver] = useState(false);
const [, drop] = useDrop({ const [, drop] = useDrop({
@ -14,7 +16,12 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
const delta = monitor.getDifferenceFromInitialOffset() as XYCoord; const delta = monitor.getDifferenceFromInitialOffset() as XYCoord;
const left = Math.round(item.left + delta.x); const left = Math.round(item.left + delta.x);
const top = Math.round(item.top + delta.y); const top = Math.round(item.top + delta.y);
props.onDrop && props.onDrop({ item, left, top }); props.onPropertyChange &&
props.onPropertyChange(WidgetDynamicProperties.CHILDREN, props, {
item,
left,
top,
});
} }
return undefined; return undefined;
}, },

View File

@ -1,5 +1,5 @@
import { normalize, schema, denormalize } from "normalizr"; import { normalize, schema, denormalize } from "normalizr";
import { PageResponse } from "../api/PageApi"; import { FetchPageResponse } from "../api/PageApi";
import { ContainerWidgetProps } from "../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../widgets/ContainerWidget";
export const widgetSchema = new schema.Entity( export const widgetSchema = new schema.Entity(
@ -10,7 +10,9 @@ export const widgetSchema = new schema.Entity(
widgetSchema.define({ children: [widgetSchema] }); widgetSchema.define({ children: [widgetSchema] });
class CanvasWidgetsNormalizer { class CanvasWidgetsNormalizer {
static normalize(pageResponse: PageResponse): { entities: any; result: any } { static normalize(
pageResponse: FetchPageResponse,
): { entities: any; result: any } {
return normalize(pageResponse.layout.dsl, widgetSchema); return normalize(pageResponse.layout.dsl, widgetSchema);
} }

View File

@ -19,7 +19,7 @@ const Canvas = (props: CanvasProps) => {
return ( return (
<React.Fragment> <React.Fragment>
<ArtBoard> <ArtBoard>
{props.layout && WidgetFactory.createWidget(props.layout)} {props.layout.widgetId && WidgetFactory.createWidget(props.layout)}
</ArtBoard> </ArtBoard>
</React.Fragment> </React.Fragment>
); );

View File

@ -1,9 +1,6 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { XYCoord, useDragLayer } from "react-dnd"; import { useDragLayer } from "react-dnd";
import snapToGrid from "./snapToGrid";
import WidgetFactory from "../../utils/WidgetFactory";
import { RenderModes, WidgetType } from "../../constants/WidgetConstants";
const WrappedDragLayer = styled.div` const WrappedDragLayer = styled.div`
position: absolute; position: absolute;
@ -13,51 +10,17 @@ const WrappedDragLayer = styled.div`
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
cursor: grab;
`; `;
function getItemStyles(
initialOffset: XYCoord | null,
currentOffset: XYCoord | null,
) {
if (!initialOffset || !currentOffset) {
return {
display: "none",
};
}
let { x, y } = currentOffset;
x -= initialOffset.x;
y -= initialOffset.y;
[x, y] = snapToGrid(64, x, y);
x += initialOffset.x;
y += initialOffset.y;
const transform = `translate(${x}px, ${y}px)`;
return {
transform,
WebkitTransform: transform,
};
}
const EditorDragLayer = () => { const EditorDragLayer = () => {
const { isDragging, initialOffset, currentOffset } = useDragLayer( const { isDragging } = useDragLayer(monitor => ({
monitor => ({ isDragging: monitor.isDragging(),
item: monitor.getItem(), }));
itemType: monitor.getItemType(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging(),
}),
);
if (!isDragging) { if (!isDragging) {
return null; return null;
} }
return ( return <WrappedDragLayer></WrappedDragLayer>;
<WrappedDragLayer>
<div style={getItemStyles(initialOffset, currentOffset)}></div>
</WrappedDragLayer>
);
}; };
export default EditorDragLayer; export default EditorDragLayer;

View File

@ -43,7 +43,7 @@ export const IconLabel = styled.h5`
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
const WidgetCard = (props: CardProps) => { const WidgetCard = (props: CardProps) => {
const [{ isDragging }, drag, preview] = useDrag({ const [, drag, preview] = useDrag({
item: props.details, item: props.details,
collect: (monitor: DragSourceMonitor) => ({ collect: (monitor: DragSourceMonitor) => ({
isDragging: monitor.isDragging(), isDragging: monitor.isDragging(),

View File

@ -2,14 +2,18 @@ import React, { Component } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import styled from "styled-components"; import styled from "styled-components";
import Canvas from "./Canvas"; import Canvas from "./Canvas";
import { WidgetCardProps, WidgetProps } from "../../widgets/BaseWidget"; import {
WidgetCardProps,
WidgetProps,
WidgetDynamicProperty,
} from "../../widgets/BaseWidget";
import { AppState } from "../../reducers"; import { AppState } from "../../reducers";
import { EditorReduxState } from "../../reducers/uiReducers/editorReducer"; import { EditorReduxState } from "../../reducers/uiReducers/editorReducer";
import WidgetCardsPane from "./WidgetCardsPane"; import WidgetCardsPane from "./WidgetCardsPane";
import EditorHeader from "./EditorHeader"; 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, updateWidget } from "../../actions/pageActions";
import { RenderModes } from "../../constants/WidgetConstants"; import { RenderModes } from "../../constants/WidgetConstants";
import EditorDragLayer from "./EditorDragLayer"; import EditorDragLayer from "./EditorDragLayer";
@ -43,10 +47,10 @@ const EditorWrapper = styled.div`
`; `;
type EditorProps = { type EditorProps = {
pageWidget: ContainerWidgetProps<WidgetProps> | any; layout: ContainerWidgetProps<WidgetProps> | any;
fetchCanvasWidgets: Function; fetchCanvasWidgets: Function;
cards: { [id: string]: WidgetCardProps[] } | any; cards: { [id: string]: WidgetCardProps[] } | any;
addPageWidget: Function; updateWidgetProperty: Function;
page: string; page: string;
}; };
@ -55,8 +59,6 @@ class Editor extends Component<EditorProps> {
this.props.fetchCanvasWidgets("1"); this.props.fetchCanvasWidgets("1");
} }
addWidgetToCanvas = (): void => {};
public render() { public render() {
return ( return (
<React.Fragment> <React.Fragment>
@ -67,8 +69,8 @@ class Editor extends Component<EditorProps> {
<CanvasContainer> <CanvasContainer>
<Canvas <Canvas
layout={{ layout={{
...this.props.pageWidget, ...this.props.layout,
onDrop: this.props.addPageWidget, onPropertyChange: this.props.updateWidgetProperty,
}} }}
/> />
</CanvasContainer> </CanvasContainer>
@ -79,13 +81,14 @@ class Editor extends Component<EditorProps> {
} }
const mapStateToProps = (state: AppState): EditorReduxState => { const mapStateToProps = (state: AppState): EditorReduxState => {
const pageWidget = CanvasWidgetsNormalizer.denormalize( const layout = CanvasWidgetsNormalizer.denormalize(
state.ui.canvas.pageWidgetId, state.ui.editor.pageWidgetId,
state.entities, state.entities,
); );
return { return {
cards: state.ui.widgetCardsPane.cards, cards: state.ui.widgetCardsPane.cards,
pageWidget, layout,
pageWidgetId: state.ui.editor.pageWidgetId,
}; };
}; };
@ -93,8 +96,11 @@ const mapDispatchToProps = (dispatch: any) => {
return { return {
fetchCanvasWidgets: (pageId: string) => fetchCanvasWidgets: (pageId: string) =>
dispatch(fetchPage(pageId, RenderModes.CANVAS)), dispatch(fetchPage(pageId, RenderModes.CANVAS)),
addPageWidget: (pageId: string, widgetProps: WidgetProps) => updateWidgetProperty: (
dispatch(addWidget(pageId, widgetProps)), propertyType: WidgetDynamicProperty,
widgetProps: WidgetProps,
payload: any,
) => dispatch(updateWidget(propertyType, widgetProps, payload)),
}; };
}; };

View File

@ -14,7 +14,7 @@ export interface FlattenedWidgetProps extends WidgetProps {
} }
const canvasWidgetsReducer = createReducer(initialState, { const canvasWidgetsReducer = createReducer(initialState, {
[ReduxActionTypes.UPDATE_CANVAS]: ( [ReduxActionTypes.LOAD_CANVAS_WIDGETS]: (
state: CanvasWidgetsReduxState, state: CanvasWidgetsReduxState,
action: ReduxAction<LoadCanvasWidgetsPayload>, action: ReduxAction<LoadCanvasWidgetsPayload>,
) => { ) => {

View File

@ -1,15 +1,15 @@
import { combineReducers } from "redux" import { combineReducers } from "redux";
import canvasWidgetsReducer from "./canvasWidgetsReducer" import canvasWidgetsReducer from "./canvasWidgetsReducer";
import apiDataReducer from './apiDataReducer'; import apiDataReducer from "./apiDataReducer";
import queryDataReducer from './queryDataReducer'; import queryDataReducer from "./queryDataReducer";
import widgetConfigReducer from './widgetConfigReducer.tsx'; import widgetConfigReducer from "./widgetConfigReducer.tsx";
import actionsReducer from './actionsReducer'; import actionsReducer from "./actionsReducer";
const entityReducer = combineReducers({ const entityReducer = combineReducers({
canvasWidgets: canvasWidgetsReducer, canvasWidgets: canvasWidgetsReducer,
apiData: apiDataReducer, apiData: apiDataReducer,
queryData: queryDataReducer, queryData: queryDataReducer,
widgetConfig: widgetConfigReducer, widgetConfig: widgetConfigReducer,
actions: actionsReducer actions: actionsReducer,
}) });
export default entityReducer export default entityReducer;

View File

@ -1,7 +1,6 @@
import { combineReducers } from "redux"; import { combineReducers } from "redux";
import entityReducer from "./entityReducers"; import entityReducer from "./entityReducers";
import uiReducer from "./uiReducers"; import uiReducer from "./uiReducers";
import { CanvasReduxState } from "./uiReducers/canvasReducer";
import { CanvasWidgetsReduxState } from "./entityReducers/canvasWidgetsReducer"; import { CanvasWidgetsReduxState } from "./entityReducers/canvasWidgetsReducer";
import { WidgetCardsPaneReduxState } from "./uiReducers/widgetCardsPaneReducer"; import { WidgetCardsPaneReduxState } from "./uiReducers/widgetCardsPaneReducer";
import { EditorReduxState } from "./uiReducers/editorReducer"; import { EditorReduxState } from "./uiReducers/editorReducer";
@ -18,9 +17,7 @@ export default appReducer;
export interface AppState { export interface AppState {
ui: { ui: {
canvas: CanvasReduxState;
widgetCardsPane: WidgetCardsPaneReduxState; widgetCardsPane: WidgetCardsPaneReduxState;
// editorHeader: EditorHeaderReduxState;
editor: EditorReduxState; editor: EditorReduxState;
}; };
entities: { entities: {

View File

@ -1,25 +0,0 @@
import { createReducer } from "../../utils/AppsmithUtils";
import {
ReduxActionTypes,
LoadCanvasWidgetsPayload,
ReduxAction,
} from "../../constants/ReduxActionConstants";
const initialState: CanvasReduxState = {
pageWidgetId: "0",
};
const canvasReducer = createReducer(initialState, {
[ReduxActionTypes.UPDATE_CANVAS]: (
state: CanvasReduxState,
action: ReduxAction<LoadCanvasWidgetsPayload>,
) => {
return { pageWidgetId: action.payload.pageWidgetId };
},
});
export interface CanvasReduxState {
pageWidgetId: string;
}
export default canvasReducer;

View File

@ -8,22 +8,21 @@ import {
import { WidgetCardProps, WidgetProps } from "../../widgets/BaseWidget"; import { WidgetCardProps, WidgetProps } from "../../widgets/BaseWidget";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
const initialState: EditorReduxState = {}; const initialState: EditorReduxState = {
pageWidgetId: "0",
};
const editorReducer = createReducer(initialState, { const editorReducer = createReducer(initialState, {
[ReduxActionTypes.SUCCESS_FETCHING_WIDGET_CARDS]: ( [ReduxActionTypes.SUCCESS_FETCHING_WIDGET_CARDS]: (
state: EditorReduxState, state: EditorReduxState,
action: ReduxAction<LoadWidgetCardsPanePayload>, action: ReduxAction<LoadWidgetCardsPanePayload>,
) => { ) => {
return { ...state.pageWidget, ...action.payload }; return { ...state.layout, ...action.payload };
}, },
[ReduxActionTypes.ADD_PAGE_WIDGET]: ( [ReduxActionTypes.ADD_PAGE_WIDGET]: (state: EditorReduxState) => {
state: EditorReduxState,
action: ReduxAction<{ pageId: string; widget: WidgetProps }>,
) => {
return state; return state;
}, },
[ReduxActionTypes.UPDATE_CANVAS]: ( [ReduxActionTypes.LOAD_CANVAS_WIDGETS]: (
state: EditorReduxState, state: EditorReduxState,
action: ReduxAction<LoadCanvasWidgetsPayload>, action: ReduxAction<LoadCanvasWidgetsPayload>,
) => { ) => {
@ -32,10 +31,11 @@ const editorReducer = createReducer(initialState, {
}); });
export interface EditorReduxState { export interface EditorReduxState {
pageWidget?: ContainerWidgetProps<any>; layout?: ContainerWidgetProps<WidgetProps>;
cards?: { cards?: {
[id: string]: WidgetCardProps[]; [id: string]: WidgetCardProps[];
}; };
pageWidgetId: string;
} }
export default editorReducer; export default editorReducer;

View File

@ -1,11 +1,9 @@
import { combineReducers } from "redux"; import { combineReducers } from "redux";
import canvasReducer from "./canvasReducer";
import widgetCardsPaneReducer from "./widgetCardsPaneReducer"; import widgetCardsPaneReducer from "./widgetCardsPaneReducer";
import editorHeaderReducer from "./editorHeaderReducer"; import editorHeaderReducer from "./editorHeaderReducer";
import editorReducer from "./editorReducer"; import editorReducer from "./editorReducer";
const uiReducer = combineReducers({ const uiReducer = combineReducers({
canvas: canvasReducer,
widgetCardsPane: widgetCardsPaneReducer, widgetCardsPane: widgetCardsPaneReducer,
editorHeader: editorHeaderReducer, editorHeader: editorHeaderReducer,
editor: editorReducer, editor: editorReducer,

View File

@ -3,7 +3,7 @@ import {
ReduxActionTypes, ReduxActionTypes,
ReduxAction, ReduxAction,
} from "../constants/ReduxActionConstants"; } from "../constants/ReduxActionConstants";
import PageApi, { PageResponse, PageRequest } from "../api/PageApi"; import PageApi, { FetchPageResponse, FetchPageRequest } from "../api/PageApi";
import { call, put, takeEvery, select, all } from "redux-saga/effects"; import { call, put, takeEvery, select, all } from "redux-saga/effects";
import { RenderModes } from "../constants/WidgetConstants"; import { RenderModes } from "../constants/WidgetConstants";
import { import {
@ -71,10 +71,12 @@ export function* executeQueryAction(queryAction: QueryActionPayload) {
}); });
} }
export function* executeAction(pageRequestAction: ReduxAction<PageRequest>) { export function* executeAction(
pageRequestAction: ReduxAction<FetchPageRequest>,
) {
const pageRequest = pageRequestAction.payload; const pageRequest = pageRequestAction.payload;
try { try {
const pageResponse: PageResponse = yield call( const pageResponse: FetchPageResponse = yield call(
PageApi.fetchPage, PageApi.fetchPage,
pageRequest, pageRequest,
); );
@ -86,9 +88,10 @@ export function* executeAction(pageRequestAction: ReduxAction<PageRequest>) {
pageWidgetId: normalizedResponse.result, pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets, widgets: normalizedResponse.entities.canvasWidgets,
}; };
yield put({ type: ReduxActionTypes.UPDATE_CANVAS, payload }); yield put({ type: ReduxActionTypes.LOAD_CANVAS_WIDGETS, payload });
} }
} catch (err) { } catch (err) {
console.log(err);
//TODO(abhinav): REFACTOR THIS //TODO(abhinav): REFACTOR THIS
} }
} }

View File

@ -4,11 +4,21 @@ import {
ReduxAction, ReduxAction,
LoadCanvasWidgetsPayload, LoadCanvasWidgetsPayload,
} from "../constants/ReduxActionConstants"; } from "../constants/ReduxActionConstants";
import PageApi, { PageResponse, PageRequest } from "../api/PageApi"; import {
import { call, put, takeEvery, all } from "redux-saga/effects"; loadCanvasWidgets,
savePageError,
savePageSuccess,
} from "../actions/pageActions";
import PageApi, {
FetchPageResponse,
SavePageResponse,
FetchPageRequest,
SavePageRequest,
} from "../api/PageApi";
import { call, put, takeLatest, all } from "redux-saga/effects";
import { RenderModes } from "../constants/WidgetConstants"; import { RenderModes } from "../constants/WidgetConstants";
export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) { export function* fetchPage(pageRequestAction: ReduxAction<FetchPageRequest>) {
const pageRequest = pageRequestAction.payload; const pageRequest = pageRequestAction.payload;
try { try {
// const pageResponse: PageResponse = yield call( // const pageResponse: PageResponse = yield call(
@ -22,12 +32,12 @@ export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) {
"dsl": { "dsl": {
"widgetId": "0", "widgetId": "0",
"type": "CONTAINER_WIDGET", "type": "CONTAINER_WIDGET",
"snapColumns": 1000, "snapColumns": 16,
"snapRows": 1500, "snapRows": 100,
"topRow": 0, "topRow": 0,
"bottomRow": 2, "bottomRow": 2000,
"leftColumn": 0, "leftColumn": 0,
"rightColumn": 2, "rightColumn": 1000,
"parentColumnSpace": 1, "parentColumnSpace": 1,
"parentRowSpace": 1, "parentRowSpace": 1,
"backgroundColor": "#ffffff", "backgroundColor": "#ffffff",
@ -39,9 +49,9 @@ export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) {
"snapColumns": 10, "snapColumns": 10,
"snapRows": 10, "snapRows": 10,
"topRow": 1, "topRow": 1,
"bottomRow": 2, "bottomRow": 20,
"leftColumn": 1, "leftColumn": 1,
"rightColumn": 2, "rightColumn": 16,
"backgroundColor": "#000000", "backgroundColor": "#000000",
"renderMode": "CANVAS", "renderMode": "CANVAS",
"children": [] "children": []
@ -57,19 +67,37 @@ export function* fetchPageSaga(pageRequestAction: ReduxAction<PageRequest>) {
pageWidgetId: normalizedResponse.result, pageWidgetId: normalizedResponse.result,
widgets: normalizedResponse.entities.canvasWidgets, widgets: normalizedResponse.entities.canvasWidgets,
}; };
yield all([
put({ type: ReduxActionTypes.UPDATE_CANVAS, canvasWidgetsPayload }), yield put(loadCanvasWidgets(canvasWidgetsPayload));
put({ yield put({
type: ReduxActionTypes.LOAD_CANVAS_ACTIONS, type: ReduxActionTypes.LOAD_CANVAS_ACTIONS,
payload: pageResponse.layout.actions, payload: pageResponse.layout.actions,
}), });
]);
} }
} catch (err) { } catch (err) {
console.log(err);
//TODO(abhinav): REFACTOR THIS //TODO(abhinav): REFACTOR THIS
} }
} }
export function* watchFetchPage() { export function* savePage(savePageAction: ReduxAction<SavePageRequest>) {
yield takeEvery(ReduxActionTypes.FETCH_PAGE, fetchPageSaga); const savePageRequest = savePageAction.payload;
try {
const savePageResponse: SavePageResponse = yield call(
PageApi.savePage,
savePageRequest,
);
yield put(savePageSuccess(savePageResponse));
} catch (err) {
console.log(err);
yield put(savePageError(err));
}
}
export default function* pageSagas() {
yield all([
takeLatest(ReduxActionTypes.FETCH_PAGE, fetchPage),
takeLatest(ReduxActionTypes.SAVE_PAGE_INIT, savePage),
]);
} }

View File

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

View File

@ -14,6 +14,7 @@ class WidgetFactory {
static createWidget(widgetData: WidgetProps): JSX.Element { static createWidget(widgetData: WidgetProps): JSX.Element {
widgetData.key = widgetData.widgetId; widgetData.key = widgetData.widgetId;
const widgetBuilder = this.widgetMap.get(widgetData.type); const widgetBuilder = this.widgetMap.get(widgetData.type);
if (widgetBuilder) return widgetBuilder.buildWidget(widgetData); if (widgetBuilder) return widgetBuilder.buildWidget(widgetData);
else { else {
const ex: WidgetCreationException = { const ex: WidgetCreationException = {

View File

@ -172,4 +172,13 @@ export interface WidgetCardProps {
icon: string; icon: string;
} }
export const WidgetDynamicProperties = {
POSITION: "POSITION",
SIZE: "SIZE",
CHILDREN: "CHILDREN",
EXISTENCE: "EXISTENCE",
};
export type WidgetDynamicProperty = (typeof WidgetDynamicProperties)[keyof typeof WidgetDynamicProperties];
export default BaseWidget; export default BaseWidget;

View File

@ -96,7 +96,7 @@ export interface ContainerWidgetProps<T extends WidgetProps>
snapRows?: number; snapRows?: number;
orientation?: ContainerOrientation; orientation?: ContainerOrientation;
backgroundColor?: Color; backgroundColor?: Color;
onDrop?: Function; onPropertyChange?: Function;
} }
export default ContainerWidget; export default ContainerWidget;