From e0706cf6e34e4d82b7fdad16103661c1f260214b Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Fri, 27 Sep 2019 13:38:31 +0530 Subject: [PATCH 01/19] Change location for save page notification --- app/client/src/constants/ApiConstants.tsx | 2 + .../src/constants/ReduxActionConstants.tsx | 4 +- app/client/src/pages/Editor/EditorHeader.tsx | 70 ++++++++++++------- app/client/src/pages/Editor/WidgetCard.tsx | 3 + app/client/src/pages/Editor/index.tsx | 26 ++----- .../src/reducers/uiReducers/editorReducer.tsx | 1 + app/client/src/sagas/PageSagas.tsx | 4 +- 7 files changed, 64 insertions(+), 46 deletions(-) diff --git a/app/client/src/constants/ApiConstants.tsx b/app/client/src/constants/ApiConstants.tsx index 88220ac5de..0492351902 100644 --- a/app/client/src/constants/ApiConstants.tsx +++ b/app/client/src/constants/ApiConstants.tsx @@ -35,11 +35,13 @@ export const getEditorConfigs = () => { return { currentPageId: "5d807e7f795dc6000482bc78", currentLayoutId: "5d807e7f795dc6000482bc77", + currentPageName: "page1", }; } else { return { currentPageId: "5d807e76795dc6000482bc76", currentLayoutId: "5d807e76795dc6000482bc75", + currentPageName: "page1", }; } }; diff --git a/app/client/src/constants/ReduxActionConstants.tsx b/app/client/src/constants/ReduxActionConstants.tsx index 712e8bd27d..5c84564080 100644 --- a/app/client/src/constants/ReduxActionConstants.tsx +++ b/app/client/src/constants/ReduxActionConstants.tsx @@ -48,7 +48,9 @@ export interface ReduxAction { export interface UpdateCanvasPayload { pageWidgetId: string; widgets: { [widgetId: string]: WidgetProps }; - layoutId: string; + currentLayoutId: string; + currentPageId: string; + currentPageName: string; } export interface ShowPropertyPanePayload { diff --git a/app/client/src/pages/Editor/EditorHeader.tsx b/app/client/src/pages/Editor/EditorHeader.tsx index ed47517185..bb3a96a1a5 100644 --- a/app/client/src/pages/Editor/EditorHeader.tsx +++ b/app/client/src/pages/Editor/EditorHeader.tsx @@ -1,35 +1,57 @@ -import React, { Component } from "react"; +import React from "react"; import styled from "styled-components"; -// import { connect } from "react-redux"; -// import { AppState } from "../../reducers"; -// import { EditorHeaderReduxState } from "../../reducers/uiReducers/editorHeaderReducer"; +import { Breadcrumbs, IBreadcrumbProps, Spinner } from "@blueprintjs/core"; const Header = styled.header` + display: flex; + justify-content: space-around; + align-items: center; height: 50px; + padding: 0px 30px; box-shadow: 0px 0px 3px #ccc; background: #fff; + font-size: ${props => props.theme.fontSizes[1]}px; `; -class EditorHeader extends Component { - render() { - return
; +const NotificationText = styled.div` + display: flex; + justify-content: space-evenly; + align-items: center; + flex-grow: 1; +`; + +const StretchedBreadCrumb = styled(Breadcrumbs)` + flex-grow: 10; + * { + font-family: ${props => props.theme.fonts[0]}; + font-size: ${props => props.theme.fontSizes[2]}px; } -} + li:after { + background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.71 7.29l-4-4a1.003 1.003 0 0 0-1.42 1.42L8.59 8 5.3 11.29c-.19.18-.3.43-.3.71a1.003 1.003 0 0 0 1.71.71l4-4c.18-.18.29-.43.29-.71 0-.28-.11-.53-.29-.71z' fill='rgba(92,112,128,1)'/%3E%3C/svg%3E"); + } +`; + +type EditorHeaderProps = { + notificationText?: string; + pageName: string; +}; + +export const EditorHeader = (props: EditorHeaderProps) => { + const navigation: IBreadcrumbProps[] = [ + { href: "#", icon: "folder-close", text: "appsmith-dev" }, + { href: "#", icon: "folder-close", text: "application" }, + { icon: "page-layout", text: props.pageName, current: true }, + ]; + + return ( +
+ + + {props.notificationText && } + {props.notificationText} + +
+ ); +}; export default EditorHeader; - -// const mapStateToProps = ( -// state: AppState, -// props: any, -// ): EditorHeaderReduxState => { -// return state; -// }; - -// const mapDispatchToProps = (dispatch: any) => { -// return {}; -// }; - -// export default connect( -// mapStateToProps, -// mapDispatchToProps, -// )(EditorHeader); diff --git a/app/client/src/pages/Editor/WidgetCard.tsx b/app/client/src/pages/Editor/WidgetCard.tsx index 4ef4f75858..ee1b8a6dec 100644 --- a/app/client/src/pages/Editor/WidgetCard.tsx +++ b/app/client/src/pages/Editor/WidgetCard.tsx @@ -29,6 +29,9 @@ export const Wrapper = styled.div` path { fill: ${props => props.theme.colors.textDefault}; } + rect { + stroke: ${props => props.theme.colors.textDefault}; + } } } & i { diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index 68390dbf71..6d3aef5d49 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -1,5 +1,4 @@ import React, { Component } from "react"; -import { Position, Toaster } from "@blueprintjs/core"; import { connect } from "react-redux"; import styled from "styled-components"; import Canvas from "./Canvas"; @@ -20,10 +19,6 @@ import { executeAction } from "../../actions/widgetActions"; import { ActionPayload } from "../../constants/ActionConstants"; import PropertyPane from "./PropertyPane"; -const SaveToast = Toaster.create({ - position: Position.TOP, -}); - const CanvasContainer = styled.section` height: 100%; width: 100%; @@ -60,7 +55,7 @@ type EditorProps = { updateWidget: Function; cards: { [id: string]: WidgetCardProps[] } | any; savePageLayout: Function; - page: string; + currentPageName: string; currentPageId: string; currentLayoutId: string; isSaving: boolean; @@ -71,23 +66,13 @@ class Editor extends Component { this.props.fetchCanvasWidgets(this.props.currentPageId); } - componentDidUpdate(prevProps: EditorProps) { - if (this.props.isSaving && prevProps.isSaving !== this.props.isSaving) { - SaveToast.clear(); - SaveToast.show({ message: "Saving Page..." }); - } else if ( - !this.props.isSaving && - prevProps.isSaving !== this.props.isSaving - ) { - SaveToast.clear(); - SaveToast.show({ message: "Page Saved" }); - } - } - public render() { return ( - + @@ -136,6 +121,7 @@ const mapStateToProps = (state: AppState): EditorReduxState => { pageWidgetId: state.ui.editor.pageWidgetId, currentPageId: state.ui.editor.currentPageId, currentLayoutId: state.ui.editor.currentLayoutId, + currentPageName: state.ui.editor.currentPageName, isSaving: state.ui.editor.isSaving, }; }; diff --git a/app/client/src/reducers/uiReducers/editorReducer.tsx b/app/client/src/reducers/uiReducers/editorReducer.tsx index 693a4d24c7..7948d4410d 100644 --- a/app/client/src/reducers/uiReducers/editorReducer.tsx +++ b/app/client/src/reducers/uiReducers/editorReducer.tsx @@ -40,6 +40,7 @@ export interface EditorReduxState { pageWidgetId: string; currentPageId: string; currentLayoutId: string; + currentPageName: string; isSaving: boolean; } diff --git a/app/client/src/sagas/PageSagas.tsx b/app/client/src/sagas/PageSagas.tsx index 8c1a440852..efba4974db 100644 --- a/app/client/src/sagas/PageSagas.tsx +++ b/app/client/src/sagas/PageSagas.tsx @@ -44,8 +44,10 @@ export function* fetchPageSaga( ); const canvasWidgetsPayload: UpdateCanvasPayload = { pageWidgetId: normalizedResponse.result, + currentPageName: fetchPageResponse.data.name, + currentPageId: fetchPageResponse.data.id, widgets: normalizedResponse.entities.canvasWidgets, - layoutId: fetchPageResponse.data.layouts[0].id, // TODO(abhinav): Handle for multiple layouts + currentLayoutId: fetchPageResponse.data.layouts[0].id, // TODO(abhinav): Handle for multiple layouts }; yield all([ put(updateCanvas(canvasWidgetsPayload)), From 062540e838ba314d03b891e916559a5e4bc1d118 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Fri, 27 Sep 2019 21:35:33 +0530 Subject: [PATCH 02/19] Add global Saga to handle errors --- app/client/src/actions/pageActions.tsx | 16 -- .../src/actions/widgetCardsPaneActions.tsx | 9 +- app/client/src/api/PageApi.tsx | 2 +- app/client/src/constants/ApiConstants.tsx | 2 - .../src/constants/ReduxActionConstants.tsx | 28 ++- .../mockResponses/WidgetCardsPaneResponse.tsx | 188 +++++++++--------- app/client/src/pages/Editor/index.tsx | 5 +- app/client/src/reducers/index.tsx | 4 +- .../uiReducers/editorHeaderReducer.tsx | 9 - .../src/reducers/uiReducers/editorReducer.tsx | 10 +- .../src/reducers/uiReducers/errorReducer.tsx | 32 +++ app/client/src/reducers/uiReducers/index.tsx | 6 +- .../uiReducers/widgetCardsPaneReducer.tsx | 27 --- app/client/src/sagas/ErrorSagas.tsx | 38 ++++ app/client/src/sagas/PageSagas.tsx | 40 ++-- app/client/src/sagas/WidgetCardsPaneSagas.tsx | 8 +- app/client/src/sagas/index.tsx | 2 + app/client/src/utils/AppsmithSagaHelper.tsx | 27 +++ 18 files changed, 263 insertions(+), 190 deletions(-) delete mode 100644 app/client/src/reducers/uiReducers/editorHeaderReducer.tsx create mode 100644 app/client/src/reducers/uiReducers/errorReducer.tsx delete mode 100644 app/client/src/reducers/uiReducers/widgetCardsPaneReducer.tsx create mode 100644 app/client/src/sagas/ErrorSagas.tsx create mode 100644 app/client/src/utils/AppsmithSagaHelper.tsx diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index 32004458ca..ae0bfbf849 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -1,5 +1,4 @@ import { FetchPageRequest } from "../api/PageApi"; -import { ResponseMeta } from "../api/ApiResponses"; import { RenderMode } from "../constants/WidgetConstants"; import { WidgetProps, WidgetOperation } from "../widgets/BaseWidget"; import { WidgetType } from "../constants/WidgetConstants"; @@ -8,7 +7,6 @@ import { ReduxAction, UpdateCanvasPayload, SavePagePayload, - SavePageErrorPayload, SavePageSuccessPayload, } from "../constants/ReduxActionConstants"; import { ContainerWidgetProps } from "../widgets/ContainerWidget"; @@ -26,13 +24,6 @@ export const fetchPage = ( }; }; -export const fetchPageError = (payload: ResponseMeta) => { - return { - type: ReduxActionTypes.FETCH_PAGE_ERROR, - payload, - }; -}; - export const addWidget = ( pageId: string, widget: WidgetProps, @@ -86,13 +77,6 @@ export const savePageSuccess = (payload: SavePageSuccessPayload) => { }; }; -export const savePageError = (payload: SavePageErrorPayload) => { - return { - type: ReduxActionTypes.SAVE_PAGE_ERROR, - payload, - }; -}; - export type WidgetAddChild = { widgetId: string; type: WidgetType; diff --git a/app/client/src/actions/widgetCardsPaneActions.tsx b/app/client/src/actions/widgetCardsPaneActions.tsx index ae393a5e0c..a3782ea18d 100644 --- a/app/client/src/actions/widgetCardsPaneActions.tsx +++ b/app/client/src/actions/widgetCardsPaneActions.tsx @@ -1,4 +1,7 @@ -import { ReduxActionTypes } from "../constants/ReduxActionConstants"; +import { + ReduxActionTypes, + ReduxActionErrorTypes, +} from "../constants/ReduxActionConstants"; import { WidgetCardProps } from "../widgets/BaseWidget"; export const fetchWidgetCards = () => { @@ -9,7 +12,7 @@ export const fetchWidgetCards = () => { export const errorFetchingWidgetCards = (error: any) => { return { - type: ReduxActionTypes.ERROR_FETCHING_WIDGET_CARDS, + type: ReduxActionErrorTypes.FETCH_WIDGET_CARDS_ERROR, error, }; }; @@ -18,7 +21,7 @@ export const successFetchingWidgetCards = (cards: { [id: string]: WidgetCardProps[]; }) => { return { - type: ReduxActionTypes.SUCCESS_FETCHING_WIDGET_CARDS, + type: ReduxActionTypes.FETCH_WIDGET_CARDS_SUCCESS, cards, }; }; diff --git a/app/client/src/api/PageApi.tsx b/app/client/src/api/PageApi.tsx index 9814ae976d..d501fd82de 100644 --- a/app/client/src/api/PageApi.tsx +++ b/app/client/src/api/PageApi.tsx @@ -31,7 +31,7 @@ export type FetchPageResponse = ApiResponse & { }; }; -export interface SavePageResponse { +export interface SavePageResponse extends ApiResponse { pageId: string; } diff --git a/app/client/src/constants/ApiConstants.tsx b/app/client/src/constants/ApiConstants.tsx index 0492351902..594ffea494 100644 --- a/app/client/src/constants/ApiConstants.tsx +++ b/app/client/src/constants/ApiConstants.tsx @@ -45,5 +45,3 @@ export const getEditorConfigs = () => { }; } }; - -console.log("here", process.env.NODE_ENV); diff --git a/app/client/src/constants/ReduxActionConstants.tsx b/app/client/src/constants/ReduxActionConstants.tsx index 5c84564080..6cecce4af4 100644 --- a/app/client/src/constants/ReduxActionConstants.tsx +++ b/app/client/src/constants/ReduxActionConstants.tsx @@ -1,6 +1,8 @@ import { WidgetProps, WidgetCardProps } from "../widgets/BaseWidget"; export const ReduxActionTypes: { [key: string]: string } = { + REPORT_ERROR: "REPORT_ERROR", + FLUSH_ERRORS: "FLUSH_ERRORS", UPDATE_CANVAS: "UPDATE_CANVAS", FETCH_CANVAS: "FETCH_CANVAS", CLEAR_CANVAS: "CLEAR_CANVAS", @@ -16,8 +18,7 @@ export const ReduxActionTypes: { [key: string]: string } = { LOAD_PROPERTY_CONFIG: "LOAD_PROPERTY_CONFIG", PUBLISH: "PUBLISH", FETCH_WIDGET_CARDS: "FETCH_WIDGET_CARDS", - SUCCESS_FETCHING_WIDGET_CARDS: "SUCCESS_FETCHING_WIDGET_CARDS", - ERROR_FETCHING_WIDGET_CARDS: "ERROR_FETCHING_WIDGET_CARDS", + FETCH_WIDGET_CARDS_SUCCESS: "FETCH_WIDGET_CARDS_SUCCESS", ADD_PAGE_WIDGET: "ADD_PAGE_WIDGET", REMOVE_PAGE_WIDGET: "REMOVE_PAGE_WIDGET", LOAD_API_RESPONSE: "LOAD_API_RESPONSE", @@ -26,8 +27,6 @@ export const ReduxActionTypes: { [key: string]: string } = { LOAD_CANVAS_ACTIONS: "LOAD_CANVAS_ACTIONS", SAVE_PAGE_INIT: "SAVE_PAGE_INIT", SAVE_PAGE_SUCCESS: "SAVE_PAGE_SUCCESS", - SAVE_PAGE_ERROR: "SAVE_PAGE_ERROR", - FETCH_PAGE_ERROR: "FETCH_PAGE_ERROR", UPDATE_LAYOUT: "UPDATE_LAYOUT", WIDGET_ADD_CHILD: "WIDGET_ADD_CHILD", WIDGET_REMOVE_CHILD: "WIDGET_REMOVE_CHILD", @@ -37,14 +36,31 @@ export const ReduxActionTypes: { [key: string]: string } = { SHOW_PROPERTY_PANE: "SHOW_PROPERTY_PANE", UPDATE_WIDGET_PROPERTY: "UPDATE_WIDGET_PROPERTY", }; - export type ReduxActionType = (typeof ReduxActionTypes)[keyof typeof ReduxActionTypes]; +export const ReduxActionErrorTypes: { [key: string]: string } = { + API_ERROR: "API_ERROR", + WIDGET_DELETE_ERROR: "WIDGET_DELETE_ERROR", + WIDGET_MOVE_ERROR: "WIDGET_MOVE_ERROR", + WIDGET_RESIZE_ERROR: "WIDGET_RESIZE_ERROR", + WIDGET_REMOVE_CHILD_ERROR: "WIDGET_REMOVE_CHILD_ERROR", + WIDGET_ADD_CHILD_ERROR: "WIDGET_ADD_CHILD_ERROR", + FETCH_PAGE_ERROR: "FETCH_PAGE_ERROR", + SAVE_PAGE_ERROR: "SAVE_PAGE_ERROR", + FETCH_WIDGET_CARDS_ERROR: "FETCH_WIDGET_CARDS_ERROR", +}; +export type ReduxActionErrorType = (typeof ReduxActionErrorTypes)[keyof typeof ReduxActionErrorTypes]; + export interface ReduxAction { - type: ReduxActionType; + type: ReduxActionType | ReduxActionErrorType; payload: T; } +export interface ReduxActionErrorPayload { + message: string; + source?: string; +} + export interface UpdateCanvasPayload { pageWidgetId: string; widgets: { [widgetId: string]: WidgetProps }; diff --git a/app/client/src/mockResponses/WidgetCardsPaneResponse.tsx b/app/client/src/mockResponses/WidgetCardsPaneResponse.tsx index bfd64b112d..eb7239fdad 100644 --- a/app/client/src/mockResponses/WidgetCardsPaneResponse.tsx +++ b/app/client/src/mockResponses/WidgetCardsPaneResponse.tsx @@ -1,99 +1,99 @@ -import { WidgetCardsPaneReduxState } from "../reducers/uiReducers/widgetCardsPaneReducer"; +import { WidgetCardProps } from "../widgets/BaseWidget"; import { generateReactKey } from "../utils/generators"; -const WidgetCardsPaneResponse: WidgetCardsPaneReduxState = { - cards: { - common: [ - { - type: "TEXT_WIDGET", - icon: "icon-text", - widgetCardName: "Text", - key: generateReactKey(), - }, - { - type: "BUTTON_WIDGET", - icon: "icon-button", - widgetCardName: "Button", - key: generateReactKey(), - }, - { - type: "SPINNER_WIDGET", - icon: "icon-switch", - widgetCardName: "Spinner", - key: generateReactKey(), - }, - { - type: "CONTAINER_WIDGET", - icon: "icon-container", - widgetCardName: "Container", - key: generateReactKey(), - }, - ], - form: [ - { - type: "BUTTON_WIDGET", - icon: "icon-button", - widgetCardName: "Button", - key: generateReactKey(), - }, - { - type: "BUTTON_WIDGET", - icon: "icon-button", - widgetCardName: "Button", - key: generateReactKey(), - }, - { - type: "DROP_DOWN_WIDGET", - icon: "icon-dropdown", - widgetCardName: "Dropdown", - key: generateReactKey(), - }, - { - type: "DATE_PICKER_WIDGET", - icon: "icon-datepicker", - widgetCardName: "DatePicker", - key: generateReactKey(), - }, - { - type: "RADIO_GROUP_WIDGET", - icon: "icon-radio", - widgetCardName: "Radio Button", - key: generateReactKey(), - }, - { - type: "SWITCH_WIDGET", - icon: "icon-switch", - widgetCardName: "Toggle", - key: generateReactKey(), - }, - ], - view: [ - { - type: "TEXT_WIDGET", - icon: "icon-text", - widgetCardName: "Text", - key: generateReactKey(), - }, - { - type: "CONTAINER_WIDGET", - icon: "icon-container", - widgetCardName: "Container", - key: generateReactKey(), - }, - { - type: "SPINNER_WIDGET", - icon: "icon-spinner", - widgetCardName: "Spinner", - key: generateReactKey(), - }, - { - type: "TABLE_WIDGET", - icon: "icon-table", - widgetCardName: "Table", - key: generateReactKey(), - }, - ], - }, +const WidgetCardsPaneResponse: { + [id: string]: WidgetCardProps[]; +} = { + common: [ + { + type: "TEXT_WIDGET", + icon: "icon-text", + widgetCardName: "Text", + key: generateReactKey(), + }, + { + type: "BUTTON_WIDGET", + icon: "icon-button", + widgetCardName: "Button", + key: generateReactKey(), + }, + { + type: "SPINNER_WIDGET", + icon: "icon-switch", + widgetCardName: "Spinner", + key: generateReactKey(), + }, + { + type: "CONTAINER_WIDGET", + icon: "icon-container", + widgetCardName: "Container", + key: generateReactKey(), + }, + ], + form: [ + { + type: "BUTTON_WIDGET", + icon: "icon-button", + widgetCardName: "Button", + key: generateReactKey(), + }, + { + type: "BUTTON_WIDGET", + icon: "icon-button", + widgetCardName: "Button", + key: generateReactKey(), + }, + { + type: "DROP_DOWN_WIDGET", + icon: "icon-dropdown", + widgetCardName: "Dropdown", + key: generateReactKey(), + }, + { + type: "DATE_PICKER_WIDGET", + icon: "icon-datepicker", + widgetCardName: "DatePicker", + key: generateReactKey(), + }, + { + type: "RADIO_GROUP_WIDGET", + icon: "icon-radio", + widgetCardName: "Radio Button", + key: generateReactKey(), + }, + { + type: "SWITCH_WIDGET", + icon: "icon-switch", + widgetCardName: "Toggle", + key: generateReactKey(), + }, + ], + view: [ + { + type: "TEXT_WIDGET", + icon: "icon-text", + widgetCardName: "Text", + key: generateReactKey(), + }, + { + type: "CONTAINER_WIDGET", + icon: "icon-container", + widgetCardName: "Container", + key: generateReactKey(), + }, + { + type: "SPINNER_WIDGET", + icon: "icon-spinner", + widgetCardName: "Spinner", + key: generateReactKey(), + }, + { + type: "TABLE_WIDGET", + icon: "icon-table", + widgetCardName: "Table", + key: generateReactKey(), + }, + ], }; export default WidgetCardsPaneResponse; diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index 6d3aef5d49..fc55ebcace 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -107,8 +107,9 @@ const mapStateToProps = (state: AppState): EditorReduxState => { ); const configs = state.entities.widgetConfig.config; - const cards = state.ui.widgetCardsPane.cards; - Object.keys(cards).forEach((group: string) => { + const cards = state.ui.editor.cards; + const groups: string[] = Object.keys(cards); + groups.forEach((group: string) => { cards[group] = cards[group].map((widget: WidgetCardProps) => ({ ...widget, ...configs[widget.type], diff --git a/app/client/src/reducers/index.tsx b/app/client/src/reducers/index.tsx index 4483e76eca..0b703388e1 100644 --- a/app/client/src/reducers/index.tsx +++ b/app/client/src/reducers/index.tsx @@ -2,8 +2,8 @@ import { combineReducers } from "redux"; import entityReducer from "./entityReducers"; import uiReducer from "./uiReducers"; import { CanvasWidgetsReduxState } from "./entityReducers/canvasWidgetsReducer"; -import { WidgetCardsPaneReduxState } from "./uiReducers/widgetCardsPaneReducer"; import { EditorReduxState } from "./uiReducers/editorReducer"; +import { ErrorReduxState } from "./uiReducers/errorReducer"; import { APIDataState } from "./entityReducers/apiDataReducer"; import { QueryDataState } from "./entityReducers/queryDataReducer"; import { ActionDataState } from "./entityReducers/actionsReducer"; @@ -20,9 +20,9 @@ export default appReducer; export interface AppState { ui: { - widgetCardsPane: WidgetCardsPaneReduxState; editor: EditorReduxState; propertyPane: PropertyPaneReduxState; + errors: ErrorReduxState; }; entities: { canvasWidgets: CanvasWidgetsReduxState; diff --git a/app/client/src/reducers/uiReducers/editorHeaderReducer.tsx b/app/client/src/reducers/uiReducers/editorHeaderReducer.tsx deleted file mode 100644 index 76896fb8cf..0000000000 --- a/app/client/src/reducers/uiReducers/editorHeaderReducer.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createReducer } from "../../utils/AppsmithUtils"; - -const initialState = {}; - -const editorHeaderReducer = createReducer(initialState, {}); - -// export interface EditorHeaderReduxState {} - -export default editorHeaderReducer; diff --git a/app/client/src/reducers/uiReducers/editorReducer.tsx b/app/client/src/reducers/uiReducers/editorReducer.tsx index 7948d4410d..952d322032 100644 --- a/app/client/src/reducers/uiReducers/editorReducer.tsx +++ b/app/client/src/reducers/uiReducers/editorReducer.tsx @@ -7,15 +7,18 @@ import { } from "../../constants/ReduxActionConstants"; import { WidgetCardProps, WidgetProps } from "../../widgets/BaseWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; +import WidgetCardsPaneResponse from "../../mockResponses/WidgetCardsPaneResponse"; + const editorConfigs = getEditorConfigs(); const initialState: EditorReduxState = { pageWidgetId: "0", ...editorConfigs, isSaving: false, + cards: WidgetCardsPaneResponse, }; const editorReducer = createReducer(initialState, { - [ReduxActionTypes.SUCCESS_FETCHING_WIDGET_CARDS]: ( + [ReduxActionTypes.FETCH_WIDGET_CARDS_SUCCESS]: ( state: EditorReduxState, action: ReduxAction, ) => { @@ -27,14 +30,11 @@ const editorReducer = createReducer(initialState, { [ReduxActionTypes.SAVE_PAGE_SUCCESS]: (state: EditorReduxState) => { return { ...state, isSaving: false }; }, - [ReduxActionTypes.SAVE_PAGE_ERROR]: (state: EditorReduxState) => { - return { ...state, isSaving: false }; - }, }); export interface EditorReduxState { dsl?: ContainerWidgetProps; - cards?: { + cards: { [id: string]: WidgetCardProps[]; }; pageWidgetId: string; diff --git a/app/client/src/reducers/uiReducers/errorReducer.tsx b/app/client/src/reducers/uiReducers/errorReducer.tsx new file mode 100644 index 0000000000..f715a3637e --- /dev/null +++ b/app/client/src/reducers/uiReducers/errorReducer.tsx @@ -0,0 +1,32 @@ +import { createReducer } from "../../utils/AppsmithUtils"; +import { + ReduxAction, + ReduxActionTypes, + ReduxActionErrorPayload, +} from "../../constants/ReduxActionConstants"; + +const initialState: ErrorReduxState = { sourceAction: "", message: "" }; + +const errorReducer = createReducer(initialState, { + [ReduxActionTypes.REPORT_ERROR]: ( + state: ErrorReduxState, + action: ReduxAction, + ) => { + console.log(action.payload); + return { + sourceAction: action.payload.source, + message: action.payload.message, + }; + }, + [ReduxActionTypes.FLUSH_ERRORS]: () => { + return {}; + }, +}); + +export interface ErrorReduxState { + // Expiration? + sourceAction?: string; + message?: string; +} + +export default errorReducer; diff --git a/app/client/src/reducers/uiReducers/index.tsx b/app/client/src/reducers/uiReducers/index.tsx index d8312d0961..73b606e0f0 100644 --- a/app/client/src/reducers/uiReducers/index.tsx +++ b/app/client/src/reducers/uiReducers/index.tsx @@ -1,13 +1,11 @@ import { combineReducers } from "redux"; -import widgetCardsPaneReducer from "./widgetCardsPaneReducer"; -import editorHeaderReducer from "./editorHeaderReducer"; import editorReducer from "./editorReducer"; +import errorReducer from "./errorReducer"; import propertyPaneReducer from "./propertyPaneReducer"; const uiReducer = combineReducers({ - widgetCardsPane: widgetCardsPaneReducer, - editorHeader: editorHeaderReducer, editor: editorReducer, + errors: errorReducer, propertyPane: propertyPaneReducer, }); export default uiReducer; diff --git a/app/client/src/reducers/uiReducers/widgetCardsPaneReducer.tsx b/app/client/src/reducers/uiReducers/widgetCardsPaneReducer.tsx deleted file mode 100644 index 42dd6c5b9e..0000000000 --- a/app/client/src/reducers/uiReducers/widgetCardsPaneReducer.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { createReducer } from "../../utils/AppsmithUtils"; -import { - ReduxActionTypes, - ReduxAction, - LoadWidgetCardsPanePayload, -} from "../../constants/ReduxActionConstants"; -import { WidgetCardProps } from "../../widgets/BaseWidget"; -import WidgetCardsPaneResponse from "../../mockResponses/WidgetCardsPaneResponse"; - -const initialState: WidgetCardsPaneReduxState = WidgetCardsPaneResponse; - -const widgetCardsPaneReducer = createReducer(initialState, { - [ReduxActionTypes.ERROR_FETCHING_WIDGET_CARDS]: ( - state: WidgetCardsPaneReduxState, - action: ReduxAction, - ) => { - return { cards: action.payload.cards }; - }, -}); - -export interface WidgetCardsPaneReduxState { - cards: { - [id: string]: WidgetCardProps[]; - }; -} - -export default widgetCardsPaneReducer; diff --git a/app/client/src/sagas/ErrorSagas.tsx b/app/client/src/sagas/ErrorSagas.tsx new file mode 100644 index 0000000000..6e3ba93c51 --- /dev/null +++ b/app/client/src/sagas/ErrorSagas.tsx @@ -0,0 +1,38 @@ +import { + ReduxActionTypes, + ReduxActionErrorTypes, + ReduxAction, +} from "../constants/ReduxActionConstants"; + +import { ApiResponse } from "../api/ApiResponses"; +import { put, takeLatest } from "redux-saga/effects"; + +export function* validateResponse(response: ApiResponse) { + if (response.responseMeta.success) { + return true; + } else { + yield put({ + type: ReduxActionErrorTypes.API_ERROR, + payload: { + error: response.responseMeta.error, + }, + }); + return false; + } +} + +export function* errorSaga(errorAction: ReduxAction<{ error: any }>) { + // Just a pass through for now. + // Add procedures to customize errors here + yield put({ + type: ReduxActionTypes.REPORT_ERROR, + payload: { + message: errorAction.payload.error, + source: errorAction.type, + }, + }); +} + +export default function* errorSagas() { + yield takeLatest(Object.values(ReduxActionErrorTypes), errorSaga); +} diff --git a/app/client/src/sagas/PageSagas.tsx b/app/client/src/sagas/PageSagas.tsx index efba4974db..e63ef3918f 100644 --- a/app/client/src/sagas/PageSagas.tsx +++ b/app/client/src/sagas/PageSagas.tsx @@ -1,15 +1,11 @@ import CanvasWidgetsNormalizer from "../normalizers/CanvasWidgetsNormalizer"; import { ReduxActionTypes, + ReduxActionErrorTypes, ReduxAction, UpdateCanvasPayload, } from "../constants/ReduxActionConstants"; -import { - updateCanvas, - savePageError, - savePageSuccess, - fetchPageError, -} from "../actions/pageActions"; +import { updateCanvas, savePageSuccess } from "../actions/pageActions"; import PageApi, { FetchPageResponse, SavePageResponse, @@ -25,20 +21,22 @@ import { takeEvery, all, } from "redux-saga/effects"; + import { extractCurrentDSL } from "../utils/WidgetPropsUtils"; import { getEditorConfigs } from "./selectors"; +import { validateResponse } from "./ErrorSagas"; export function* fetchPageSaga( pageRequestAction: ReduxAction, ) { - const pageRequest = pageRequestAction.payload; try { + const pageRequest = pageRequestAction.payload; const fetchPageResponse: FetchPageResponse = yield call( PageApi.fetchPage, pageRequest, ); - - if (fetchPageResponse.responseMeta.success) { + const isValidResponse = yield validateResponse(fetchPageResponse); + if (isValidResponse) { const normalizedResponse = CanvasWidgetsNormalizer.normalize( extractCurrentDSL(fetchPageResponse), ); @@ -58,8 +56,12 @@ export function* fetchPageSaga( ]); } } catch (error) { - console.log(error); - yield put(fetchPageError(error)); + yield put({ + type: ReduxActionErrorTypes.FETCH_PAGE_ERROR, + payload: { + error, + }, + }); } } @@ -70,10 +72,17 @@ export function* savePageSaga(savePageAction: ReduxAction) { PageApi.savePage, savePageRequest, ); - yield put(savePageSuccess(savePageResponse)); - } catch (err) { - console.log(err); - yield put(savePageError(err)); + const isValidResponse = validateResponse(savePageResponse); + if (isValidResponse) { + yield put(savePageSuccess(savePageResponse)); + } + } catch (error) { + yield put({ + type: ReduxActionErrorTypes.SAVE_PAGE_ERROR, + payload: { + error, + }, + }); } } @@ -89,7 +98,6 @@ export function* saveLayoutSaga( { canvasWidgets: widgets }, ); const editorConfigs = yield select(getEditorConfigs) as any; - console.log(editorConfigs); yield put({ type: ReduxActionTypes.SAVE_PAGE_INIT, payload: { diff --git a/app/client/src/sagas/WidgetCardsPaneSagas.tsx b/app/client/src/sagas/WidgetCardsPaneSagas.tsx index d6cf112b1a..4d4a1b7f42 100644 --- a/app/client/src/sagas/WidgetCardsPaneSagas.tsx +++ b/app/client/src/sagas/WidgetCardsPaneSagas.tsx @@ -1,5 +1,7 @@ -// import CanvasWidgetsNormalizer from "../normalizers/CanvasWidgetsNormalizer" -import { ReduxActionTypes } from "../constants/ReduxActionConstants"; +import { + ReduxActionTypes, + ReduxActionErrorTypes, +} from "../constants/ReduxActionConstants"; import WidgetCardsPaneApi, { WidgetCardsPaneResponse, } from "../api/WidgetCardsPaneApi"; @@ -13,7 +15,7 @@ export function* fetchWidgetCards() { ]); yield put(successFetchingWidgetCards(widgetCards.cards)); } catch (err) { - yield put({ type: ReduxActionTypes.ERROR_FETCHING_WIDGET_CARDS, err }); + yield put({ type: ReduxActionErrorTypes.FETCH_WIDGET_CARDS_ERROR, err }); } } diff --git a/app/client/src/sagas/index.tsx b/app/client/src/sagas/index.tsx index 5ab51c8cd7..52593510e2 100644 --- a/app/client/src/sagas/index.tsx +++ b/app/client/src/sagas/index.tsx @@ -3,6 +3,7 @@ import pageSagas from "../sagas/PageSagas"; import { fetchWidgetCardsSaga } from "./WidgetCardsPaneSagas"; import { watchExecuteActionSaga } from "./ActionSagas"; import widgetOperationSagas from "./WidgetOperationSagas"; +import errorSagas from "./ErrorSagas"; export function* rootSaga() { yield all([ @@ -10,5 +11,6 @@ export function* rootSaga() { spawn(fetchWidgetCardsSaga), spawn(watchExecuteActionSaga), spawn(widgetOperationSagas), + spawn(errorSagas), ]); } diff --git a/app/client/src/utils/AppsmithSagaHelper.tsx b/app/client/src/utils/AppsmithSagaHelper.tsx new file mode 100644 index 0000000000..c9e819329b --- /dev/null +++ b/app/client/src/utils/AppsmithSagaHelper.tsx @@ -0,0 +1,27 @@ +import { + call as ReduxSagaCall, + select as ReduxSagaSelect, + put as ReduxSagaPut, + takeLatest as ReduxSagaTakeLatest, + takeEvery as ReduxSagaTakeEvery, + all as ReduxSagaAll, +} from "redux-saga/effects"; + +function* safe(effect: any) { + try { + return yield effect; + } catch (error) { + console.log(error); + } +} + +export const call = (fn: any, ...args: unknown[]) => + safe(ReduxSagaCall(fn, ...args)); +export const select = (state: any, ...args: any[]) => + safe(ReduxSagaSelect(state, ...args)); +export const put = (action: any) => safe(ReduxSagaPut(action)); +export const takeLatest = (pattern: any, worker: any) => + safe(ReduxSagaTakeLatest(pattern, worker)); +export const takeEvery = (pattern: any, worker: any) => + safe(ReduxSagaTakeEvery(pattern, worker)); +export const all = (args: unknown[]) => safe(ReduxSagaAll(args)); From 6c942abe2bb0375645f4ad7ca89aba27d862925b Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Mon, 30 Sep 2019 08:55:14 +0530 Subject: [PATCH 03/19] Remove dependencies from Readme.md. Fix #36, #37 --- app/client/README.md | 7 --- app/client/src/constants/WidgetConstants.tsx | 1 + .../editorComponents/DraggableComponent.tsx | 12 ++++- .../editorComponents/ResizableComponent.tsx | 8 +++- .../src/reducers/uiReducers/errorReducer.tsx | 1 - app/client/src/utils/helpers.tsx | 12 ----- app/client/src/widgets/BaseWidget.tsx | 26 ++++++----- app/client/src/widgets/ContainerWidget.tsx | 45 ++++++++++--------- 8 files changed, 56 insertions(+), 56 deletions(-) diff --git a/app/client/README.md b/app/client/README.md index c533c7c2ef..d20687e8ed 100755 --- a/app/client/README.md +++ b/app/client/README.md @@ -1,10 +1,3 @@ -## GIT Commit Hooks - -This project has scripts to ESLint fix and Prettier write the code on the git commit hook. -It is recommended to install ESLint and Prettier global for successful git commits - -`yarn global add eslint` -`yarn global add prettier` This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). diff --git a/app/client/src/constants/WidgetConstants.tsx b/app/client/src/constants/WidgetConstants.tsx index be21d05f84..05278c8c24 100644 --- a/app/client/src/constants/WidgetConstants.tsx +++ b/app/client/src/constants/WidgetConstants.tsx @@ -71,4 +71,5 @@ export const GridDefaults = { DEFAULT_WIDGET_HEIGHT: 100, DEFAULT_GRID_COLUMNS: 16, DEFAULT_GRID_ROWS: 32, + DEFAULT_GRID_ROW_HEIGHT: 40, }; diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index 1c634b5e6e..27e3986196 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -6,17 +6,25 @@ import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "../assets/images/blank.png"; import { ContainerProps } from "./ContainerComponent"; +const DraggableWrapper = styled.div` + &:hover > div { + display: block; + } +`; + const DragHandle = styled.div` position: absolute; left: ${props => props.theme.spaces[2]}px; top: -${props => props.theme.spaces[8]}px; cursor: move; + display: none; `; const DeleteControl = styled.div` position: absolute; right: ${props => props.theme.spaces[2]}px; top: -${props => props.theme.spaces[8]}px; + display: none; `; type DraggableComponentProps = WidgetProps & ContainerProps; @@ -35,7 +43,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { return ( -
{ {props.children} -
+
); }; diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 5d3bdd5d5b..59b6404d49 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -13,7 +13,13 @@ const ResizableContainer = styled(Resizable)` }}; `; -const CustomHandle = (props: any) =>
; +const DisplayHandleWrapper = styled.div` + display: none; + ${ResizableContainer}:hover & { + display: block; + } +`; +const CustomHandle = (props: any) => ; const BottomRightHandle = () => ( diff --git a/app/client/src/reducers/uiReducers/errorReducer.tsx b/app/client/src/reducers/uiReducers/errorReducer.tsx index f715a3637e..3cb81b3473 100644 --- a/app/client/src/reducers/uiReducers/errorReducer.tsx +++ b/app/client/src/reducers/uiReducers/errorReducer.tsx @@ -12,7 +12,6 @@ const errorReducer = createReducer(initialState, { state: ErrorReduxState, action: ReduxAction, ) => { - console.log(action.payload); return { sourceAction: action.payload.source, message: action.payload.message, diff --git a/app/client/src/utils/helpers.tsx b/app/client/src/utils/helpers.tsx index 9b0937a97b..885e5dcf00 100644 --- a/app/client/src/utils/helpers.tsx +++ b/app/client/src/utils/helpers.tsx @@ -8,15 +8,3 @@ export const snapToGrid = ( const snappedY = Math.floor(y / rowHeight); return [snappedX, snappedY]; }; - -export const getRowColSizes = ( - rowCount: number, - columnCount: number, - width: number, - height: number, -): { rowHeight: number; columnWidth: number } => { - return { - columnWidth: width / columnCount, - rowHeight: height / rowCount, - }; -}; diff --git a/app/client/src/widgets/BaseWidget.tsx b/app/client/src/widgets/BaseWidget.tsx index c0f3c33476..e7e9cd47b4 100644 --- a/app/client/src/widgets/BaseWidget.tsx +++ b/app/client/src/widgets/BaseWidget.tsx @@ -94,17 +94,21 @@ abstract class BaseWidget< getCanvasView(): JSX.Element { const style = this.getPositionStyle(); - return ( - - - {this.getPageView()} - - - ); + if (!this.props.parentId) { + return this.getPageView(); + } else { + return ( + + + {this.getPageView()} + + + ); + } } abstract getWidgetType(): WidgetType; diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index f19db96f12..97bd563f9d 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -14,7 +14,7 @@ import { GridDefaults } from "../constants/WidgetConstants"; import DraggableComponent from "../editorComponents/DraggableComponent"; import ResizableComponent from "../editorComponents/ResizableComponent"; -const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROWS } = GridDefaults; +const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROW_HEIGHT } = GridDefaults; class ContainerWidget extends BaseWidget< ContainerWidgetProps, @@ -34,21 +34,14 @@ class ContainerWidget extends BaseWidget< componentDidUpdate(previousProps: ContainerWidgetProps) { super.componentDidUpdate(previousProps); let snapColumnSpace = this.state.snapColumnSpace; - let snapRowSpace = this.state.snapRowSpace; if (this.state.componentWidth) snapColumnSpace = this.state.componentWidth / (this.props.snapColumns || DEFAULT_GRID_COLUMNS); - if (this.state.componentHeight) - snapRowSpace = - this.state.componentHeight / (this.props.snapRows || DEFAULT_GRID_ROWS); - if ( - this.state.snapColumnSpace !== snapColumnSpace || - this.state.snapRowSpace !== snapRowSpace - ) { + if (this.state.snapColumnSpace !== snapColumnSpace) { this.setState({ snapColumnSpace, - snapRowSpace, + snapRowSpace: DEFAULT_GRID_ROW_HEIGHT, }); } } @@ -79,9 +72,8 @@ class ContainerWidget extends BaseWidget< ); } - getCanvasView() { - const style = this.getPositionStyle(); - const occupiedSpaces: OccupiedSpace[] | null = this.props.children + getOccupiedSpaces(): OccupiedSpace[] | null { + return this.props.children ? this.props.children.map(child => ({ id: child.widgetId, left: child.leftColumn, @@ -90,6 +82,23 @@ class ContainerWidget extends BaseWidget< right: child.rightColumn, })) : null; + } + getCanvasView() { + const style = this.getPositionStyle(); + const occupiedSpaces = this.getOccupiedSpaces(); + + const renderDraggableComponent = ( + + + {this.getPageView()} + + + ); + return ( - - - {this.getPageView()} - - + {this.props.parentId ? renderDraggableComponent : this.getPageView()} ); } From e23643e5e8260497c74cfe63b400a4d34a92de0e Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Tue, 1 Oct 2019 01:34:03 +0530 Subject: [PATCH 04/19] WIP: Canvas Fixes: Adhere to Figma Styles --- .../src/assets/icons/control/delete.svg | 4 +++ app/client/src/assets/icons/control/move.svg | 4 +++ .../src/editorComponents/ButtonComponent.tsx | 2 +- .../editorComponents/ContainerComponent.tsx | 1 + .../editorComponents/DragLayerComponent.tsx | 2 +- .../editorComponents/DraggableComponent.tsx | 31 +++++++++++++------ app/client/src/editorComponents/Dropzone.tsx | 2 +- app/client/src/icons/ControlIcons.tsx | 21 +++++++++++++ app/client/src/pages/Editor/index.tsx | 2 +- 9 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 app/client/src/assets/icons/control/delete.svg create mode 100644 app/client/src/assets/icons/control/move.svg create mode 100644 app/client/src/icons/ControlIcons.tsx diff --git a/app/client/src/assets/icons/control/delete.svg b/app/client/src/assets/icons/control/delete.svg new file mode 100644 index 0000000000..09b3855266 --- /dev/null +++ b/app/client/src/assets/icons/control/delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/client/src/assets/icons/control/move.svg b/app/client/src/assets/icons/control/move.svg new file mode 100644 index 0000000000..3cd36f1c26 --- /dev/null +++ b/app/client/src/assets/icons/control/move.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/client/src/editorComponents/ButtonComponent.tsx b/app/client/src/editorComponents/ButtonComponent.tsx index 2fb5efa485..da9669b6c9 100644 --- a/app/client/src/editorComponents/ButtonComponent.tsx +++ b/app/client/src/editorComponents/ButtonComponent.tsx @@ -1,4 +1,4 @@ -import * as React from "react"; +import React from "react"; import { Button, MaybeElement } from "@blueprintjs/core"; import { TextComponentProps } from "./TextComponent"; import { Container } from "./ContainerComponent"; diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index 10826cc822..c9e9b04808 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -13,6 +13,7 @@ export const Container = styled("div")` position: ${props => { return props.style.positionType === "ABSOLUTE" ? "absolute" : "relative"; }}; + align-items: stretch; `; const ContainerComponent = (props: ContainerProps) => { diff --git a/app/client/src/editorComponents/DragLayerComponent.tsx b/app/client/src/editorComponents/DragLayerComponent.tsx index a84dd0e23a..b3b7b8f6b8 100644 --- a/app/client/src/editorComponents/DragLayerComponent.tsx +++ b/app/client/src/editorComponents/DragLayerComponent.tsx @@ -8,7 +8,7 @@ import { OccupiedSpace } from "../widgets/ContainerWidget"; const WrappedDragLayer = styled.div` position: absolute; pointer-events: none; - z-index: 100; + z-index: 10; left: 0; top: 0; width: 100%; diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index 27e3986196..59c7eb1af0 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -1,10 +1,11 @@ import React from "react"; -import { Icon } from "@blueprintjs/core"; import styled from "styled-components"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "../assets/images/blank.png"; import { ContainerProps } from "./ContainerComponent"; +import { ControlIcons } from "../icons/ControlIcons"; +import { theme } from "../constants/DefaultTheme"; const DraggableWrapper = styled.div` &:hover > div { @@ -14,19 +15,33 @@ const DraggableWrapper = styled.div` const DragHandle = styled.div` position: absolute; - left: ${props => props.theme.spaces[2]}px; - top: -${props => props.theme.spaces[8]}px; + left: -${props => props.theme.spaces[4]}px; + top: -${props => props.theme.spaces[4]}px; cursor: move; display: none; + cursor: pointer; + z-index: 11; `; const DeleteControl = styled.div` position: absolute; - right: ${props => props.theme.spaces[2]}px; - top: -${props => props.theme.spaces[8]}px; + right: -${props => props.theme.spaces[4]}px; + top: -${props => props.theme.spaces[4]}px; display: none; + cursor: pointer; + z-index: 11; `; +const moveControlIcon = ControlIcons.MOVE_CONTROL({ + width: theme.fontSizes[6], + height: theme.fontSizes[6], +}); + +const deleteControlIcon = ControlIcons.DELETE_CONTROL({ + width: theme.fontSizes[6], + height: theme.fontSizes[6], +}); + type DraggableComponentProps = WidgetProps & ContainerProps; const DraggableComponent = (props: DraggableComponentProps) => { @@ -57,11 +72,9 @@ const DraggableComponent = (props: DraggableComponentProps) => { : 0, }} > - - - + {moveControlIcon} - + {deleteControlIcon} {props.children} diff --git a/app/client/src/editorComponents/Dropzone.tsx b/app/client/src/editorComponents/Dropzone.tsx index c52da957ac..5d17ac892b 100644 --- a/app/client/src/editorComponents/Dropzone.tsx +++ b/app/client/src/editorComponents/Dropzone.tsx @@ -5,7 +5,7 @@ import { snapToGrid } from "../utils/helpers"; const DropZoneWrapper = styled.div` position: absolute; - z-index: 100; + z-index: 10; background: ${props => props.theme.colors.hover}; border: 1px dashed ${props => props.theme.colors.textAnchor}; opacity: 0.7; diff --git a/app/client/src/icons/ControlIcons.tsx b/app/client/src/icons/ControlIcons.tsx new file mode 100644 index 0000000000..b69acedcd5 --- /dev/null +++ b/app/client/src/icons/ControlIcons.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { IconProps, IconWrapper } from "../constants/IconConstants"; +import { ReactComponent as DeleteIcon } from "../assets/icons/control/delete.svg"; +import { ReactComponent as MoveIcon } from "../assets/icons/control/move.svg"; + +/* eslint-disable react/display-name */ + +export const ControlIcons: { + [id: string]: Function; +} = { + DELETE_CONTROL: (props: IconProps) => ( + + + + ), + MOVE_CONTROL: (props: IconProps) => ( + + + + ), +}; diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index fc55ebcace..9c0a334015 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -32,7 +32,7 @@ const CanvasContainer = styled.section` right: 0; bottom: 0; left: 0; - z-index: 1000; + z-index: 11; pointer-events: none; } `; From e8c72f5a0671f50205c0bddc7db8d7914284cbf8 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Tue, 1 Oct 2019 01:36:11 +0530 Subject: [PATCH 05/19] WIP: Canvas Fixes: Adhere to Figma styles. Add Control Icons --- app/client/src/assets/icons/control/address.svg | 3 +++ app/client/src/assets/icons/control/bold.svg | 3 +++ app/client/src/assets/icons/control/center-align.svg | 3 +++ app/client/src/assets/icons/control/chevron-down.svg | 3 +++ app/client/src/assets/icons/control/copy.svg | 4 ++++ app/client/src/assets/icons/control/currency.svg | 3 +++ app/client/src/assets/icons/control/datepicker.svg | 3 +++ app/client/src/assets/icons/control/decimal.svg | 3 +++ app/client/src/assets/icons/control/email.svg | 3 +++ app/client/src/assets/icons/control/info.svg | 3 +++ app/client/src/assets/icons/control/input.svg | 4 ++++ app/client/src/assets/icons/control/integer.svg | 3 +++ app/client/src/assets/icons/control/italics.svg | 3 +++ app/client/src/assets/icons/control/left-align.svg | 3 +++ app/client/src/assets/icons/control/multiline.svg | 8 ++++++++ app/client/src/assets/icons/control/password.svg | 9 +++++++++ app/client/src/assets/icons/control/phone.svg | 3 +++ app/client/src/assets/icons/control/redo.svg | 3 +++ app/client/src/assets/icons/control/right-align.svg | 3 +++ app/client/src/assets/icons/control/search.svg | 3 +++ app/client/src/assets/icons/control/underline.svg | 3 +++ app/client/src/assets/icons/control/undo.svg | 3 +++ app/client/src/assets/icons/control/zoomin.svg | 3 +++ app/client/src/assets/icons/control/zoomout.svg | 3 +++ 24 files changed, 85 insertions(+) create mode 100644 app/client/src/assets/icons/control/address.svg create mode 100644 app/client/src/assets/icons/control/bold.svg create mode 100644 app/client/src/assets/icons/control/center-align.svg create mode 100644 app/client/src/assets/icons/control/chevron-down.svg create mode 100644 app/client/src/assets/icons/control/copy.svg create mode 100644 app/client/src/assets/icons/control/currency.svg create mode 100644 app/client/src/assets/icons/control/datepicker.svg create mode 100644 app/client/src/assets/icons/control/decimal.svg create mode 100644 app/client/src/assets/icons/control/email.svg create mode 100644 app/client/src/assets/icons/control/info.svg create mode 100644 app/client/src/assets/icons/control/input.svg create mode 100644 app/client/src/assets/icons/control/integer.svg create mode 100644 app/client/src/assets/icons/control/italics.svg create mode 100644 app/client/src/assets/icons/control/left-align.svg create mode 100644 app/client/src/assets/icons/control/multiline.svg create mode 100644 app/client/src/assets/icons/control/password.svg create mode 100644 app/client/src/assets/icons/control/phone.svg create mode 100644 app/client/src/assets/icons/control/redo.svg create mode 100644 app/client/src/assets/icons/control/right-align.svg create mode 100644 app/client/src/assets/icons/control/search.svg create mode 100644 app/client/src/assets/icons/control/underline.svg create mode 100644 app/client/src/assets/icons/control/undo.svg create mode 100644 app/client/src/assets/icons/control/zoomin.svg create mode 100644 app/client/src/assets/icons/control/zoomout.svg diff --git a/app/client/src/assets/icons/control/address.svg b/app/client/src/assets/icons/control/address.svg new file mode 100644 index 0000000000..21acef28d8 --- /dev/null +++ b/app/client/src/assets/icons/control/address.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/bold.svg b/app/client/src/assets/icons/control/bold.svg new file mode 100644 index 0000000000..f3e136da0f --- /dev/null +++ b/app/client/src/assets/icons/control/bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/center-align.svg b/app/client/src/assets/icons/control/center-align.svg new file mode 100644 index 0000000000..34e6f1a462 --- /dev/null +++ b/app/client/src/assets/icons/control/center-align.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/chevron-down.svg b/app/client/src/assets/icons/control/chevron-down.svg new file mode 100644 index 0000000000..783082577d --- /dev/null +++ b/app/client/src/assets/icons/control/chevron-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/copy.svg b/app/client/src/assets/icons/control/copy.svg new file mode 100644 index 0000000000..3affe770d7 --- /dev/null +++ b/app/client/src/assets/icons/control/copy.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/client/src/assets/icons/control/currency.svg b/app/client/src/assets/icons/control/currency.svg new file mode 100644 index 0000000000..2115953d27 --- /dev/null +++ b/app/client/src/assets/icons/control/currency.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/datepicker.svg b/app/client/src/assets/icons/control/datepicker.svg new file mode 100644 index 0000000000..959f2763c8 --- /dev/null +++ b/app/client/src/assets/icons/control/datepicker.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/decimal.svg b/app/client/src/assets/icons/control/decimal.svg new file mode 100644 index 0000000000..a6adb8fcb5 --- /dev/null +++ b/app/client/src/assets/icons/control/decimal.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/email.svg b/app/client/src/assets/icons/control/email.svg new file mode 100644 index 0000000000..16d7748e2e --- /dev/null +++ b/app/client/src/assets/icons/control/email.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/info.svg b/app/client/src/assets/icons/control/info.svg new file mode 100644 index 0000000000..300bcd9a06 --- /dev/null +++ b/app/client/src/assets/icons/control/info.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/input.svg b/app/client/src/assets/icons/control/input.svg new file mode 100644 index 0000000000..aeac1584b3 --- /dev/null +++ b/app/client/src/assets/icons/control/input.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/client/src/assets/icons/control/integer.svg b/app/client/src/assets/icons/control/integer.svg new file mode 100644 index 0000000000..cd3e6a56c7 --- /dev/null +++ b/app/client/src/assets/icons/control/integer.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/italics.svg b/app/client/src/assets/icons/control/italics.svg new file mode 100644 index 0000000000..7ae3bbba66 --- /dev/null +++ b/app/client/src/assets/icons/control/italics.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/left-align.svg b/app/client/src/assets/icons/control/left-align.svg new file mode 100644 index 0000000000..94eb13e628 --- /dev/null +++ b/app/client/src/assets/icons/control/left-align.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/multiline.svg b/app/client/src/assets/icons/control/multiline.svg new file mode 100644 index 0000000000..220bfad216 --- /dev/null +++ b/app/client/src/assets/icons/control/multiline.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/client/src/assets/icons/control/password.svg b/app/client/src/assets/icons/control/password.svg new file mode 100644 index 0000000000..ad542c6f95 --- /dev/null +++ b/app/client/src/assets/icons/control/password.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/client/src/assets/icons/control/phone.svg b/app/client/src/assets/icons/control/phone.svg new file mode 100644 index 0000000000..33fc877272 --- /dev/null +++ b/app/client/src/assets/icons/control/phone.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/redo.svg b/app/client/src/assets/icons/control/redo.svg new file mode 100644 index 0000000000..71bfe8be4e --- /dev/null +++ b/app/client/src/assets/icons/control/redo.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/right-align.svg b/app/client/src/assets/icons/control/right-align.svg new file mode 100644 index 0000000000..967eb8d1fb --- /dev/null +++ b/app/client/src/assets/icons/control/right-align.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/search.svg b/app/client/src/assets/icons/control/search.svg new file mode 100644 index 0000000000..3aa4f00565 --- /dev/null +++ b/app/client/src/assets/icons/control/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/underline.svg b/app/client/src/assets/icons/control/underline.svg new file mode 100644 index 0000000000..12a393304a --- /dev/null +++ b/app/client/src/assets/icons/control/underline.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/undo.svg b/app/client/src/assets/icons/control/undo.svg new file mode 100644 index 0000000000..2ec8e0fb7c --- /dev/null +++ b/app/client/src/assets/icons/control/undo.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/zoomin.svg b/app/client/src/assets/icons/control/zoomin.svg new file mode 100644 index 0000000000..baa27c369d --- /dev/null +++ b/app/client/src/assets/icons/control/zoomin.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/client/src/assets/icons/control/zoomout.svg b/app/client/src/assets/icons/control/zoomout.svg new file mode 100644 index 0000000000..aceffa4ff6 --- /dev/null +++ b/app/client/src/assets/icons/control/zoomout.svg @@ -0,0 +1,3 @@ + + + From fc2676487bc89bdf840669c9051c5952baa763d0 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Wed, 2 Oct 2019 01:37:43 +0530 Subject: [PATCH 06/19] Stop resize bleeding. Change resize handle styles. Change grid styles. Fix container size. Change grid dot color. Change grid dot offset. Show drag/resize handles on hover and focus. --- app/client/src/constants/Colors.tsx | 1 + app/client/src/constants/DefaultTheme.tsx | 9 ++-- .../editorComponents/ContainerComponent.tsx | 42 +++++++++++++++-- .../editorComponents/DraggableComponent.tsx | 26 ++++++++--- .../src/editorComponents/DropTargetMask.tsx | 3 +- .../editorComponents/ResizableComponent.tsx | 46 +++++++++++-------- app/client/src/utils/AppsmithSagaHelper.tsx | 27 ----------- app/client/src/widgets/BaseWidget.tsx | 8 +--- app/client/src/widgets/ContainerWidget.tsx | 1 + 9 files changed, 96 insertions(+), 67 deletions(-) delete mode 100644 app/client/src/utils/AppsmithSagaHelper.tsx diff --git a/app/client/src/constants/Colors.tsx b/app/client/src/constants/Colors.tsx index 7a4e702fdd..60fd21b8c1 100644 --- a/app/client/src/constants/Colors.tsx +++ b/app/client/src/constants/Colors.tsx @@ -17,6 +17,7 @@ export const Colors: Record = { RED: "#CE4257", PURPLE: "#6871EF", OXFORD_BLUE: "#2E3D49", + FRENCH_PASS: "#BBE8FE", }; export type Color = (typeof Colors)[keyof typeof Colors]; diff --git a/app/client/src/constants/DefaultTheme.tsx b/app/client/src/constants/DefaultTheme.tsx index adf796fe59..62e02cfdb7 100644 --- a/app/client/src/constants/DefaultTheme.tsx +++ b/app/client/src/constants/DefaultTheme.tsx @@ -38,15 +38,16 @@ export const theme: Theme = { border: Colors.GEYSER, paneCard: Colors.SHARK, paneBG: Colors.OUTER_SPACE, - grid: Colors.POLAR, + grid: Colors.GEYSER, + containerBorder: Colors.FRENCH_PASS, }, lineHeights: [0, 14, 18, 22, 24, 28, 36, 48, 64, 80], fonts: [FontFamilies.DMSans, FontFamilies.AppsmithWidget], borders: [ { - thickness: "2px", - style: "dashed", - color: Colors.POLAR, + thickness: "1px", + style: "solid", + color: Colors.FRENCH_PASS, }, ], }; diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index c9e9b04808..eb6a53b842 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -1,7 +1,14 @@ import { ComponentProps } from "./BaseComponent"; import { ContainerOrientation } from "../constants/WidgetConstants"; import styled from "../constants/DefaultTheme"; -import React from "react"; +import React, { + createContext, + useState, + Dispatch, + SetStateAction, + Context, + useRef, +} from "react"; export const Container = styled("div")` display: flex; @@ -13,16 +20,45 @@ export const Container = styled("div")` position: ${props => { return props.style.positionType === "ABSOLUTE" ? "absolute" : "relative"; }}; - align-items: stretch; + height: 100%; + left: 0; + top: 0; + width: 100%; `; +export const FocusContext: Context<{ + isFocused?: string; + setFocus?: Dispatch>; +}> = createContext({}); + +export const ParentBoundsContext: Context<{ + boundingParent?: React.RefObject; +}> = createContext({}); + const ContainerComponent = (props: ContainerProps) => { - return {props.children}; + const [isFocused, setFocus] = useState(""); + const container = useRef(null); + const ContainerWithoutFocusContextProvider = ( + + + {props.children} + + + ); + const ContainerWithFocusContextProvider = ( + + {ContainerWithoutFocusContextProvider} + + ); + return props.isRoot + ? ContainerWithFocusContextProvider + : ContainerWithoutFocusContextProvider; }; export interface ContainerProps extends ComponentProps { children?: JSX.Element[] | JSX.Element; orientation?: ContainerOrientation; + isRoot?: boolean; } export default ContainerComponent; diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index 59c7eb1af0..f72d01fb96 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -1,13 +1,16 @@ -import React from "react"; +import React, { useContext } from "react"; import styled from "styled-components"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "../assets/images/blank.png"; -import { ContainerProps } from "./ContainerComponent"; +import { ContainerProps, FocusContext } from "./ContainerComponent"; import { ControlIcons } from "../icons/ControlIcons"; import { theme } from "../constants/DefaultTheme"; -const DraggableWrapper = styled.div` +const DraggableWrapper = styled.div<{ show: boolean }>` + & > div.control { + display: ${props => (props.show ? "block" : "none")}; + } &:hover > div { display: block; } @@ -19,7 +22,7 @@ const DragHandle = styled.div` top: -${props => props.theme.spaces[4]}px; cursor: move; display: none; - cursor: pointer; + cursor: grab; z-index: 11; `; @@ -45,6 +48,7 @@ const deleteControlIcon = ControlIcons.DELETE_CONTROL({ type DraggableComponentProps = WidgetProps & ContainerProps; const DraggableComponent = (props: DraggableComponentProps) => { + const { isFocused, setFocus } = useContext(FocusContext); const deleteWidget = () => { props.updateWidget && props.updateWidget(WidgetOperations.DELETE, props.widgetId); @@ -55,11 +59,19 @@ const DraggableComponent = (props: DraggableComponentProps) => { isDragging: monitor.isDragging(), }), }); + return ( { + if (setFocus) { + setFocus(props.widgetId); + e.stopPropagation(); + } + }} + show={props.widgetId === isFocused} style={{ display: isDragging ? "none" : "flex", flexDirection: "column", @@ -72,8 +84,10 @@ const DraggableComponent = (props: DraggableComponentProps) => { : 0, }} > - {moveControlIcon} - + + {moveControlIcon} + + {deleteControlIcon} {props.children} diff --git a/app/client/src/editorComponents/DropTargetMask.tsx b/app/client/src/editorComponents/DropTargetMask.tsx index dba29bf90e..47eeb53203 100644 --- a/app/client/src/editorComponents/DropTargetMask.tsx +++ b/app/client/src/editorComponents/DropTargetMask.tsx @@ -22,7 +22,8 @@ export const DropTargetMaskWrapper = styled.div` transparent 0 ); background-size: ${props => props.columnWidth}px ${props => props.rowHeight}px; - background-position: -50% -50%; + background-position: -${props => props.columnWidth / 2}px -${props => + props.rowHeight / 2}px; `; /* eslint-disable react/display-name */ export const DropTargetMask = (props: DropTargetMaskProps) => { diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 59b6404d49..d24eea983f 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -1,32 +1,40 @@ -import React from "react"; +import React, { useContext } from "react"; import styled from "styled-components"; -import { Icon } from "@blueprintjs/core"; import { Resizable, ResizeDirection } from "re-resizable"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; -import { ContainerProps } from "./ContainerComponent"; +import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; export type ResizableComponentProps = WidgetProps & ContainerProps; const ResizableContainer = styled(Resizable)` + position: relative; + z-index: 10; border: ${props => { return Object.values(props.theme.borders[0]).join(" "); }}; -`; + &:after, + &:before { + content: ""; + position: absolute; + width: 8px; + height: 8px; + border-radius: 50%; + z-index: 9; + background: ${props => props.theme.colors.containerBorder}; + } + &:after { + right: -4px; + top: 50%; + } -const DisplayHandleWrapper = styled.div` - display: none; - ${ResizableContainer}:hover & { - display: block; + &:before { + left: calc(50%); + top: calc(100% - 4px); } `; -const CustomHandle = (props: any) => ; -const BottomRightHandle = () => ( - - - -); export const ResizableComponent = (props: ResizableComponentProps) => { + const { boundingParent } = useContext(ParentBoundsContext); const updateSize = ( e: Event, dir: ResizeDirection, @@ -43,18 +51,18 @@ export const ResizableComponent = (props: ResizableComponentProps) => { height: props.style.componentHeight as number, }} style={{ ...props.style }} - handleComponent={{ bottomRight: }} onResizeStop={updateSize} grid={[props.parentColumnSpace, props.parentRowSpace]} + bounds={boundingParent ? boundingParent.current || undefined : "window"} enable={{ - top: true, + top: false, right: true, bottom: true, - left: true, + left: false, topRight: false, topLeft: false, - bottomRight: true, - bottomLeft: true, + bottomRight: false, + bottomLeft: false, }} > {props.children} diff --git a/app/client/src/utils/AppsmithSagaHelper.tsx b/app/client/src/utils/AppsmithSagaHelper.tsx deleted file mode 100644 index c9e819329b..0000000000 --- a/app/client/src/utils/AppsmithSagaHelper.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - call as ReduxSagaCall, - select as ReduxSagaSelect, - put as ReduxSagaPut, - takeLatest as ReduxSagaTakeLatest, - takeEvery as ReduxSagaTakeEvery, - all as ReduxSagaAll, -} from "redux-saga/effects"; - -function* safe(effect: any) { - try { - return yield effect; - } catch (error) { - console.log(error); - } -} - -export const call = (fn: any, ...args: unknown[]) => - safe(ReduxSagaCall(fn, ...args)); -export const select = (state: any, ...args: any[]) => - safe(ReduxSagaSelect(state, ...args)); -export const put = (action: any) => safe(ReduxSagaPut(action)); -export const takeLatest = (pattern: any, worker: any) => - safe(ReduxSagaTakeLatest(pattern, worker)); -export const takeEvery = (pattern: any, worker: any) => - safe(ReduxSagaTakeEvery(pattern, worker)); -export const all = (args: unknown[]) => safe(ReduxSagaAll(args)); diff --git a/app/client/src/widgets/BaseWidget.tsx b/app/client/src/widgets/BaseWidget.tsx index e7e9cd47b4..7ca2745541 100644 --- a/app/client/src/widgets/BaseWidget.tsx +++ b/app/client/src/widgets/BaseWidget.tsx @@ -115,7 +115,7 @@ abstract class BaseWidget< getPositionStyle(): BaseStyle { return { - positionType: "CONTAINER_DIRECTION", + positionType: "ABSOLUTE", componentHeight: this.state.componentHeight, componentWidth: this.state.componentWidth, yPosition: this.props.topRow * this.props.parentRowSpace, @@ -138,12 +138,6 @@ export interface WidgetState { componentWidth: number; } -export interface DraggableWidget { - type: string; - widget: WidgetProps; - key: string; -} - export interface WidgetBuilder { buildWidget(widgetProps: T): JSX.Element; } diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index 97bd563f9d..768e95d5b8 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -65,6 +65,7 @@ class ContainerWidget extends BaseWidget< style={{ ...this.getPositionStyle(), }} + isRoot={!this.props.parentId} orientation={this.props.orientation || "VERTICAL"} > {_.map(this.props.children, this.renderChildWidget)} From 59b3eb1d7bc4428531d2bc6011c8a0ae4c7b209d Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Wed, 2 Oct 2019 01:45:02 +0530 Subject: [PATCH 07/19] Make control sizes configurable --- .../editorComponents/DraggableComponent.tsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index f72d01fb96..bb4ada102e 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -7,6 +7,10 @@ import { ContainerProps, FocusContext } from "./ContainerComponent"; import { ControlIcons } from "../icons/ControlIcons"; import { theme } from "../constants/DefaultTheme"; +// FontSizes array in DefaultTheme.tsx +// Change this to toggle the size of delete and move handles. +const CONTROL_THEME_FONTSIZE_INDEX = 6; + const DraggableWrapper = styled.div<{ show: boolean }>` & > div.control { display: ${props => (props.show ? "block" : "none")}; @@ -18,8 +22,8 @@ const DraggableWrapper = styled.div<{ show: boolean }>` const DragHandle = styled.div` position: absolute; - left: -${props => props.theme.spaces[4]}px; - top: -${props => props.theme.spaces[4]}px; + left: -${props => props.theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX] / 2}px; + top: -${props => props.theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX] / 2}px; cursor: move; display: none; cursor: grab; @@ -28,21 +32,21 @@ const DragHandle = styled.div` const DeleteControl = styled.div` position: absolute; - right: -${props => props.theme.spaces[4]}px; - top: -${props => props.theme.spaces[4]}px; + right: -${props => props.theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX] / 2}px; + top: -${props => props.theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX] / 2}px; display: none; cursor: pointer; z-index: 11; `; const moveControlIcon = ControlIcons.MOVE_CONTROL({ - width: theme.fontSizes[6], - height: theme.fontSizes[6], + width: theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX], + height: theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX], }); const deleteControlIcon = ControlIcons.DELETE_CONTROL({ - width: theme.fontSizes[6], - height: theme.fontSizes[6], + width: theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX], + height: theme.fontSizes[CONTROL_THEME_FONTSIZE_INDEX], }); type DraggableComponentProps = WidgetProps & ContainerProps; From 91fd8ff17e739a81dc5541e9f6a7b60447877fdc Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Wed, 2 Oct 2019 23:43:04 +0530 Subject: [PATCH 08/19] Propagate WidgetConfigs to new widget. Use theme spaces everywhere. --- app/client/src/constants/DefaultTheme.tsx | 4 +- .../src/constants/ReduxActionConstants.tsx | 1 + .../src/editorComponents/BaseComponent.tsx | 1 + .../editorComponents/ContainerComponent.tsx | 11 ++++ .../editorComponents/ResizableComponent.tsx | 16 +++--- .../src/pages/Editor/WidgetCardsPane.tsx | 2 +- app/client/src/pages/Editor/index.tsx | 9 ++-- app/client/src/sagas/ErrorSagas.tsx | 1 + app/client/src/sagas/WidgetOperationSagas.tsx | 54 ++++++++++++------- app/client/src/sagas/selectors.tsx | 13 ++++- app/client/src/utils/AppsmithUtils.tsx | 28 ++++++++++ app/client/src/utils/WidgetPropsUtils.tsx | 6 ++- app/client/src/widgets/ButtonWidget.tsx | 1 + app/client/src/widgets/ContainerWidget.tsx | 6 ++- app/client/src/widgets/SpinnerWidget.tsx | 1 + 15 files changed, 116 insertions(+), 38 deletions(-) diff --git a/app/client/src/constants/DefaultTheme.tsx b/app/client/src/constants/DefaultTheme.tsx index 62e02cfdb7..34b6872f51 100644 --- a/app/client/src/constants/DefaultTheme.tsx +++ b/app/client/src/constants/DefaultTheme.tsx @@ -24,9 +24,9 @@ export type Theme = { }; export const theme: Theme = { - radii: [0, 4, 8, 10, 20], + radii: [0, 4, 8, 10, 20, 50], fontSizes: [0, 10, 12, 14, 16, 18, 24, 28, 32, 48, 64], - spaces: [0, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24], + spaces: [0, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24], fontWeights: [0, 400, 500, 700], colors: { primary: Colors.GREEN, diff --git a/app/client/src/constants/ReduxActionConstants.tsx b/app/client/src/constants/ReduxActionConstants.tsx index 6cecce4af4..a40adcf4e7 100644 --- a/app/client/src/constants/ReduxActionConstants.tsx +++ b/app/client/src/constants/ReduxActionConstants.tsx @@ -48,6 +48,7 @@ export const ReduxActionErrorTypes: { [key: string]: string } = { FETCH_PAGE_ERROR: "FETCH_PAGE_ERROR", SAVE_PAGE_ERROR: "SAVE_PAGE_ERROR", FETCH_WIDGET_CARDS_ERROR: "FETCH_WIDGET_CARDS_ERROR", + WIDGET_OPERATION_ERROR: "WIDGET_OPERATION_ERROR", }; export type ReduxActionErrorType = (typeof ReduxActionErrorTypes)[keyof typeof ReduxActionErrorTypes]; diff --git a/app/client/src/editorComponents/BaseComponent.tsx b/app/client/src/editorComponents/BaseComponent.tsx index 3389208508..886a8be1fe 100644 --- a/app/client/src/editorComponents/BaseComponent.tsx +++ b/app/client/src/editorComponents/BaseComponent.tsx @@ -22,6 +22,7 @@ export interface BaseStyle { export interface ComponentProps { widgetId: string; + widgetName?: string; style: BaseStyle; } diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index eb6a53b842..36da05b658 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -24,6 +24,17 @@ export const Container = styled("div")` left: 0; top: 0; width: 100%; + padding: ${props => props.theme.spaces[8]}px ${props => + props.theme.spaces[1]}px ${props => props.theme.spaces[1]}px; + &:after { + content: "${props => props.widgetName}"; + position: absolute; + left: ${props => props.theme.spaces[1]}px; + top: ${props => props.theme.spaces[1]}px; + font-size: ${props => props.theme.fontSizes[2]}px; + text-align: left; + width: 100%; + } `; export const FocusContext: Context<{ diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index d24eea983f..90404df1bf 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -16,20 +16,20 @@ const ResizableContainer = styled(Resizable)` &:before { content: ""; position: absolute; - width: 8px; - height: 8px; - border-radius: 50%; + width: ${props => props.theme.spaces[2]}px; + height: ${props => props.theme.spaces[2]}px; + border-radius: ${props => props.theme.radii[5]}%; z-index: 9; background: ${props => props.theme.colors.containerBorder}; } &:after { - right: -4px; - top: 50%; + right: -${props => props.theme.spaces[1]}px; + top: calc(50% - ${props => props.theme.spaces[1]}px); } &:before { - left: calc(50%); - top: calc(100% - 4px); + left: calc(50% - ${props => props.theme.spaces[1]}px); + bottom: -${props => props.theme.spaces[1]}px; } `; @@ -50,6 +50,8 @@ export const ResizableComponent = (props: ResizableComponentProps) => { width: props.style.componentWidth as number, height: props.style.componentHeight as number, }} + minWidth={props.parentColumnSpace} + minHeight={props.parentRowSpace} style={{ ...props.style }} onResizeStop={updateSize} grid={[props.parentColumnSpace, props.parentRowSpace]} diff --git a/app/client/src/pages/Editor/WidgetCardsPane.tsx b/app/client/src/pages/Editor/WidgetCardsPane.tsx index 6e7652af77..5c4a048979 100644 --- a/app/client/src/pages/Editor/WidgetCardsPane.tsx +++ b/app/client/src/pages/Editor/WidgetCardsPane.tsx @@ -19,7 +19,7 @@ const CardsPaneWrapper = styled.div` const CardsWrapper = styled.div` display: grid; grid-template-columns: 1fr 1fr 1fr; - grid-gap: ${props => props.theme.spaces[2]}px; + grid-gap: ${props => props.theme.spaces[1]}px; justify-items: stretch; align-items: stretch; `; diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index 9c0a334015..a4c781d9ee 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -105,15 +105,14 @@ const mapStateToProps = (state: AppState): EditorReduxState => { state.ui.editor.pageWidgetId, state.entities, ); - const configs = state.entities.widgetConfig.config; const cards = state.ui.editor.cards; const groups: string[] = Object.keys(cards); groups.forEach((group: string) => { - cards[group] = cards[group].map((widget: WidgetCardProps) => ({ - ...widget, - ...configs[widget.type], - })); + cards[group] = cards[group].map((widget: WidgetCardProps) => { + const { rows, columns } = state.entities.widgetConfig.config[widget.type]; + return { ...widget, rows, columns }; + }); }); return { diff --git a/app/client/src/sagas/ErrorSagas.tsx b/app/client/src/sagas/ErrorSagas.tsx index 6e3ba93c51..754999101f 100644 --- a/app/client/src/sagas/ErrorSagas.tsx +++ b/app/client/src/sagas/ErrorSagas.tsx @@ -24,6 +24,7 @@ export function* validateResponse(response: ApiResponse) { export function* errorSaga(errorAction: ReduxAction<{ error: any }>) { // Just a pass through for now. // Add procedures to customize errors here + console.log(errorAction.payload.error); yield put({ type: ReduxActionTypes.REPORT_ERROR, payload: { diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index 88504f0705..f542311a2a 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -1,5 +1,6 @@ import { ReduxActionTypes, + ReduxActionErrorTypes, ReduxAction, } from "../constants/ReduxActionConstants"; import { @@ -9,13 +10,19 @@ import { WidgetDelete, } from "../actions/pageActions"; import { FlattenedWidgetProps } from "../reducers/entityReducers/canvasWidgetsReducer"; -import { getWidgets, getWidget, getWidgetParent } from "./selectors"; +import { + getWidgets, + getWidget, + getWidgetParent, + getDefaultWidgetConfig, +} from "./selectors"; import { generateWidgetProps, updateWidgetSize, updateWidgetPosition, } from "../utils/WidgetPropsUtils"; import { put, select, takeEvery, takeLatest, all } from "redux-saga/effects"; +import { getNextWidgetName } from "../utils/AppsmithUtils"; export function* addChildSaga(addChildAction: ReduxAction) { try { @@ -31,7 +38,7 @@ export function* addChildSaga(addChildAction: ReduxAction) { } = addChildAction.payload; const widget: FlattenedWidgetProps = yield select(getWidget, widgetId); const widgets = yield select(getWidgets); - + const defaultWidgetConfig = yield select(getDefaultWidgetConfig, type); const childWidget = generateWidgetProps( widget, type, @@ -41,6 +48,8 @@ export function* addChildSaga(addChildAction: ReduxAction) { rows, parentRowSpace, parentColumnSpace, + getNextWidgetName(type, widgets), + defaultWidgetConfig, ); widgets[childWidget.widgetId] = childWidget; if (widget && widget.children) { @@ -51,11 +60,13 @@ export function* addChildSaga(addChildAction: ReduxAction) { type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets }, }); - } catch (err) { + } catch (error) { yield put({ - type: ReduxActionTypes.WIDGET_OPERATION_ERROR, - action: ReduxActionTypes.WIDGET_ADD_CHILD, - ...err, + type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR, + payload: { + action: ReduxActionTypes.WIDGET_ADD_CHILD, + error, + }, }); } } @@ -74,12 +85,13 @@ export function* deleteSaga(deleteAction: ReduxAction) { type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets }, }); - } catch (err) { - console.log(err); + } catch (error) { yield put({ - type: ReduxActionTypes.WIDGET_OPERATION_ERROR, - action: ReduxActionTypes.WIDGET_DELETE, - ...err, + type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR, + payload: { + action: ReduxActionTypes.WIDGET_DELETE, + error, + }, }); } } @@ -110,11 +122,13 @@ export function* moveSaga(moveAction: ReduxAction) { type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets }, }); - } catch (err) { + } catch (error) { yield put({ - type: ReduxActionTypes.WIDGET_OPERATION_ERROR, - action: ReduxActionTypes.WIDGET_MOVE, - ...err, + type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR, + payload: { + action: ReduxActionTypes.WIDGET_MOVE, + error, + }, }); } } @@ -133,11 +147,13 @@ export function* resizeSaga(resizeAction: ReduxAction) { type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets }, }); - } catch (err) { + } catch (error) { yield put({ - type: ReduxActionTypes.WIDGET_OPERATION_ERROR, - action: ReduxActionTypes.WIDGET_RESIZE, - ...err, + type: ReduxActionErrorTypes.WIDGET_OPERATION_ERROR, + payload: { + action: ReduxActionTypes.WIDGET_RESIZE, + error, + }, }); } } diff --git a/app/client/src/sagas/selectors.tsx b/app/client/src/sagas/selectors.tsx index a32b31a914..fc1c5eacf8 100644 --- a/app/client/src/sagas/selectors.tsx +++ b/app/client/src/sagas/selectors.tsx @@ -1,7 +1,7 @@ import { AppState } from "../reducers"; import { FlattenedWidgetProps } from "../reducers/entityReducers/canvasWidgetsReducer"; import { WidgetProps } from "../widgets/BaseWidget"; - +import { WidgetType } from "../constants/WidgetConstants"; export const getWidgets = ( state: AppState, ): { [widgetId: string]: FlattenedWidgetProps } => { @@ -35,3 +35,14 @@ export const getWidgetParent = ( widget.children.indexOf(widgetId) > -1, ); }; + +export const getDefaultWidgetConfig = ( + state: AppState, + type: WidgetType, +): Partial => { + const configs = state.entities.widgetConfig.config; + const widgetConfig = { ...configs[type] }; + delete widgetConfig.rows; + delete widgetConfig.columns; + return widgetConfig; +}; diff --git a/app/client/src/utils/AppsmithUtils.tsx b/app/client/src/utils/AppsmithUtils.tsx index af48741e0f..ba3636bba0 100644 --- a/app/client/src/utils/AppsmithUtils.tsx +++ b/app/client/src/utils/AppsmithUtils.tsx @@ -12,6 +12,8 @@ import FontFaceObserver from "fontfaceobserver"; import PropertyControlRegistry from "./PropertyControlRegistry"; import WidgetBuilderRegistry from "./WidgetRegistry"; import { Property } from "../api/ActionAPI"; +import { WidgetType } from "../constants/WidgetConstants"; +import { FlattenedWidgetProps } from "../reducers/entityReducers/canvasWidgetsReducer"; import _ from "lodash"; export const createReducer = ( @@ -60,3 +62,29 @@ export const mapToPropList = (map: Record): Property[] => { return { key: key, value: value }; }); }; + +export const getNextWidgetName = ( + type: WidgetType, + widgets: { + [id: string]: FlattenedWidgetProps; + }, +) => { + const prefix = type + .split("_") + .filter(token => token !== "WIDGET") + .join("") + .toLowerCase(); + const usedIndices: number[] = Object.values(widgets).map(widget => { + if (widget.type === type) { + const ind = widget.widgetName + ? parseInt(widget.widgetName.split(prefix)[1], 10) + : 0; + return Number.isNaN(ind) ? 0 : ind; + } + return 0; + }) as number[]; + + const lastIndex = Math.max(...usedIndices); + + return prefix + (lastIndex + 1); +}; diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index 13966d9f3f..bd2f953966 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -211,6 +211,8 @@ export const generateWidgetProps = ( rows: number, parentRowSpace: number, parentColumnSpace: number, + widgetName: string, + widgetConfig: Partial, ): ContainerWidgetProps => { if (parent && parent.snapColumns && parent.snapRows) { const sizes = { @@ -229,11 +231,13 @@ export const generateWidgetProps = ( background: Colors.WHITE, }; } + console.log(widgetConfig); return { + ...widgetConfig, type, executeAction: () => {}, widgetId: generateReactKey(), - widgetName: generateReactKey(), //TODO: figure out what this is to populate appropriately + widgetName: widgetName || generateReactKey(), //TODO: figure out what this is to populate appropriately isVisible: true, parentColumnSpace, parentRowSpace, diff --git a/app/client/src/widgets/ButtonWidget.tsx b/app/client/src/widgets/ButtonWidget.tsx index 63e4a04c92..75f56b8b39 100644 --- a/app/client/src/widgets/ButtonWidget.tsx +++ b/app/client/src/widgets/ButtonWidget.tsx @@ -14,6 +14,7 @@ class ButtonWidget extends BaseWidget { { diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index 768e95d5b8..9cbc9dbfa1 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -35,9 +35,10 @@ class ContainerWidget extends BaseWidget< super.componentDidUpdate(previousProps); let snapColumnSpace = this.state.snapColumnSpace; if (this.state.componentWidth) - snapColumnSpace = + snapColumnSpace = Math.floor( this.state.componentWidth / - (this.props.snapColumns || DEFAULT_GRID_COLUMNS); + (this.props.snapColumns || DEFAULT_GRID_COLUMNS), + ); if (this.state.snapColumnSpace !== snapColumnSpace) { this.setState({ snapColumnSpace, @@ -67,6 +68,7 @@ class ContainerWidget extends BaseWidget< }} isRoot={!this.props.parentId} orientation={this.props.orientation || "VERTICAL"} + widgetName={this.props.widgetName} > {_.map(this.props.children, this.renderChildWidget)} diff --git a/app/client/src/widgets/SpinnerWidget.tsx b/app/client/src/widgets/SpinnerWidget.tsx index 70429a8d50..3291c20e6f 100644 --- a/app/client/src/widgets/SpinnerWidget.tsx +++ b/app/client/src/widgets/SpinnerWidget.tsx @@ -10,6 +10,7 @@ class SpinnerWidget extends BaseWidget { Date: Thu, 3 Oct 2019 01:12:25 +0530 Subject: [PATCH 09/19] Use React-RND to resize on all sides. Use class selector for resize bounds --- app/client/package.json | 1 + app/client/src/actions/pageActions.tsx | 6 ++- .../editorComponents/ContainerComponent.tsx | 1 + .../editorComponents/DraggableComponent.tsx | 5 +++ .../editorComponents/ResizableComponent.tsx | 44 ++++++++++++++----- app/client/src/sagas/WidgetOperationSagas.tsx | 11 +++-- app/client/yarn.lock | 36 ++++++++++++--- 7 files changed, 83 insertions(+), 21 deletions(-) diff --git a/app/client/package.json b/app/client/package.json index eec0818de8..49f2533503 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -46,6 +46,7 @@ "react-dom": "^16.7.0", "react-netlify-identity": "^0.1.9", "react-redux": "^6.0.0", + "react-rnd": "^10.1.1", "react-router": "^5.0.1", "react-router-dom": "^5.0.1", "react-scripts": "^3.1.1", diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index ae0bfbf849..29d9137f59 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -111,8 +111,10 @@ export type WidgetDelete = { export type WidgetResize = { widgetId: string; - width: number; // delta/diff - height: number; // delta/diff + leftColumn: number; + rightColumn: number; + topRow: number; + bottomRow: number; }; export const updateWidget = ( diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index 36da05b658..8e67cf1e73 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -32,6 +32,7 @@ export const Container = styled("div")` left: ${props => props.theme.spaces[1]}px; top: ${props => props.theme.spaces[1]}px; font-size: ${props => props.theme.fontSizes[2]}px; + color: ${props => props.theme.colors.containerBorder}; text-align: left; width: 100%; } diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index bb4ada102e..fa8347ec2c 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -18,6 +18,7 @@ const DraggableWrapper = styled.div<{ show: boolean }>` &:hover > div { display: block; } + display: block; `; const DragHandle = styled.div` @@ -86,6 +87,10 @@ const DraggableComponent = (props: DraggableComponentProps) => { top: props.style ? props.style.yPosition + props.style.yPositionUnit : 0, + minWidth: + props.style.componentWidth + (props.style.widthUnit || "px"), + minHeight: + props.style.componentHeight + (props.style.heightUnit || "px"), }} > diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 90404df1bf..81f9e8d4f4 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -1,12 +1,13 @@ import React, { useContext } from "react"; import styled from "styled-components"; -import { Resizable, ResizeDirection } from "re-resizable"; +import { Rnd } from "react-rnd"; +import { XYCoord } from "react-dnd"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; export type ResizableComponentProps = WidgetProps & ContainerProps; -const ResizableContainer = styled(Resizable)` +const ResizableContainer = styled(Rnd)` position: relative; z-index: 10; border: ${props => { @@ -35,35 +36,58 @@ const ResizableContainer = styled(Resizable)` export const ResizableComponent = (props: ResizableComponentProps) => { const { boundingParent } = useContext(ParentBoundsContext); + let bounds = "body"; + if (boundingParent && boundingParent.current) { + bounds = "." + boundingParent.current.className.split(" ")[1]; + } const updateSize = ( e: Event, - dir: ResizeDirection, + dir: any, ref: any, delta: { width: number; height: number }, + position: XYCoord, ) => { + const leftColumn = props.leftColumn + position.x / props.parentColumnSpace; + const topRow = props.topRow + position.y / props.parentRowSpace; + + const rightColumn = + props.rightColumn + (delta.width + position.x) / props.parentColumnSpace; + const bottomRow = + props.bottomRow + (delta.height + position.y) / props.parentRowSpace; + props.updateWidget && - props.updateWidget(WidgetOperations.RESIZE, props.widgetId, delta); + props.updateWidget(WidgetOperations.RESIZE, props.widgetId, { + leftColumn, + rightColumn, + topRow, + bottomRow, + }); }; return ( diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index f542311a2a..dbb7d4faef 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -18,7 +18,6 @@ import { } from "./selectors"; import { generateWidgetProps, - updateWidgetSize, updateWidgetPosition, } from "../utils/WidgetPropsUtils"; import { put, select, takeEvery, takeLatest, all } from "redux-saga/effects"; @@ -135,12 +134,18 @@ export function* moveSaga(moveAction: ReduxAction) { export function* resizeSaga(resizeAction: ReduxAction) { try { - const { widgetId, height, width } = resizeAction.payload; + const { + widgetId, + leftColumn, + rightColumn, + topRow, + bottomRow, + } = resizeAction.payload; let widget: FlattenedWidgetProps = yield select(getWidget, widgetId); const widgets = yield select(getWidgets); - widget = updateWidgetSize(widget, height, width); + widget = { ...widget, leftColumn, rightColumn, topRow, bottomRow }; widgets[widgetId] = widget; yield put({ diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 95bc8690f1..4ac8855416 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -3031,7 +3031,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.2: +classnames@^2.2, classnames@^2.2.5: version "2.2.6" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== @@ -9576,6 +9576,13 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +re-resizable@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.1.0.tgz#ba4ece505b48f05691446d57837151349d7575e8" + integrity sha512-Jj9zdYW6SnUto8pmH4b/3Kms/PKPv9CuWE70W1IuUIR1HlrEibgsqhbUe8BYDRBTuagH1gav09806k7TieUeSA== + dependencies: + fast-memoize "^2.5.1" + re-resizable@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.0.0.tgz#84258f098b0dde214a39ca6d9ca9959aeefbc26d" @@ -9661,6 +9668,14 @@ react-dom@^16.7.0: prop-types "^15.6.2" scheduler "^0.15.0" +react-draggable@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.0.3.tgz#6b9f76f66431c47b9070e9b805bbc520df8ca481" + integrity sha512-4vD6zms+9QGeZ2RQXzlUBw8PBYUXy+dzYX5r22idjp9YwQKIIvD/EojL0rbjS1GK4C3P0rAJnmKa8gDQYWUDyA== + dependencies: + classnames "^2.2.5" + prop-types "^15.6.0" + react-error-overlay@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f" @@ -9708,6 +9723,15 @@ react-redux@^6.0.0: prop-types "^15.7.2" react-is "^16.8.2" +react-rnd@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/react-rnd/-/react-rnd-10.1.1.tgz#4f4d9d28c46a6060acb64600df7a88490862a324" + integrity sha512-KwNUbNd4Kg2DTLdw/Eb8dSC3T5nMRQIRfyyVjdoLT85hKXpeCkMRb2zo4BHCzkgdgCbFGgYLDmj1qRH5DUkTGA== + dependencies: + re-resizable "6.1.0" + react-draggable "4.0.3" + tslib "1.10.0" + react-router-dom@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be" @@ -11650,16 +11674,16 @@ tsdx@^0.6.0: tslib "^1.9.3" typescript "^3.4.5" +tslib@1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + tslib@1.9.3, tslib@~1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - tsutils@^3.17.1, tsutils@^3.7.0: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" From 089bc97122a3ab3b6e0e432a20d93f244e6e5754 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 01:31:51 +0530 Subject: [PATCH 10/19] Allow dragging from anywhere on widget. Use theme colors for dropzone. Fix container widget positioning. --- app/client/src/editorComponents/DraggableComponent.tsx | 2 +- app/client/src/editorComponents/DropTargetComponent.tsx | 2 +- app/client/src/editorComponents/Dropzone.tsx | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index fa8347ec2c..a260d8a07c 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -69,7 +69,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { { if (setFocus) { setFocus(props.widgetId); diff --git a/app/client/src/editorComponents/DropTargetComponent.tsx b/app/client/src/editorComponents/DropTargetComponent.tsx index b6285d1714..9668faa57f 100644 --- a/app/client/src/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/editorComponents/DropTargetComponent.tsx @@ -85,7 +85,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
{ width: wrapperProps.width + "px", top: wrapperProps.top + "px", height: wrapperProps.height + "px", - background: props.canDrop ? "blue" : "red", + background: props.canDrop ? theme.colors.hover : theme.colors.error, }} /> ); From 87171c6ecb1e62b981f5417eec6db195bcb5385d Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 02:44:58 +0530 Subject: [PATCH 11/19] Fix collision with self on dragging --- app/client/src/editorComponents/ContainerComponent.tsx | 2 +- .../src/editorComponents/DropTargetComponent.tsx | 10 +++++++--- app/client/src/sagas/WidgetOperationSagas.tsx | 2 +- app/client/src/utils/WidgetPropsUtils.tsx | 6 ++++-- app/client/src/widgets/ContainerWidget.tsx | 3 ++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index 8e67cf1e73..880e3a264e 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -27,7 +27,7 @@ export const Container = styled("div")` padding: ${props => props.theme.spaces[8]}px ${props => props.theme.spaces[1]}px ${props => props.theme.spaces[1]}px; &:after { - content: "${props => props.widgetName}"; + content: "${props => props.widgetId}"; position: absolute; left: ${props => props.theme.spaces[1]}px; top: ${props => props.theme.spaces[1]}px; diff --git a/app/client/src/editorComponents/DropTargetComponent.tsx b/app/client/src/editorComponents/DropTargetComponent.tsx index 9668faa57f..d5697a7157 100644 --- a/app/client/src/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/editorComponents/DropTargetComponent.tsx @@ -35,7 +35,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { accept: Object.values(WidgetFactory.getWidgetTypes()), drop(widget: WidgetProps & Partial, monitor) { // Make sure we're dropping in this container. - if (isOver && monitor.canDrop()) { + if (isOver) { props.updateWidget && props.updateWidget( ...widgetOperationParams( @@ -52,13 +52,17 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { }, // Collect isOver for ui transforms when hovering over this component collect: monitor => ({ - isOver: !!monitor.isOver({ shallow: true }), + isOver: + (monitor.isOver({ shallow: true }) && + props.widgetId !== monitor.getItem().widgetId) || + (monitor.isOver() && props.widgetId !== monitor.getItem().widgetId), }), // Only allow drop if the drag object is directly over this component // As opposed to the drag object being over a child component, or outside the component bounds // Also only if the dropzone does not overlap any existing children canDrop: (widget, monitor) => { - if (monitor.isOver({ shallow: true })) { + // Check if the draggable is the same as the dropTarget + if (isOver) { return noCollision( monitor.getClientOffset() as XYCoord, props.snapColumnSpace, diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index dbb7d4faef..c5e856738c 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -108,7 +108,7 @@ export function* moveSaga(moveAction: ReduxAction) { // Replace widget with update widget props widgets[widgetId] = widget; // If the parent has changed i.e parentWidgetId is not parent.widgetId - if (parent.widgetId !== parentWidgetId) { + if (parent.widgetId !== parentWidgetId && widgetId !== parentWidgetId) { // Remove from the previous parent parent.children = parent.children.filter( (child: string) => child !== widgetId, diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index bd2f953966..4b4b1a7160 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -71,7 +71,10 @@ export const isDropZoneOccupied = ( ) => { if (occupied) { occupied = occupied.filter(widgetDetails => { - return widgetDetails.id !== widget.widgetId; + return ( + widgetDetails.id !== widget.widgetId && + widgetDetails.parentId !== widget.widgetId + ); }); for (let i = 0; i < occupied.length; i++) { if (areIntersecting(occupied[i], offset)) { @@ -231,7 +234,6 @@ export const generateWidgetProps = ( background: Colors.WHITE, }; } - console.log(widgetConfig); return { ...widgetConfig, type, diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index 9cbc9dbfa1..49f283bfee 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -79,6 +79,7 @@ class ContainerWidget extends BaseWidget< return this.props.children ? this.props.children.map(child => ({ id: child.widgetId, + parentId: this.props.widgetId, left: child.leftColumn, top: child.topRow, bottom: child.bottomRow, @@ -89,7 +90,6 @@ class ContainerWidget extends BaseWidget< getCanvasView() { const style = this.getPositionStyle(); const occupiedSpaces = this.getOccupiedSpaces(); - const renderDraggableComponent = ( Date: Thu, 3 Oct 2019 03:03:37 +0530 Subject: [PATCH 12/19] Revert to only handle based dragging due to conflict with resizable component --- app/client/src/editorComponents/DraggableComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index a260d8a07c..fa8347ec2c 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -69,7 +69,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { { if (setFocus) { setFocus(props.widgetId); From afed39a6e2976072e4294fea0a925726757e40bf Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 03:26:25 +0530 Subject: [PATCH 13/19] Change back to widget Name --- app/client/src/editorComponents/ContainerComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index 880e3a264e..8e67cf1e73 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -27,7 +27,7 @@ export const Container = styled("div")` padding: ${props => props.theme.spaces[8]}px ${props => props.theme.spaces[1]}px ${props => props.theme.spaces[1]}px; &:after { - content: "${props => props.widgetId}"; + content: "${props => props.widgetName}"; position: absolute; left: ${props => props.theme.spaces[1]}px; top: ${props => props.theme.spaces[1]}px; From 5bf84ee3612f8334d01730224ef4bff5567a55ec Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 16:34:11 +0530 Subject: [PATCH 14/19] Move FocusContext to Canvas --- app/client/package.json | 2 - .../editorComponents/ContainerComponent.tsx | 26 +-- .../editorComponents/DraggableComponent.tsx | 3 +- .../editorComponents/DropTargetComponent.tsx | 2 - app/client/src/pages/Editor/Canvas.tsx | 18 +- app/client/yarn.lock | 220 +----------------- 6 files changed, 29 insertions(+), 242 deletions(-) diff --git a/app/client/package.json b/app/client/package.json index 49f2533503..1ffbb1d56f 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -39,7 +39,6 @@ "node-sass": "^4.11.0", "normalizr": "^3.3.0", "prettier": "^1.18.2", - "re-resizable": "^6.0.0", "react": "^16.7.0", "react-dnd": "^9.3.4", "react-dnd-html5-backend": "^9.3.4", @@ -84,7 +83,6 @@ "eslint-config-react": "^1.1.7", "eslint-plugin-prettier": "^3.1.0", "eslint-plugin-react": "^7.14.3", - "icon-font-generator": "^2.1.10", "redux-devtools": "^3.5.0", "redux-devtools-extension": "^2.13.8" }, diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index 8e67cf1e73..62fe2d4da9 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -1,14 +1,7 @@ import { ComponentProps } from "./BaseComponent"; import { ContainerOrientation } from "../constants/WidgetConstants"; import styled from "../constants/DefaultTheme"; -import React, { - createContext, - useState, - Dispatch, - SetStateAction, - Context, - useRef, -} from "react"; +import React, { createContext, Context, useRef } from "react"; export const Container = styled("div")` display: flex; @@ -38,33 +31,20 @@ export const Container = styled("div")` } `; -export const FocusContext: Context<{ - isFocused?: string; - setFocus?: Dispatch>; -}> = createContext({}); - export const ParentBoundsContext: Context<{ boundingParent?: React.RefObject; }> = createContext({}); const ContainerComponent = (props: ContainerProps) => { - const [isFocused, setFocus] = useState(""); const container = useRef(null); - const ContainerWithoutFocusContextProvider = ( + + return ( {props.children} ); - const ContainerWithFocusContextProvider = ( - - {ContainerWithoutFocusContextProvider} - - ); - return props.isRoot - ? ContainerWithFocusContextProvider - : ContainerWithoutFocusContextProvider; }; export interface ContainerProps extends ComponentProps { diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index fa8347ec2c..133e72b8c4 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -3,7 +3,8 @@ import styled from "styled-components"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "../assets/images/blank.png"; -import { ContainerProps, FocusContext } from "./ContainerComponent"; +import { ContainerProps } from "./ContainerComponent"; +import { FocusContext } from "../pages/Editor/Canvas"; import { ControlIcons } from "../icons/ControlIcons"; import { theme } from "../constants/DefaultTheme"; diff --git a/app/client/src/editorComponents/DropTargetComponent.tsx b/app/client/src/editorComponents/DropTargetComponent.tsx index d5697a7157..296e2574d8 100644 --- a/app/client/src/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/editorComponents/DropTargetComponent.tsx @@ -5,7 +5,6 @@ import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReduce import { useDrop, XYCoord } from "react-dnd"; import { ContainerProps } from "./ContainerComponent"; import WidgetFactory from "../utils/WidgetFactory"; - import { widgetOperationParams, noCollision } from "../utils/WidgetPropsUtils"; import DragLayerComponent from "./DragLayerComponent"; import DropTargetMask from "./DropTargetMask"; @@ -29,7 +28,6 @@ type DropTargetBounds = { export const DropTargetComponent = (props: DropTargetComponentProps) => { // Hook to keep the offset of the drop target container in state const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 }); - // Make this component a drop target const [{ isOver }, drop] = useDrop({ accept: Object.values(WidgetFactory.getWidgetTypes()), diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 0b7f414dee..a3e88c5a2e 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -1,4 +1,10 @@ -import React from "react"; +import React, { + createContext, + useState, + Context, + Dispatch, + SetStateAction, +} from "react"; import styled from "styled-components"; import WidgetFactory from "../../utils/WidgetFactory"; import { RenderModes } from "../../constants/WidgetConstants"; @@ -18,9 +24,15 @@ interface CanvasProps { widgetFunctions: WidgetFunctions; } +export const FocusContext: Context<{ + isFocused?: string; + setFocus?: Dispatch>; +}> = createContext({}); + const Canvas = (props: CanvasProps) => { + const [isFocused, setFocus] = useState(""); return ( - + {props.dsl.widgetId && WidgetFactory.createWidget( @@ -29,7 +41,7 @@ const Canvas = (props: CanvasProps) => { RenderModes.CANVAS, )} - + ); }; diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 4ac8855416..6ac6215440 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -2090,7 +2090,7 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -argparse@^1.0.6, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -2562,13 +2562,6 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== -bindings@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -2782,13 +2775,6 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -bufferstreams@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-1.1.3.tgz#a8515ac024fa90e8fa7d58c11b13dea1f28abe72" - integrity sha512-HaJnVuslRF4g2kSDeyl++AaVizoitCpL9PglzCYwy0uHHyvWerfvEb8jWmYbF1z4kiVFolGomnxSGl+GUQp2jg== - dependencies: - readable-stream "^2.0.2" - builtin-modules@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" @@ -3190,11 +3176,6 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.2" -colors@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" - integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -3207,7 +3188,7 @@ commander@2.17.x: resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@^2.9.0, commander@~2.20.0: +commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0: version "2.20.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== @@ -3707,11 +3688,6 @@ csstype@^2.2.0: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41" integrity sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg== -cubic2quad@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/cubic2quad/-/cubic2quad-1.1.1.tgz#69b19c61a3f5b41ecf2f1d5fae8fb03415aa8b15" - integrity sha1-abGcYaP1tB7PLx1fro+wNBWqixU= - currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -4856,11 +4832,6 @@ file-loader@3.0.1: loader-utils "^1.0.2" schema-utils "^1.0.0" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filesize@3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" @@ -5369,7 +5340,7 @@ handle-thing@^2.0.0: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== -handlebars@^4.0.5, handlebars@^4.1.2: +handlebars@^4.1.2: version "4.2.0" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.2.0.tgz#57ce8d2175b9bbb3d8b3cf3e4217b1aec8ddcb2e" integrity sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw== @@ -5688,16 +5659,6 @@ husky@^3.0.5: run-node "^1.0.0" slash "^3.0.0" -icon-font-generator@^2.1.10: - version "2.1.10" - resolved "https://registry.yarnpkg.com/icon-font-generator/-/icon-font-generator-2.1.10.tgz#95d6d7f3c44dc68a5fbc37b2e1a9511487387eba" - integrity sha512-p8iMm+eG9toP/nRt3K7u19NPgPkjOzJS+zdf/FG7TXH0SE7teiBQIzge2aDvQOZf4HYtCVswz0Do3/nEQHLAhA== - dependencies: - colors "^1.2.1" - glob "^7.1.2" - minimist "^1.2.0" - webfonts-generator "^0.4.0" - iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -7214,7 +7175,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@^4.2.0, lodash@~4.17.10: +"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5, lodash@^4.2.0, lodash@~4.17.10: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -7448,11 +7409,6 @@ micro-api-client@^3.2.1: resolved "https://registry.yarnpkg.com/micro-api-client/-/micro-api-client-3.3.0.tgz#52dd567d322f10faffe63d19d4feeac4e4ffd215" integrity sha512-y0y6CUB9RLVsy3kfgayU28746QrNMpSm9O/AYGNsBgOkJr/X/Jk0VLGoO8Ude7Bpa8adywzF+MzXNZRFRsNPhg== -microbuffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/microbuffer/-/microbuffer-1.0.0.tgz#8b3832ed40c87d51f47bb234913a698a756d19d2" - integrity sha1-izgy7UDIfVH0e7I0kTppinVtGdI= - microevent.ts@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" @@ -7689,7 +7645,7 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@^2.1.0, nan@^2.12.1, nan@^2.13.2: +nan@^2.12.1, nan@^2.13.2: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -7721,13 +7677,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -neatequal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/neatequal/-/neatequal-1.0.0.tgz#2ee1211bc9fa6e4c55715fd210bb05602eb1ae3b" - integrity sha1-LuEhG8n6bkxVcV/SELsFYC6xrjs= - dependencies: - varstream "^0.3.2" - needle@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" @@ -7774,7 +7723,7 @@ node-forge@0.8.2: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.2.tgz#b4bcc59fb12ce77a8825fc6a783dfe3182499c5a" integrity sha512-mXQ9GBq1N3uDCyV1pdSzgIguwgtVpM7f5/5J4ipz12PKWElmPpVWLDuWl8iXmhysr21+WmX/OJ5UKx82wjomgg== -node-gyp@^3.0.3, node-gyp@^3.8.0: +node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== @@ -8347,7 +8296,7 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@^1.0.0, pako@~1.0.5: +pako@~1.0.5: version "1.0.10" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== @@ -9365,11 +9314,6 @@ private@^0.1.6: resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -9583,13 +9527,6 @@ re-resizable@6.1.0: dependencies: fast-memoize "^2.5.1" -re-resizable@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.0.0.tgz#84258f098b0dde214a39ca6d9ca9959aeefbc26d" - integrity sha512-RTrnhbGgYyZ4hTc6db4JeMnRfmloEPWtuYaXZEa2PRaEC4mreWNFnZtMVsHil3z3iX+WchD+da8BLlTJBcstMA== - dependencies: - fast-memoize "^2.5.1" - react-app-polyfill@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-1.0.2.tgz#2a51175885c88245a2a356dc46df29f38ec9f060" @@ -9902,7 +9839,7 @@ read-pkg@^5.1.1: parse-json "^5.0.0" type-fest "^0.6.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -9915,16 +9852,6 @@ read-pkg@^5.1.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readable-stream@^3.0.6, readable-stream@^3.1.1: version "3.4.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" @@ -9934,18 +9861,6 @@ readable-stream@^3.0.6, readable-stream@^3.1.1: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -10547,7 +10462,7 @@ sass-loader@7.2.0: pify "^4.0.1" semver "^5.5.0" -sax@^1.1.5, sax@^1.2.4, sax@~1.2.4: +sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -11099,16 +11014,6 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string.fromcodepoint@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz#8d978333c0bc92538f50f383e4888f3e5619d653" - integrity sha1-jZeDM8C8klOPUPOD5IiPPlYZ1lM= - -string.prototype.codepointat@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc" - integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg== - string.prototype.trimleft@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" @@ -11132,11 +11037,6 @@ string_decoder@^1.0.0, string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -11291,38 +11191,6 @@ svg-parser@^2.0.0: resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.2.tgz#d134cc396fa2681dc64f518330784e98bd801ec8" integrity sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg== -svg-pathdata@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/svg-pathdata/-/svg-pathdata-1.0.4.tgz#7a681342aac7effd8d52afba7999910c9da3b959" - integrity sha1-emgTQqrH7/2NUq+6eZmRDJ2juVk= - dependencies: - readable-stream "~2.0.4" - -svg2ttf@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/svg2ttf/-/svg2ttf-4.3.0.tgz#433440c7e9062f8fdcec3cad721cd08a2c7e51e3" - integrity sha512-LZ0B7zzHWLWbzLzwaKGHQvPOuxCXLReIb3LSxFSGUy1gMw2Utk6KGNbTmbmRL6Rk1qDSmTixnDrQgnXaL9n0CA== - dependencies: - argparse "^1.0.6" - cubic2quad "^1.0.0" - lodash "^4.17.10" - microbuffer "^1.0.0" - svgpath "^2.1.5" - xmldom "~0.1.22" - -svgicons2svgfont@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/svgicons2svgfont/-/svgicons2svgfont-5.0.2.tgz#0511823c6491be1a7d543292e29a8ae627ad0406" - integrity sha1-BRGCPGSRvhp9VDKS4pqK5ietBAY= - dependencies: - commander "^2.9.0" - neatequal "^1.0.0" - readable-stream "^2.0.4" - sax "^1.1.5" - string.fromcodepoint "^0.2.1" - string.prototype.codepointat "^0.2.0" - svg-pathdata "^1.0.4" - svgo@^1.0.0, svgo@^1.2.2: version "1.3.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.0.tgz#bae51ba95ded9a33a36b7c46ce9c359ae9154313" @@ -11342,11 +11210,6 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" -svgpath@^2.1.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/svgpath/-/svgpath-2.2.2.tgz#1c70d44e27f7b6bd42a74ed3c960be93e411def3" - integrity sha512-7cXFbkZvPkZpKLC+3QIfyUd3/Un/CvJONjTD3Gz5qLuEa73StPOt8kZjTi9apxO6zwCaza0bPNnmzTyrQ4qQlw== - symbol-observable@^1.0.2, symbol-observable@^1.1.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -11691,33 +11554,6 @@ tsutils@^3.17.1, tsutils@^3.7.0: dependencies: tslib "^1.8.1" -ttf2eot@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ttf2eot/-/ttf2eot-2.0.0.tgz#8e6337a585abd1608a0c84958ab483ce69f6654b" - integrity sha1-jmM3pYWr0WCKDISVirSDzmn2ZUs= - dependencies: - argparse "^1.0.6" - microbuffer "^1.0.0" - -ttf2woff2@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/ttf2woff2/-/ttf2woff2-2.0.3.tgz#5e020afe6e643287f3ad7687abed20fe654eb329" - integrity sha1-XgIK/m5kMofzrXaHq+0g/mVOsyk= - dependencies: - bindings "^1.2.1" - bufferstreams "^1.1.0" - nan "^2.1.0" - node-gyp "^3.0.3" - -ttf2woff@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ttf2woff/-/ttf2woff-2.0.1.tgz#871832240024b09db9570904c7c1928b8057c969" - integrity sha1-hxgyJAAksJ25VwkEx8GSi4BXyWk= - dependencies: - argparse "^1.0.6" - microbuffer "^1.0.0" - pako "^1.0.0" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -11810,11 +11646,6 @@ uglify-js@^3.1.4: commander "~2.20.0" source-map "~0.6.1" -underscore@^1.7.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -11917,11 +11748,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-join@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" - integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg= - url-loader@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.1.0.tgz#bcc1ecabbd197e913eca23f5e0378e24b4412961" @@ -12012,13 +11838,6 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -varstream@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/varstream/-/varstream-0.3.2.tgz#18ac6494765f3ff1a35ad9a4be053bec188a5de1" - integrity sha1-GKxklHZfP/GjWtmkvgU77BiKXeE= - dependencies: - readable-stream "^1.0.33" - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -12096,22 +11915,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -webfonts-generator@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/webfonts-generator/-/webfonts-generator-0.4.0.tgz#5f89fc81c7160e6e0cbbc9b7387e42a5851fda46" - integrity sha1-X4n8gccWDm4Mu8m3OH5CpYUf2kY= - dependencies: - handlebars "^4.0.5" - mkdirp "^0.5.0" - q "^1.1.2" - svg2ttf "^4.0.0" - svgicons2svgfont "^5.0.0" - ttf2eot "^2.0.0" - ttf2woff "^2.0.1" - ttf2woff2 "^2.0.3" - underscore "^1.7.0" - url-join "^1.1.0" - webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -12549,11 +12352,6 @@ xmlchars@^2.1.1: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xmldom@~0.1.22: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= - xregexp@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" From 622e5dc0a90ad95ced3488ca29da189630c58f54 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 20:44:50 +0530 Subject: [PATCH 15/19] Show grid only on hover. Remove min grid space between adjacent components. Fix all dropzones showing issue. Disable show control on hover. --- .../editorComponents/DragLayerComponent.tsx | 10 +++++++ .../editorComponents/DraggableComponent.tsx | 3 -- .../editorComponents/DropTargetComponent.tsx | 28 +++++++++-------- .../src/editorComponents/DropTargetMask.tsx | 25 +++++++++------- app/client/src/utils/WidgetPropsUtils.tsx | 8 ++--- app/client/src/widgets/ContainerWidget.tsx | 30 ++++++++++--------- 6 files changed, 61 insertions(+), 43 deletions(-) diff --git a/app/client/src/editorComponents/DragLayerComponent.tsx b/app/client/src/editorComponents/DragLayerComponent.tsx index b3b7b8f6b8..454d68b40a 100644 --- a/app/client/src/editorComponents/DragLayerComponent.tsx +++ b/app/client/src/editorComponents/DragLayerComponent.tsx @@ -4,6 +4,7 @@ import { useDragLayer, XYCoord } from "react-dnd"; import DropZone from "./Dropzone"; import { noCollision } from "../utils/WidgetPropsUtils"; import { OccupiedSpace } from "../widgets/ContainerWidget"; +import DropTargetMask from "./DropTargetMask"; const WrappedDragLayer = styled.div` position: absolute; @@ -23,6 +24,8 @@ type DragLayerProps = { visible: boolean; dropTargetOffset: XYCoord; occupiedSpaces: OccupiedSpace[] | null; + onBoundsUpdate: Function; + isOver: boolean; }; const DragLayerComponent = (props: DragLayerProps) => { @@ -54,8 +57,15 @@ const DragLayerComponent = (props: DragLayerProps) => { } return ( + ` & > div.control { display: ${props => (props.show ? "block" : "none")}; } - &:hover > div { - display: block; - } display: block; `; diff --git a/app/client/src/editorComponents/DropTargetComponent.tsx b/app/client/src/editorComponents/DropTargetComponent.tsx index 296e2574d8..85a2581d27 100644 --- a/app/client/src/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/editorComponents/DropTargetComponent.tsx @@ -7,7 +7,6 @@ import { ContainerProps } from "./ContainerComponent"; import WidgetFactory from "../utils/WidgetFactory"; import { widgetOperationParams, noCollision } from "../utils/WidgetPropsUtils"; import DragLayerComponent from "./DragLayerComponent"; -import DropTargetMask from "./DropTargetMask"; type DropTargetComponentProps = ContainerProps & { updateWidget?: Function; @@ -29,7 +28,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { // Hook to keep the offset of the drop target container in state const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 }); // Make this component a drop target - const [{ isOver }, drop] = useDrop({ + const [{ isOver, isExactlyOver }, drop] = useDrop({ accept: Object.values(WidgetFactory.getWidgetTypes()), drop(widget: WidgetProps & Partial, monitor) { // Make sure we're dropping in this container. @@ -54,6 +53,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { (monitor.isOver({ shallow: true }) && props.widgetId !== monitor.getItem().widgetId) || (monitor.isOver() && props.widgetId !== monitor.getItem().widgetId), + isExactlyOver: monitor.isOver({ shallow: true }), }), // Only allow drop if the drag object is directly over this component // As opposed to the drag object being over a child component, or outside the component bounds @@ -86,27 +86,31 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { return (
- + {props.children}
); diff --git a/app/client/src/editorComponents/DropTargetMask.tsx b/app/client/src/editorComponents/DropTargetMask.tsx index 47eeb53203..fe0b07c986 100644 --- a/app/client/src/editorComponents/DropTargetMask.tsx +++ b/app/client/src/editorComponents/DropTargetMask.tsx @@ -1,10 +1,11 @@ import React, { useLayoutEffect, MutableRefObject } from "react"; -import styled from "styled-components"; +import styled, { css } from "styled-components"; type DropTargetMaskProps = { rowHeight: number; columnWidth: number; setBounds: Function; + showGrid: boolean; }; export const DropTargetMaskWrapper = styled.div` @@ -16,14 +17,19 @@ export const DropTargetMaskWrapper = styled.div` width: 100%; height: 100%; background: white; - background-image: radial-gradient( - circle, - ${props => props.theme.colors.grid} 2px, - transparent 0 - ); - background-size: ${props => props.columnWidth}px ${props => props.rowHeight}px; - background-position: -${props => props.columnWidth / 2}px -${props => - props.rowHeight / 2}px; + ${props => + props.showGrid && + css` + background-image: radial-gradient( + circle, + ${props => props.theme.colors.grid} 2px, + transparent 0 + ); + background-size: ${props => props.columnWidth}px + ${props => props.rowHeight}px; + background-position: -${props => props.columnWidth / 2}px -${props => + props.rowHeight / 2}px; + `} `; /* eslint-disable react/display-name */ export const DropTargetMask = (props: DropTargetMaskProps) => { @@ -39,7 +45,6 @@ export const DropTargetMask = (props: DropTargetMaskProps) => { props.setBounds(rect); } }); - return ; }; diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index 4b4b1a7160..7ac4e40891 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -57,10 +57,10 @@ export const getDropZoneOffsets = ( const areIntersecting = (r1: Rect, r2: Rect) => { return !( - r2.left > r1.right || - r2.right < r1.left || - r2.top > r1.bottom || - r2.bottom < r1.top + r2.left >= r1.right || + r2.right <= r1.left || + r2.top >= r1.bottom || + r2.bottom <= r1.top ); }; diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index 49f283bfee..ed4deae0e2 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -90,19 +90,7 @@ class ContainerWidget extends BaseWidget< getCanvasView() { const style = this.getPositionStyle(); const occupiedSpaces = this.getOccupiedSpaces(); - const renderDraggableComponent = ( - - - {this.getPageView()} - - - ); - - return ( + const renderComponent = ( - {this.props.parentId ? renderDraggableComponent : this.getPageView()} + {this.getPageView()} ); + const renderDraggableComponent = ( + + + {renderComponent} + + + ); + + return this.props.parentId ? renderDraggableComponent : renderComponent; } getWidgetType(): WidgetType { From da634cacf33a1f10ef4cc1d22e947e9bf4ed0f13 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 21:08:46 +0530 Subject: [PATCH 16/19] Disable controls when resizing --- .../src/editorComponents/DraggableComponent.tsx | 13 +++++++++---- .../src/editorComponents/ResizableComponent.tsx | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index e4b9c3bd6f..749a4beb25 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from "react"; +import React, { useContext, createContext, useState, Context } from "react"; import styled from "styled-components"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; @@ -50,8 +50,13 @@ const deleteControlIcon = ControlIcons.DELETE_CONTROL({ type DraggableComponentProps = WidgetProps & ContainerProps; +export const ResizingContext: Context<{ + setIsResizing?: Function; +}> = createContext({}); + const DraggableComponent = (props: DraggableComponentProps) => { const { isFocused, setFocus } = useContext(FocusContext); + const [isResizing, setIsResizing] = useState(false); const deleteWidget = () => { props.updateWidget && props.updateWidget(WidgetOperations.DELETE, props.widgetId); @@ -64,7 +69,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { }); return ( - + { e.stopPropagation(); } }} - show={props.widgetId === isFocused} + show={props.widgetId === isFocused && !isResizing} style={{ display: isDragging ? "none" : "flex", flexDirection: "column", @@ -99,7 +104,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { {props.children} - + ); }; diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 81f9e8d4f4..8a48390849 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -4,6 +4,7 @@ import { Rnd } from "react-rnd"; import { XYCoord } from "react-dnd"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; +import { ResizingContext } from "./DraggableComponent"; export type ResizableComponentProps = WidgetProps & ContainerProps; @@ -35,6 +36,7 @@ const ResizableContainer = styled(Rnd)` `; export const ResizableComponent = (props: ResizableComponentProps) => { + const { setIsResizing } = useContext(ResizingContext); const { boundingParent } = useContext(ParentBoundsContext); let bounds = "body"; if (boundingParent && boundingParent.current) { @@ -47,6 +49,7 @@ export const ResizableComponent = (props: ResizableComponentProps) => { delta: { width: number; height: number }, position: XYCoord, ) => { + setIsResizing && setIsResizing(false); const leftColumn = props.leftColumn + position.x / props.parentColumnSpace; const topRow = props.topRow + position.y / props.parentRowSpace; @@ -78,6 +81,9 @@ export const ResizableComponent = (props: ResizableComponentProps) => { minHeight={props.parentRowSpace} style={{ ...props.style }} onResizeStop={updateSize} + onResizeStart={() => { + setIsResizing && setIsResizing(true); + }} resizeGrid={[props.parentColumnSpace, props.parentRowSpace]} bounds={bounds} enableResizing={{ From 58c0c647bfd30079203cac1e77ea17eb96e73e34 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 21:54:29 +0530 Subject: [PATCH 17/19] Move WidgetFunctions to Context Provider --- .../editorComponents/DraggableComponent.tsx | 5 ++-- .../editorComponents/DropTargetComponent.tsx | 8 +++--- .../editorComponents/ResizableComponent.tsx | 6 +++-- app/client/src/pages/Editor/Canvas.tsx | 8 +----- app/client/src/pages/Editor/index.tsx | 26 ++++++++++--------- app/client/src/utils/WidgetFactory.tsx | 3 --- app/client/src/utils/WidgetPropsUtils.tsx | 1 - app/client/src/widgets/BaseWidget.tsx | 17 ++++++++---- app/client/src/widgets/ButtonWidget.tsx | 2 +- app/client/src/widgets/ContainerWidget.tsx | 13 ++-------- 10 files changed, 42 insertions(+), 47 deletions(-) diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index 749a4beb25..f45d20d5b6 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -5,6 +5,7 @@ import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "../assets/images/blank.png"; import { ContainerProps } from "./ContainerComponent"; import { FocusContext } from "../pages/Editor/Canvas"; +import { WidgetFunctionsContext } from "../pages/Editor"; import { ControlIcons } from "../icons/ControlIcons"; import { theme } from "../constants/DefaultTheme"; @@ -56,10 +57,10 @@ export const ResizingContext: Context<{ const DraggableComponent = (props: DraggableComponentProps) => { const { isFocused, setFocus } = useContext(FocusContext); + const { updateWidget } = useContext(WidgetFunctionsContext); const [isResizing, setIsResizing] = useState(false); const deleteWidget = () => { - props.updateWidget && - props.updateWidget(WidgetOperations.DELETE, props.widgetId); + updateWidget && updateWidget(WidgetOperations.DELETE, props.widgetId); }; const [{ isDragging }, drag, preview] = useDrag({ item: props, diff --git a/app/client/src/editorComponents/DropTargetComponent.tsx b/app/client/src/editorComponents/DropTargetComponent.tsx index 85a2581d27..c3d96b7881 100644 --- a/app/client/src/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/editorComponents/DropTargetComponent.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useContext } from "react"; import { WidgetProps } from "../widgets/BaseWidget"; import { OccupiedSpace } from "../widgets/ContainerWidget"; import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer"; @@ -7,6 +7,7 @@ import { ContainerProps } from "./ContainerComponent"; import WidgetFactory from "../utils/WidgetFactory"; import { widgetOperationParams, noCollision } from "../utils/WidgetPropsUtils"; import DragLayerComponent from "./DragLayerComponent"; +import { WidgetFunctionsContext } from "../pages/Editor"; type DropTargetComponentProps = ContainerProps & { updateWidget?: Function; @@ -27,14 +28,15 @@ type DropTargetBounds = { export const DropTargetComponent = (props: DropTargetComponentProps) => { // Hook to keep the offset of the drop target container in state const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 }); + const { updateWidget } = useContext(WidgetFunctionsContext); // Make this component a drop target const [{ isOver, isExactlyOver }, drop] = useDrop({ accept: Object.values(WidgetFactory.getWidgetTypes()), drop(widget: WidgetProps & Partial, monitor) { // Make sure we're dropping in this container. if (isOver) { - props.updateWidget && - props.updateWidget( + updateWidget && + updateWidget( ...widgetOperationParams( widget, monitor.getClientOffset() as XYCoord, diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 8a48390849..1ceaab6679 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -5,6 +5,7 @@ import { XYCoord } from "react-dnd"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; import { ResizingContext } from "./DraggableComponent"; +import { WidgetFunctionsContext } from "../pages/Editor"; export type ResizableComponentProps = WidgetProps & ContainerProps; @@ -38,6 +39,7 @@ const ResizableContainer = styled(Rnd)` export const ResizableComponent = (props: ResizableComponentProps) => { const { setIsResizing } = useContext(ResizingContext); const { boundingParent } = useContext(ParentBoundsContext); + const { updateWidget } = useContext(WidgetFunctionsContext); let bounds = "body"; if (boundingParent && boundingParent.current) { bounds = "." + boundingParent.current.className.split(" ")[1]; @@ -58,8 +60,8 @@ export const ResizableComponent = (props: ResizableComponentProps) => { const bottomRow = props.bottomRow + (delta.height + position.y) / props.parentRowSpace; - props.updateWidget && - props.updateWidget(WidgetOperations.RESIZE, props.widgetId, { + updateWidget && + updateWidget(WidgetOperations.RESIZE, props.widgetId, { leftColumn, rightColumn, topRow, diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index a3e88c5a2e..a5e9350d9a 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -8,7 +8,6 @@ import React, { import styled from "styled-components"; import WidgetFactory from "../../utils/WidgetFactory"; import { RenderModes } from "../../constants/WidgetConstants"; -import { WidgetFunctions } from "../../widgets/BaseWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; import { WidgetProps } from "../../widgets/BaseWidget"; @@ -21,7 +20,6 @@ const ArtBoard = styled.div` interface CanvasProps { dsl: ContainerWidgetProps; - widgetFunctions: WidgetFunctions; } export const FocusContext: Context<{ @@ -35,11 +33,7 @@ const Canvas = (props: CanvasProps) => { {props.dsl.widgetId && - WidgetFactory.createWidget( - props.dsl, - props.widgetFunctions, - RenderModes.CANVAS, - )} + WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)} ); diff --git a/app/client/src/pages/Editor/index.tsx b/app/client/src/pages/Editor/index.tsx index a4c781d9ee..086ad989b5 100644 --- a/app/client/src/pages/Editor/index.tsx +++ b/app/client/src/pages/Editor/index.tsx @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component, Context, createContext } from "react"; import { connect } from "react-redux"; import styled from "styled-components"; import Canvas from "./Canvas"; @@ -6,6 +6,7 @@ import { WidgetCardProps, WidgetProps, WidgetOperation, + WidgetFunctions, } from "../../widgets/BaseWidget"; import { AppState } from "../../reducers"; import { EditorReduxState } from "../../reducers/uiReducers/editorReducer"; @@ -61,6 +62,10 @@ type EditorProps = { isSaving: boolean; }; +export const WidgetFunctionsContext: Context = createContext( + {}, +); + class Editor extends Component { componentDidMount() { this.props.fetchCanvasWidgets(this.props.currentPageId); @@ -68,7 +73,12 @@ class Editor extends Component { public render() { return ( - + { - {this.props.dsl && ( - - )} + {this.props.dsl && } - + ); } } diff --git a/app/client/src/utils/WidgetFactory.tsx b/app/client/src/utils/WidgetFactory.tsx index 9ca0c0adcd..bbac31556b 100644 --- a/app/client/src/utils/WidgetFactory.tsx +++ b/app/client/src/utils/WidgetFactory.tsx @@ -2,7 +2,6 @@ import { WidgetType, RenderMode } from "../constants/WidgetConstants"; import { WidgetBuilder, WidgetProps, - WidgetFunctions, WidgetDataProps, } from "../widgets/BaseWidget"; @@ -18,13 +17,11 @@ class WidgetFactory { static createWidget( widgetData: WidgetDataProps, - widgetFunctions: WidgetFunctions, renderMode: RenderMode, ): JSX.Element { const widgetProps: WidgetProps = { key: widgetData.widgetId, renderMode: renderMode, - ...widgetFunctions, ...widgetData, }; const widgetBuilder = this.widgetMap.get(widgetData.type); diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index 7ac4e40891..5395d90b88 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -237,7 +237,6 @@ export const generateWidgetProps = ( return { ...widgetConfig, type, - executeAction: () => {}, widgetId: generateReactKey(), widgetName: widgetName || generateReactKey(), //TODO: figure out what this is to populate appropriately isVisible: true, diff --git a/app/client/src/widgets/BaseWidget.tsx b/app/client/src/widgets/BaseWidget.tsx index 7ca2745541..f67fbf8bcf 100644 --- a/app/client/src/widgets/BaseWidget.tsx +++ b/app/client/src/widgets/BaseWidget.tsx @@ -9,16 +9,16 @@ import { RenderModes, CSSUnits, } from "../constants/WidgetConstants"; -import { Component } from "react"; +import React, { Component } from "react"; import { BaseStyle } from "../editorComponents/BaseComponent"; import _ from "lodash"; -import React from "react"; import DraggableComponent from "../editorComponents/DraggableComponent"; import ResizableComponent from "../editorComponents/ResizableComponent"; import { ActionPayload } from "../constants/ActionConstants"; +import { WidgetFunctionsContext } from "../pages/Editor"; abstract class BaseWidget< - T extends WidgetProps & WidgetFunctions, + T extends WidgetProps, K extends WidgetState > extends Component { constructor(props: T) { @@ -32,6 +32,13 @@ abstract class BaseWidget< this.state = initialState as K; } + static contextType = WidgetFunctionsContext; + + executeAction(actionPayloads?: ActionPayload[]): void { + const { executeAction } = this.context; + executeAction && executeAction(actionPayloads); + } + componentDidMount(): void { this.calculateWidgetBounds( this.props.rightColumn, @@ -142,7 +149,7 @@ export interface WidgetBuilder { buildWidget(widgetProps: T): JSX.Element; } -export interface WidgetProps extends WidgetFunctions, WidgetDataProps { +export interface WidgetProps extends WidgetDataProps { key?: string; renderMode: RenderMode; } @@ -162,7 +169,7 @@ export interface WidgetDataProps { } export interface WidgetFunctions { - executeAction: (actionPayloads?: ActionPayload[]) => void; + executeAction?: (actionPayloads?: ActionPayload[]) => void; updateWidget?: Function; } diff --git a/app/client/src/widgets/ButtonWidget.tsx b/app/client/src/widgets/ButtonWidget.tsx index 75f56b8b39..8967c0df80 100644 --- a/app/client/src/widgets/ButtonWidget.tsx +++ b/app/client/src/widgets/ButtonWidget.tsx @@ -6,7 +6,7 @@ import { ActionPayload } from "../constants/ActionConstants"; class ButtonWidget extends BaseWidget { onButtonClick() { - this.props.executeAction(this.props.onClick); + super.executeAction(this.props.onClick); } getPageView() { diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index ed4deae0e2..ec1ded6bb3 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -1,9 +1,5 @@ import React from "react"; -import BaseWidget, { - WidgetProps, - WidgetState, - WidgetFunctions, -} from "./BaseWidget"; +import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget"; import ContainerComponent from "../editorComponents/ContainerComponent"; import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants"; import WidgetFactory from "../utils/WidgetFactory"; @@ -51,12 +47,7 @@ class ContainerWidget extends BaseWidget< childWidgetData.parentColumnSpace = this.state.snapColumnSpace; childWidgetData.parentRowSpace = this.state.snapRowSpace; childWidgetData.parentId = this.props.widgetId; - const widgetFunctions: WidgetFunctions = this.props as WidgetFunctions; - return WidgetFactory.createWidget( - childWidgetData, - widgetFunctions, - this.props.renderMode, - ); + return WidgetFactory.createWidget(childWidgetData, this.props.renderMode); } getPageView() { From eb195aa321449c3d7460d81066ce14ce435e1437 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 22:36:44 +0530 Subject: [PATCH 18/19] Get new widget name based on widget configs --- .../src/mockResponses/WidgetConfigResponse.tsx | 13 +++++++++++++ app/client/src/sagas/WidgetOperationSagas.tsx | 2 +- app/client/src/utils/AppsmithUtils.tsx | 18 +++++++----------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/client/src/mockResponses/WidgetConfigResponse.tsx b/app/client/src/mockResponses/WidgetConfigResponse.tsx index efff9f0c9f..f63cf16dd6 100644 --- a/app/client/src/mockResponses/WidgetConfigResponse.tsx +++ b/app/client/src/mockResponses/WidgetConfigResponse.tsx @@ -7,12 +7,14 @@ const WidgetConfigResponse: WidgetConfigReducerState = { buttonStyle: "PRIMARY_BUTTON", rows: 1, columns: 2, + widgetName: "Button", }, TEXT_WIDGET: { text: "Not all labels are bad!", textStyle: "LABEL", rows: 1, columns: 3, + widgetName: "Text", }, IMAGE_WIDGET: { defaultImage: "", @@ -20,27 +22,32 @@ const WidgetConfigResponse: WidgetConfigReducerState = { image: "", rows: 3, columns: 3, + widgetName: "Image", }, INPUT_WIDGET: { inputType: "TEXT", label: "Label me", rows: 1, columns: 3, + widgetName: "Input", }, SWITCH_WIDGET: { isOn: false, label: "Turn me on", rows: 1, columns: 4, + widgetName: "Switch", }, CONTAINER_WIDGET: { backgroundColor: "#FFFFFF", rows: 1, columns: 4, + widgetName: "Container", }, SPINNER_WIDGET: { rows: 1, columns: 1, + widgetName: "Spinner", }, DATE_PICKER_WIDGET: { enableTime: false, @@ -48,23 +55,27 @@ const WidgetConfigResponse: WidgetConfigReducerState = { rows: 1, columns: 3, label: "Date", + widgetName: "Datepicker", }, TABLE_WIDGET: { rows: 5, columns: 7, label: "Don't table me!", + widgetName: "Table", }, DROP_DOWN_WIDGET: { rows: 1, columns: 3, selectionType: "SINGLE_SELECT", label: "Pick me!", + widgetName: "Dropdown", }, CHECKBOX_WIDGET: { rows: 1, columns: 3, label: "Label - CHECK!", defaultCheckedState: true, + widgetName: "Checkbox", }, RADIO_GROUP_WIDGET: { rows: 3, @@ -76,6 +87,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = { { label: "Charlie", value: "3" }, ], defaultOptionValue: "1", + widgetName: "RadioGroup", }, ALERT_WIDGET: { alertType: "NOTIFICATION", @@ -84,6 +96,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = { columns: 3, header: "", message: "", + widgetName: "Alert", }, }, configVersion: 1, diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index c5e856738c..1c5a08634d 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -47,7 +47,7 @@ export function* addChildSaga(addChildAction: ReduxAction) { rows, parentRowSpace, parentColumnSpace, - getNextWidgetName(type, widgets), + getNextWidgetName(defaultWidgetConfig.widgetName, widgets), defaultWidgetConfig, ); widgets[childWidget.widgetId] = childWidget; diff --git a/app/client/src/utils/AppsmithUtils.tsx b/app/client/src/utils/AppsmithUtils.tsx index ba3636bba0..dbd83854b3 100644 --- a/app/client/src/utils/AppsmithUtils.tsx +++ b/app/client/src/utils/AppsmithUtils.tsx @@ -12,7 +12,6 @@ import FontFaceObserver from "fontfaceobserver"; import PropertyControlRegistry from "./PropertyControlRegistry"; import WidgetBuilderRegistry from "./WidgetRegistry"; import { Property } from "../api/ActionAPI"; -import { WidgetType } from "../constants/WidgetConstants"; import { FlattenedWidgetProps } from "../reducers/entityReducers/canvasWidgetsReducer"; import _ from "lodash"; @@ -64,21 +63,18 @@ export const mapToPropList = (map: Record): Property[] => { }; export const getNextWidgetName = ( - type: WidgetType, + prefix: string, widgets: { [id: string]: FlattenedWidgetProps; }, ) => { - const prefix = type - .split("_") - .filter(token => token !== "WIDGET") - .join("") - .toLowerCase(); + const regex = new RegExp(`^${prefix}(\\d+)$`); const usedIndices: number[] = Object.values(widgets).map(widget => { - if (widget.type === type) { - const ind = widget.widgetName - ? parseInt(widget.widgetName.split(prefix)[1], 10) - : 0; + if (widget && widget.widgetName && regex.test(widget.widgetName)) { + const name = widget.widgetName || ""; + const matches = name.match(regex); + const ind = + matches && Array.isArray(matches) ? parseInt(matches[1], 10) : 0; return Number.isNaN(ind) ? 0 : ind; } return 0; From 72443b0b0668218c1e6194696e4868a0e97f70f7 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 3 Oct 2019 23:05:13 +0530 Subject: [PATCH 19/19] Use parentId to delete and move --- app/client/src/actions/pageActions.tsx | 6 ++-- .../editorComponents/DraggableComponent.tsx | 5 +++- app/client/src/sagas/WidgetOperationSagas.tsx | 29 ++++++++++--------- app/client/src/sagas/selectors.tsx | 14 --------- app/client/src/utils/WidgetPropsUtils.tsx | 3 +- 5 files changed, 25 insertions(+), 32 deletions(-) diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index 29d9137f59..248edb4d5f 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -92,12 +92,13 @@ export type WidgetMove = { widgetId: string; leftColumn: number; topRow: number; + parentId: string; /* - If parentWidgetId 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. */ - parentWidgetId: string; + newParentId: string; }; export type WidgetRemoveChild = { @@ -107,6 +108,7 @@ export type WidgetRemoveChild = { export type WidgetDelete = { widgetId: string; + parentId: string; }; export type WidgetResize = { diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index f45d20d5b6..11892cfbfb 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -60,7 +60,10 @@ const DraggableComponent = (props: DraggableComponentProps) => { const { updateWidget } = useContext(WidgetFunctionsContext); const [isResizing, setIsResizing] = useState(false); const deleteWidget = () => { - updateWidget && updateWidget(WidgetOperations.DELETE, props.widgetId); + updateWidget && + updateWidget(WidgetOperations.DELETE, props.widgetId, { + parentId: props.parentId, + }); }; const [{ isDragging }, drag, preview] = useDrag({ item: props, diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index 1c5a08634d..d7c42a9c2d 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -10,12 +10,7 @@ import { WidgetDelete, } from "../actions/pageActions"; import { FlattenedWidgetProps } from "../reducers/entityReducers/canvasWidgetsReducer"; -import { - getWidgets, - getWidget, - getWidgetParent, - getDefaultWidgetConfig, -} from "./selectors"; +import { getWidgets, getWidget, getDefaultWidgetConfig } from "./selectors"; import { generateWidgetProps, updateWidgetPosition, @@ -72,14 +67,14 @@ export function* addChildSaga(addChildAction: ReduxAction) { export function* deleteSaga(deleteAction: ReduxAction) { try { - const { widgetId } = deleteAction.payload; + const { widgetId, parentId } = deleteAction.payload; const widgets = yield select(getWidgets); - delete widgets[widgetId]; - const parent = yield select(getWidgetParent, widgetId); + const parent = yield select(getWidget, parentId); parent.children = parent.children.filter( (child: string) => child !== widgetId, ); - widgets[parent.widgetId] = parent; + delete widgets[widgetId]; + widgets[parentId] = parent; yield put({ type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets }, @@ -97,25 +92,31 @@ export function* deleteSaga(deleteAction: ReduxAction) { export function* moveSaga(moveAction: ReduxAction) { try { - const { widgetId, leftColumn, topRow, parentWidgetId } = moveAction.payload; + const { + widgetId, + leftColumn, + topRow, + parentId, + newParentId, + } = moveAction.payload; let widget: FlattenedWidgetProps = yield select(getWidget, widgetId); // Get all widgets from DSL/Redux Store const widgets = yield select(getWidgets) as any; // Get parent from DSL/Redux Store - const parent = yield select(getWidgetParent, widgetId); + const parent = yield select(getWidget, parentId); // Update position of widget widget = updateWidgetPosition(widget, leftColumn, topRow, parent); // Replace widget with update widget props widgets[widgetId] = widget; // If the parent has changed i.e parentWidgetId is not parent.widgetId - if (parent.widgetId !== parentWidgetId && widgetId !== parentWidgetId) { + if (parent.widgetId !== newParentId && widgetId !== newParentId) { // Remove from the previous parent parent.children = parent.children.filter( (child: string) => child !== widgetId, ); widgets[parent.widgetId] = parent; // Add to new parent - widgets[parentWidgetId].children.push(widgetId); + widgets[newParentId].children.push(widgetId); } yield put({ type: ReduxActionTypes.UPDATE_LAYOUT, diff --git a/app/client/src/sagas/selectors.tsx b/app/client/src/sagas/selectors.tsx index fc1c5eacf8..86fa24db4c 100644 --- a/app/client/src/sagas/selectors.tsx +++ b/app/client/src/sagas/selectors.tsx @@ -22,20 +22,6 @@ export const getEditorConfigs = ( }; }; -export const getWidgetParent = ( - state: AppState, - widgetId: string, -): FlattenedWidgetProps | undefined => { - const widgets = state.entities.canvasWidgets; - return Object.values(widgets).find( - (widget: FlattenedWidgetProps) => - widget && - widget.children && - widget.children.length > 0 && - widget.children.indexOf(widgetId) > -1, - ); -}; - export const getDefaultWidgetConfig = ( state: AppState, type: WidgetType, diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index 5395d90b88..3e974980f8 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -142,7 +142,8 @@ export const widgetOperationParams = ( { leftColumn, topRow, - parentWidgetId: widgetId, + parentId: widget.parentId, + newParentId: widgetId, }, ]; // If this is not an existing widget, we'll not have the widgetId