diff --git a/app/client/.gitignore b/app/client/.gitignore index 436ff4fe1b..0a4e9d9f84 100755 --- a/app/client/.gitignore +++ b/app/client/.gitignore @@ -26,3 +26,4 @@ yarn-error.log* /out /public/fonts/* /src/assets/icons/fonts/* +.idea diff --git a/app/client/src/constants/DefaultTheme.tsx b/app/client/src/constants/DefaultTheme.tsx index 45bb80c526..3c73994142 100644 --- a/app/client/src/constants/DefaultTheme.tsx +++ b/app/client/src/constants/DefaultTheme.tsx @@ -35,7 +35,7 @@ export const getColorWithOpacity = (color: Color, opacity: number) => { export const theme: Theme = { radii: [0, 4, 8, 10, 20, 50], fontSizes: [0, 10, 12, 14, 16, 18, 24, 28, 32, 48, 64], - spaces: [0, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24], + spaces: [0, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 30], fontWeights: [0, 400, 500, 700], colors: { primary: Colors.GREEN, diff --git a/app/client/src/constants/errors.ts b/app/client/src/constants/errors.ts new file mode 100644 index 0000000000..e7b8e60938 --- /dev/null +++ b/app/client/src/constants/errors.ts @@ -0,0 +1,3 @@ +export const DEFAULT_ERROR_MESSAGE = "There was an error"; +export const DEFAULT_ACTION_ERROR = (action: string) => + `Incurred an error when ${action}`; diff --git a/app/client/src/editorComponents/DraggableComponent.tsx b/app/client/src/editorComponents/DraggableComponent.tsx index 689efd4f8e..094419b62a 100644 --- a/app/client/src/editorComponents/DraggableComponent.tsx +++ b/app/client/src/editorComponents/DraggableComponent.tsx @@ -51,8 +51,9 @@ const deleteControlIcon = ControlIcons.DELETE_CONTROL({ type DraggableComponentProps = WidgetProps & ContainerProps; -export const ResizingContext: Context<{ +export const RnDContext: Context<{ setIsResizing?: Function; + isDragging?: boolean; }> = createContext({}); const DraggableComponent = (props: DraggableComponentProps) => { @@ -70,13 +71,16 @@ const DraggableComponent = (props: DraggableComponentProps) => { collect: (monitor: DragSourceMonitor) => ({ isDragging: monitor.isDragging(), }), + canDrag: () => { + return !isResizing && !!isFocused && isFocused === props.widgetId; + }, }); return ( - + { if (setFocus) { setFocus(props.widgetId); @@ -108,7 +112,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { {deleteControlIcon} - + ); }; diff --git a/app/client/src/editorComponents/ResizableComponent.tsx b/app/client/src/editorComponents/ResizableComponent.tsx index 1589eb170e..b68a1e2b07 100644 --- a/app/client/src/editorComponents/ResizableComponent.tsx +++ b/app/client/src/editorComponents/ResizableComponent.tsx @@ -6,8 +6,8 @@ import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { OccupiedSpaceContext } from "../widgets/ContainerWidget"; import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; import { isDropZoneOccupied } from "../utils/WidgetPropsUtils"; -import { ResizingContext } from "./DraggableComponent"; import { FocusContext } from "../pages/Editor/Canvas"; +import { RnDContext } from "./DraggableComponent"; import { WidgetFunctionsContext } from "../pages/Editor"; import { theme, getColorWithOpacity } from "../constants/DefaultTheme"; @@ -63,7 +63,7 @@ const ResizableContainer = styled(Rnd)` `; export const ResizableComponent = (props: ResizableComponentProps) => { - const { setIsResizing } = useContext(ResizingContext); + const { setIsResizing, isDragging } = useContext(RnDContext); const { boundingParent } = useContext(ParentBoundsContext); const { updateWidget } = useContext(WidgetFunctionsContext); const { setFocus } = useContext(FocusContext); @@ -165,13 +165,13 @@ export const ResizableComponent = (props: ResizableComponentProps) => { bounds={bounds} resizeHandleStyles={handleStyles} enableResizing={{ - top: true, - right: true, - bottom: true, - left: true, + top: true && !isDragging, + right: true && !isDragging, + bottom: true && !isDragging, + left: true && !isDragging, topRight: false, topLeft: false, - bottomRight: true, + bottomRight: true && !isDragging, bottomLeft: false, }} > diff --git a/app/client/src/editorComponents/ToastComponent.tsx b/app/client/src/editorComponents/ToastComponent.tsx new file mode 100644 index 0000000000..9376e93940 --- /dev/null +++ b/app/client/src/editorComponents/ToastComponent.tsx @@ -0,0 +1,7 @@ +import { Position, Toaster } from "@blueprintjs/core"; + +// To add a toast import this instance and call .show() +// https://blueprintjs.com/docs/#core/components/toast.example +export default Toaster.create({ + position: Position.BOTTOM_RIGHT, +}); diff --git a/app/client/src/sagas/ErrorSagas.tsx b/app/client/src/sagas/ErrorSagas.tsx index 754999101f..4f66de37a6 100644 --- a/app/client/src/sagas/ErrorSagas.tsx +++ b/app/client/src/sagas/ErrorSagas.tsx @@ -1,9 +1,15 @@ +import _ from "lodash"; +import { Intent } from "@blueprintjs/core"; import { ReduxActionTypes, ReduxActionErrorTypes, ReduxAction, } from "../constants/ReduxActionConstants"; - +import AppToaster from "../editorComponents/ToastComponent"; +import { + DEFAULT_ERROR_MESSAGE, + DEFAULT_ACTION_ERROR, +} from "../constants/errors"; import { ApiResponse } from "../api/ApiResponses"; import { put, takeLatest } from "redux-saga/effects"; @@ -21,10 +27,34 @@ export function* validateResponse(response: ApiResponse) { } } -export function* errorSaga(errorAction: ReduxAction<{ error: any }>) { +type ErrorPayloadType = object | { message: string }; + +const ActionErrorDisplayMap: { + [key: string]: (error: ErrorPayloadType) => string; +} = { + [ReduxActionErrorTypes.API_ERROR]: error => + _.get(error, "message", DEFAULT_ERROR_MESSAGE), + [ReduxActionErrorTypes.FETCH_PAGE_ERROR]: () => + DEFAULT_ACTION_ERROR("fetching the page"), + [ReduxActionErrorTypes.SAVE_PAGE_ERROR]: () => + DEFAULT_ACTION_ERROR("saving the page"), + [ReduxActionErrorTypes.FETCH_WIDGET_CARDS_ERROR]: () => DEFAULT_ERROR_MESSAGE, + [ReduxActionErrorTypes.WIDGET_OPERATION_ERROR]: () => DEFAULT_ERROR_MESSAGE, +}; + +export function* errorSaga( + errorAction: ReduxAction<{ error: ErrorPayloadType }>, +) { // Just a pass through for now. // Add procedures to customize errors here - console.log(errorAction.payload.error); + console.log({ error: errorAction }); + // Show a toast when the error occurs + const { + type, + payload: { error }, + } = errorAction; + const message = ActionErrorDisplayMap[type](error); + AppToaster.show({ message, intent: Intent.DANGER }); yield put({ type: ReduxActionTypes.REPORT_ERROR, payload: {