Merge branch 'dynamic-binding-scaffold' into 'release'

Dynamic binding scaffold

See merge request theappsmith/internal-tools-client!104
This commit is contained in:
Hetu Nandu 2019-11-01 07:11:32 +00:00
commit ecbd6cd067
24 changed files with 194 additions and 166 deletions

View File

@ -0,0 +1,17 @@
import {
ReduxAction,
ReduxActionTypes,
ReduxActionWithoutPayload,
} from "../constants/ReduxActionConstants";
import { NamePathBindingMap } from "../constants/BindingsConstants";
export const createUpdateBindingsMap = (): ReduxActionWithoutPayload => ({
type: ReduxActionTypes.CREATE_UPDATE_BINDINGS_MAP_INIT,
});
export const bindingsMapSuccess = (
map: NamePathBindingMap,
): ReduxAction<NamePathBindingMap> => ({
type: ReduxActionTypes.CREATE_UPDATE_BINDINGS_MAP_SUCCESS,
payload: map,
});

View File

@ -0,0 +1,8 @@
import {
ReduxActionTypes,
ReduxActionWithoutPayload,
} from "../constants/ReduxActionConstants";
export const initAppData = (): ReduxActionWithoutPayload => ({
type: ReduxActionTypes.INIT_APP_DATA,
});

View File

@ -1,5 +1,4 @@
import { FetchPageRequest } from "../api/PageApi";
import { RenderMode } from "../constants/WidgetConstants";
import { WidgetProps, WidgetOperation } from "../widgets/BaseWidget";
import { WidgetType } from "../constants/WidgetConstants";
import {
@ -11,10 +10,11 @@ import {
} from "../constants/ReduxActionConstants";
import { ContainerWidgetProps } from "../widgets/ContainerWidget";
export const fetchPage = (
pageId: string,
renderMode: RenderMode,
): ReduxAction<FetchPageRequest> => {
export const fetchPageList = () => ({
type: ReduxActionTypes.FETCH_PAGE_LIST_INIT,
});
export const fetchPage = (pageId: string): ReduxAction<FetchPageRequest> => {
return {
type: ReduxActionTypes.FETCH_PAGE,
payload: {
@ -93,9 +93,9 @@ export type WidgetMove = {
topRow: number;
parentId: string;
/*
If newParentId is different from what we have in redux store,
If newParentId is different from what we have in redux store,
then we have to delete this,
as it has been dropped in another container somewhere.
as it has been dropped in another container somewhere.
*/
newParentId: string;
};

View File

@ -59,7 +59,7 @@ export interface RestAction {
export interface ExecuteActionRequest extends APIRequest {
actionId: string;
dynamicBindingList?: Property[];
params?: Property[];
}
export interface ExecuteActionResponse extends ApiResponse {

View File

@ -24,16 +24,6 @@ const ResponseMetaInfo = styled.div`
}
`;
const ResponseBodyWrapper = styled.span`
max-height: 100%;
&&& {
textarea,
pre {
height: 100%;
overflow: auto;
}
}
`;
const StatusCodeText = styled(BaseText)<{ code: string }>`
color: ${props =>
props.code.match(/2\d\d/) ? props.theme.colors.primary : "red"};
@ -61,10 +51,10 @@ const LoadingScreen = styled.div`
bottom: 0;
right: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.6);
background-color: rgba(255, 255, 255, 0.6);
pointer-events: none;
z-index: 1;
color: white;
color: black;
display: flex;
align-items: center;
justify-content: center;
@ -138,17 +128,13 @@ const ApiResponseView = (props: Props) => {
key: "body",
title: "Response Body",
panelComponent: (
<ResponseBodyWrapper>
{response.body && (
<CodeEditor
height={500}
language={"json"}
input={{
value: JSON.stringify(response.body, null, 2),
}}
/>
)}
</ResponseBodyWrapper>
<CodeEditor
height={500}
language={"json"}
input={{
value: JSON.stringify(response.body, null, 2),
}}
/>
),
},
{

View File

@ -24,7 +24,6 @@ const CodeEditor = (props: Props) => {
minimap: { enabled: false },
readOnly: !props.input.onChange,
};
debugger;
return (
<Wrapper height={props.height}>
<MonacoEditor

View File

@ -20,6 +20,8 @@ import { required } from "../../utils/validation/common";
import { apiPathValidation } from "../../utils/validation/ApiForm";
const Form = styled.form`
display: flex;
flex-direction: column;
height: calc(100vh - ${props => props.theme.headerHeight});
width: 100%;
${FormLabel} {
@ -40,6 +42,7 @@ const Form = styled.form`
const SecondaryWrapper = styled.div`
display: flex;
height: 100%;
border-top: 1px solid #d0d7dd;
`;

View File

@ -0,0 +1 @@
export type NamePathBindingMap = Record<string, string>;

View File

@ -2,6 +2,7 @@ import { WidgetProps, WidgetCardProps } from "../widgets/BaseWidget";
import { RefObject } from "react";
export const ReduxActionTypes: { [key: string]: string } = {
INIT_APP_DATA: "INIT_APP_DATA",
REPORT_ERROR: "REPORT_ERROR",
FLUSH_ERRORS: "FLUSH_ERRORS",
UPDATE_CANVAS: "UPDATE_CANVAS",
@ -64,11 +65,14 @@ export const ReduxActionTypes: { [key: string]: string } = {
FETCH_PAGE_LIST_INIT: "FETCH_PAGE_LIST_INIT",
FETCH_PAGE_LIST_SUCCESS: "FETCH_PAGE_LIST_SUCCESS",
INITIALIZE_PAGE_VIEWER: "INITIALIZE_PAGE_VIEWER",
CREATE_UPDATE_BINDINGS_MAP_INIT: "CREATE_UPDATE_BINDINGS_MAP_INIT",
CREATE_UPDATE_BINDINGS_MAP_SUCCESS: "CREATE_UPDATE_BINDINGS_MAP_SUCCESS",
};
export type ReduxActionType = (typeof ReduxActionTypes)[keyof typeof ReduxActionTypes];
export const ReduxActionErrorTypes: { [key: string]: string } = {
INIT_APP_DATA_ERROR: "INIT_APP_DATA_ERROR",
API_ERROR: "API_ERROR",
WIDGET_DELETE_ERROR: "WIDGET_DELETE_ERROR",
WIDGET_MOVE_ERROR: "WIDGET_MOVE_ERROR",
@ -101,6 +105,8 @@ export interface ReduxAction<T> {
payload: T;
}
export type ReduxActionWithoutPayload = Pick<ReduxAction<undefined>, "type">;
export interface ReduxActionErrorPayload {
message: string;
source?: string;

View File

@ -13,8 +13,6 @@ import { AppState } from "../../reducers";
import { RouteComponentProps } from "react-router";
import { API_EDITOR_URL } from "../../constants/routes";
import { API_EDITOR_FORM_NAME } from "../../constants/forms";
import { ResourceDataState } from "../../reducers/entityReducers/resourcesReducer";
import { fetchResources } from "../../actions/resourcesActions";
import { FORM_INITIAL_VALUES } from "../../constants/ApiEditorConstants";
import { normalizeApiFormData } from "../../normalizers/ApiFormNormalizer";
import { ActionDataState } from "../../reducers/entityReducers/actionsReducer";
@ -22,7 +20,6 @@ import { ActionDataState } from "../../reducers/entityReducers/actionsReducer";
interface ReduxStateProps {
actions: ActionDataState;
formData: any;
resources: ResourceDataState;
}
interface ReduxActionProps {
submitForm: (name: string) => void;
@ -32,7 +29,6 @@ interface ReduxActionProps {
updateAction: (data: RestAction) => void;
initialize: (formName: string, data?: Partial<RestAction>) => void;
destroy: (formName: string) => void;
fetchResources: () => void;
}
type Props = ReduxActionProps &
@ -41,9 +37,6 @@ type Props = ReduxActionProps &
class ApiEditor extends React.Component<Props> {
componentDidMount(): void {
if (!this.props.resources.list.length) {
this.props.fetchResources();
}
const currentId = this.props.match.params.id;
if (!currentId) return;
if (!this.props.actions.data.length) {
@ -111,7 +104,6 @@ class ApiEditor extends React.Component<Props> {
const mapStateToProps = (state: AppState): ReduxStateProps => ({
actions: state.entities.actions,
formData: getFormValues(API_EDITOR_FORM_NAME)(state),
resources: state.entities.resources,
});
const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
@ -123,7 +115,6 @@ const mapDispatchToProps = (dispatch: any): ReduxActionProps => ({
initialize: (formName: string, data?: Partial<RestAction>) =>
dispatch(initialize(formName, data)),
destroy: (formName: string) => dispatch(destroy(formName)),
fetchResources: () => dispatch(fetchResources()),
});
export default connect(

View File

@ -3,7 +3,6 @@ import { connect } from "react-redux";
import { RouteComponentProps } from "react-router";
import styled from "styled-components";
import { AppState } from "../../reducers";
import { fetchActions } from "../../actions/actionActions";
import { ActionDataState } from "../../reducers/entityReducers/actionsReducer";
import { API_EDITOR_ID_URL, API_EDITOR_URL } from "../../constants/routes";
import { BaseButton } from "../../components/blueprint/ButtonComponent";
@ -86,22 +85,9 @@ interface ReduxStateProps {
actions: ActionDataState;
}
interface ReduxActionProps {
fetchActions: () => void;
selectAction: (id: string) => void;
}
type Props = ReduxStateProps &
ReduxActionProps &
RouteComponentProps<{ id: string }>;
type Props = ReduxStateProps & RouteComponentProps<{ id: string }>;
class ApiSidebar extends React.Component<Props> {
componentDidMount(): void {
if (!this.props.actions.data.length) {
this.props.fetchActions();
}
}
handleCreateNew = () => {
const { history } = this.props;
history.push(API_EDITOR_URL);
@ -147,11 +133,4 @@ const mapStateToProps = (state: AppState): ReduxStateProps => ({
actions: state.entities.actions,
});
const mapDispatchToProps = (dispatch: any) => ({
fetchActions: () => dispatch(fetchActions()),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ApiSidebar);
export default connect(mapStateToProps)(ApiSidebar);

View File

@ -9,6 +9,7 @@ const Wrapper = styled.div`
grid-template-columns: 1fr 4fr;
width: ${props => props.theme.sidebarWidth};
box-shadow: 0px 1px 3px ${props => props.theme.colors.paneBG};
z-index: 20;
`;
const NavBar = styled.div`

View File

@ -11,20 +11,9 @@ import {
} from "../../widgets/BaseWidget";
import { ActionPayload } from "../../constants/ActionConstants";
import { executeAction } from "../../actions/widgetActions";
import { fetchPage, savePage, updateWidget } from "../../actions/pageActions";
import {
getPropertyPaneConfigsId,
getCurrentLayoutId,
getCurrentPageId,
getDenormalizedDSL,
getCurrentPageName,
} from "../../selectors/editorSelectors";
import { RenderModes } from "../../constants/WidgetConstants";
import { savePage, updateWidget } from "../../actions/pageActions";
import { getDenormalizedDSL } from "../../selectors/editorSelectors";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
import {
EditorConfigIdsType,
fetchEditorConfigs,
} from "../../actions/configsActions";
import { ReduxActionTypes } from "../../constants/ReduxActionConstants";
import { updateWidgetProperty } from "../../actions/controlActions";
@ -56,7 +45,6 @@ const CanvasContainer = styled.section`
type EditorProps = {
dsl: ContainerWidgetProps<WidgetProps> | any;
fetchCanvasWidgets: Function;
executeAction: (actionPayloads?: ActionPayload[]) => void;
updateWidget: Function;
updateWidgetProperty: (
@ -65,64 +53,39 @@ type EditorProps = {
propertyValue: any,
) => void;
savePageLayout: Function;
currentPageName: string;
currentPageId: string;
currentLayoutId: string;
showPropertyPane: (
widgetId?: string,
node?: HTMLDivElement,
toggle?: boolean,
) => void;
fetchConfigs: Function;
propertyPaneConfigsId: string;
};
export const WidgetFunctionsContext: Context<WidgetFunctions> = createContext(
{},
);
class WidgetsEditor extends React.Component<EditorProps> {
componentDidMount() {
this.props.fetchConfigs({
propertyPaneConfigsId: this.props.propertyPaneConfigsId,
// widgetCardsPaneId: this.props.widgetCardsPaneId,
// widgetConfigsId: this.props.widgetConfigsId,
});
this.props.fetchCanvasWidgets(this.props.currentPageId);
}
render(): React.ReactNode {
return (
<WidgetFunctionsContext.Provider
value={{
executeAction: this.props.executeAction,
updateWidget: this.props.updateWidget,
updateWidgetProperty: this.props.updateWidgetProperty,
}}
>
<EditorWrapper>
<CanvasContainer>
{this.props.dsl && (
<Canvas
dsl={this.props.dsl}
showPropertyPane={this.props.showPropertyPane}
/>
)}
</CanvasContainer>
<PropertyPane />
</EditorWrapper>
</WidgetFunctionsContext.Provider>
);
}
}
const WidgetsEditor = (props: EditorProps) => (
<WidgetFunctionsContext.Provider
value={{
executeAction: props.executeAction,
updateWidget: props.updateWidget,
updateWidgetProperty: props.updateWidgetProperty,
}}
>
<EditorWrapper>
<CanvasContainer>
{props.dsl && (
<Canvas dsl={props.dsl} showPropertyPane={props.showPropertyPane} />
)}
</CanvasContainer>
<PropertyPane />
</EditorWrapper>
</WidgetFunctionsContext.Provider>
);
const mapStateToProps = (state: AppState) => {
return {
dsl: getDenormalizedDSL(state),
currentPageId: getCurrentPageId(state),
currentLayoutId: getCurrentLayoutId(state),
currentPageName: getCurrentPageName(state),
propertyPaneConfigsId: getPropertyPaneConfigsId(state),
};
};
@ -135,8 +98,6 @@ const mapDispatchToProps = (dispatch: any) => {
) => dispatch(updateWidgetProperty(widgetId, propertyName, propertyValue)),
executeAction: (actionPayloads?: ActionPayload[]) =>
dispatch(executeAction(actionPayloads)),
fetchCanvasWidgets: (pageId: string) =>
dispatch(fetchPage(pageId, RenderModes.CANVAS)),
updateWidget: (
operation: WidgetOperation,
widgetId: string,
@ -147,8 +108,6 @@ const mapDispatchToProps = (dispatch: any) => {
layoutId: string,
dsl: ContainerWidgetProps<WidgetProps>,
) => dispatch(savePage(pageId, layoutId, dsl)),
fetchConfigs: (configsIds: EditorConfigIdsType) =>
dispatch(fetchEditorConfigs(configsIds)),
showPropertyPane: (
widgetId?: string,
node?: HTMLDivElement,

View File

@ -17,6 +17,7 @@ import {
PageListPayload,
} from "../../constants/ReduxActionConstants";
import { Dialog, Classes, AnchorButton } from "@blueprintjs/core";
import { initAppData } from "../../actions/initActions";
type EditorProps = {
currentPageName: string;
@ -26,8 +27,8 @@ type EditorProps = {
currentPageId: string;
publishApplication: Function;
previewPage: Function;
initData: Function;
createPage: Function;
fetchPageList: Function;
pages: PageListPayload;
switchPage: (pageId: string) => void;
isPublishing: boolean;
@ -40,7 +41,7 @@ class Editor extends Component<EditorProps> {
};
componentDidMount() {
this.props.fetchPageList();
this.props.initData();
}
componentDidUpdate(currently: EditorProps) {
const previously = this.props;
@ -123,6 +124,7 @@ const mapStateToProps = (state: AppState) => ({
const mapDispatchToProps = (dispatch: any) => {
return {
initData: () => dispatch(initAppData()),
publishApplication: (applicationId: string) => {
dispatch({
type: ReduxActionTypes.PUBLISH_APPLICATION_INIT,
@ -149,11 +151,6 @@ const mapDispatchToProps = (dispatch: any) => {
},
});
},
fetchPageList: () => {
dispatch({
type: ReduxActionTypes.FETCH_PAGE_LIST_INIT,
});
},
switchPage: (pageId: string) => {
dispatch({
type: ReduxActionTypes.FETCH_PAGE,

View File

@ -4,12 +4,9 @@ import {
ReduxAction,
ReduxActionErrorTypes,
} from "../../constants/ReduxActionConstants";
import _ from "lodash";
import { PageAction } from "../../constants/ActionConstants";
import { RestAction } from "../../api/ActionAPI";
const initialState: ActionDataState = {
list: {},
data: [],
isFetching: false,
isRunning: false,
@ -18,9 +15,6 @@ const initialState: ActionDataState = {
};
export interface ActionDataState {
list: {
[name: string]: PageAction;
};
data: RestAction[];
isFetching: boolean;
isRunning: boolean;
@ -29,15 +23,6 @@ export interface ActionDataState {
}
const actionsReducer = createReducer(initialState, {
[ReduxActionTypes.LOAD_CANVAS_ACTIONS]: (
state: ActionDataState,
action: ReduxAction<PageAction[]>,
) => {
const actionMap = _.mapKeys(action.payload, (action: PageAction) => {
return action.id;
});
return { ...state, list: { ...actionMap } };
},
[ReduxActionTypes.FETCH_ACTIONS_INIT]: (state: ActionDataState) => ({
...state,
isFetching: true,

View File

@ -0,0 +1,19 @@
import { createReducer } from "../../utils/AppsmithUtils";
import {
ReduxActionTypes,
ReduxAction,
} from "../../constants/ReduxActionConstants";
import { NamePathBindingMap } from "../../constants/BindingsConstants";
export type BindingsDataState = NamePathBindingMap;
const initialState: BindingsDataState = {};
const bindingsReducer = createReducer(initialState, {
[ReduxActionTypes.CREATE_UPDATE_BINDINGS_MAP_SUCCESS]: (
state: BindingsDataState,
action: ReduxAction<NamePathBindingMap>,
) => action.payload,
});
export default bindingsReducer;

View File

@ -6,6 +6,7 @@ import widgetConfigReducer from "./widgetConfigReducer";
import actionsReducer from "./actionsReducer";
import propertyPaneConfigReducer from "./propertyPaneConfigReducer";
import resourceReducer from "./resourcesReducer";
import bindingsReducer from "./bindingsReducer";
const entityReducer = combineReducers({
canvasWidgets: canvasWidgetsReducer,
@ -15,5 +16,6 @@ const entityReducer = combineReducers({
actions: actionsReducer,
propertyConfig: propertyPaneConfigReducer,
resources: resourceReducer,
nameBindings: bindingsReducer,
});
export default entityReducer;

View File

@ -14,6 +14,7 @@ import { WidgetConfigReducerState } from "./entityReducers/widgetConfigReducer";
import { WidgetSidebarReduxState } from "./uiReducers/widgetSidebarReducer";
import { ResourceDataState } from "./entityReducers/resourcesReducer";
import { AppViewReduxState } from "./uiReducers/appViewReducer";
import { BindingsDataState } from "./entityReducers/bindingsReducer";
const appReducer = combineReducers({
entities: entityReducer,
@ -39,5 +40,6 @@ export interface AppState {
propertyConfig: PropertyPaneConfigState;
widgetConfig: WidgetConfigReducerState;
resources: ResourceDataState;
nameBindings: BindingsDataState;
};
}

View File

@ -39,36 +39,42 @@ const getDataTree = (state: AppState) => {
return state.entities;
};
const getAction = (state: AppState, actionId: string): PageAction => {
return state.entities.actions.list[actionId];
const getAction = (
state: AppState,
actionId: string,
): RestAction | undefined => {
return _.find(state.entities.actions.data, { id: actionId });
};
export function* evaluateJSONPathSaga(jsonPath: string): any {
const dataTree = yield select(getDataTree);
return JSONPath({ path: jsonPath, json: dataTree });
const splitPath = jsonPath.split(".");
const bindingPath = dataTree.nameBindings[splitPath[0]];
const fullPath = `${bindingPath}.${splitPath.slice(1).join(".")}`;
return JSONPath({ path: fullPath, json: dataTree });
}
export function* executeAPIQueryActionSaga(apiAction: ActionPayload) {
export function* executeAPIQueryActionSaga(apiAction: { actionId: string }) {
const api: PageAction = yield select(getAction, apiAction.actionId);
const executeActionRequest: ExecuteActionRequest = {
actionId: apiAction.actionId,
};
if (!_.isNil(api.jsonPathKeys)) {
const responses: any = yield all(
api.jsonPathKeys.map((jsonPath: string) => {
return call(evaluateJSONPathSaga, jsonPath);
}),
const values: any = _.flatten(
yield all(
api.jsonPathKeys.map((jsonPath: string) => {
return call(evaluateJSONPathSaga, jsonPath);
}),
),
);
const dynamicBindingMap: Record<string, any> = _.keyBy(
responses,
(response: string, index: number) => {
return api.jsonPathKeys ? api.jsonPathKeys[index] : undefined;
},
);
executeActionRequest.dynamicBindingList = mapToPropList(dynamicBindingMap);
const dynamicBindings: Record<string, string> = {};
api.jsonPathKeys.forEach((key, i) => {
dynamicBindings[key] = values[i];
});
executeActionRequest.params = mapToPropList(dynamicBindings);
}
yield ActionAPI.executeAction(executeActionRequest);
return yield ActionAPI.executeAction(executeActionRequest);
}
export function* executeActionSaga(action: ReduxAction<ActionPayload[]>) {
@ -128,10 +134,9 @@ export function* fetchActionSaga(actionPayload: ReduxAction<{ id: string }>) {
export function* runActionSaga(actionPayload: ReduxAction<{ id: string }>) {
const id = actionPayload.payload.id;
const response: ActionApiResponse = yield ActionAPI.executeAction({
const response: ActionApiResponse = yield call(executeAPIQueryActionSaga, {
actionId: id,
});
let payload = response;
if (response.responseMeta && response.responseMeta.error) {
payload = {

View File

@ -0,0 +1,26 @@
import { all, select, takeLatest, put } from "redux-saga/effects";
import { ReduxActionTypes } from "../constants/ReduxActionConstants";
import { AppState } from "../reducers";
import { bindingsMapSuccess } from "../actions/bindingActions";
function* createUpdateBindingsMapData() {
const data: AppState = yield select();
const map: Record<string, string> = {};
data.entities.actions.data.forEach(action => {
map[action.name] = `$.apiData.${action.id}`;
});
Object.keys(data.entities.canvasWidgets).forEach(widgetId => {
const name = data.entities.canvasWidgets[widgetId].widgetName;
map[name] = `$.canvasWidgets.${widgetId}`;
});
yield put(bindingsMapSuccess(map));
}
export default function* watchBindingsSagas() {
yield all([
takeLatest(
ReduxActionTypes.CREATE_UPDATE_BINDINGS_MAP_INIT,
createUpdateBindingsMapData,
),
]);
}

View File

@ -0,0 +1,37 @@
import { all, select, put, takeLatest, take } from "redux-saga/effects";
import { ReduxActionTypes } from "../constants/ReduxActionConstants";
import {
getPropertyPaneConfigsId,
getCurrentPageId,
} from "../selectors/editorSelectors";
import { fetchEditorConfigs } from "../actions/configsActions";
import { fetchPage, fetchPageList } from "../actions/pageActions";
import { fetchActions } from "../actions/actionActions";
import { fetchResources } from "../actions/resourcesActions";
import { createUpdateBindingsMap } from "../actions/bindingActions";
function* fetchAppDataSaga() {
// Step 1: Start getting all the data needed by the app
const propertyPaneConfigsId = yield select(getPropertyPaneConfigsId);
const currentPageId = yield select(getCurrentPageId);
yield all([
put(fetchPageList()),
put(fetchEditorConfigs(propertyPaneConfigsId)),
put(fetchPage(currentPageId)),
put(fetchActions()),
put(fetchResources()),
]);
// Step 2: Wait for all data to be in the state
yield all([
take(ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS),
take(ReduxActionTypes.UPDATE_CANVAS),
take(ReduxActionTypes.FETCH_ACTIONS_SUCCESS),
take(ReduxActionTypes.FETCH_RESOURCES_SUCCESS),
]);
// Step 3: Create the bindings map;
yield put(createUpdateBindingsMap());
}
export default function* watchInitSagas() {
yield all([takeLatest(ReduxActionTypes.INIT_APP_DATA, fetchAppDataSaga)]);
}

View File

@ -7,8 +7,12 @@ import errorSagas from "./ErrorSagas";
import configsSagas from "./ConfigsSagas";
import applicationSagas from "./ApplicationSagas";
import { watchResourcesSagas } from "./ResourcesSagas";
import initSagas from "./InitSagas";
import bindingsSagas from "./BindingsSagas";
export function* rootSaga() {
yield all([
spawn(initSagas),
spawn(pageSagas),
spawn(fetchWidgetCardsSaga),
spawn(watchActionSagas),
@ -17,5 +21,6 @@ export function* rootSaga() {
spawn(configsSagas),
spawn(watchResourcesSagas),
spawn(applicationSagas),
spawn(bindingsSagas),
]);
}

View File

@ -1,2 +1,2 @@
// import * as React from "react";
declare module 'react-base-table';
declare module "react-base-table";