From ed2ecadbc4b03f029cb04cb6a0d493d3e9ae48d9 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Mon, 16 Dec 2019 08:49:10 +0000 Subject: [PATCH] User Auth Flow --- app/client/.eslintrc.js | 2 +- app/client/package.json | 6 +- app/client/public/index.html | 5 +- app/client/src/api/ActionAPI.tsx | 2 +- app/client/src/api/Api.tsx | 60 +- app/client/src/api/PageApi.tsx | 1 - app/client/src/api/UserApi.tsx | 67 + app/client/src/assets/images/Github.png | Bin 0 -> 4268 bytes app/client/src/assets/images/Google.png | Bin 0 -> 11446 bytes .../appsmith/TextInputComponent.tsx | 1 + .../designSystems/blueprint/Checkbox.tsx | 41 + .../editorComponents/ContextDropdown.tsx | 4 +- .../components/editorComponents/Divider.tsx | 10 + .../src/components/editorComponents/Form.tsx | 8 + .../editorComponents/FormButton.tsx | 28 + .../components/editorComponents/FormGroup.tsx | 8 + .../components/editorComponents/Spinner.tsx | 3 + .../editorComponents/form/MessageTag.tsx | 86 + .../form/fields/CheckboxField.tsx | 10 + .../form/fields/TextField.tsx | 16 +- app/client/src/configs/dev.config.ts | 5 +- app/client/src/configs/index.ts | 2 +- app/client/src/configs/prod.config.ts | 5 +- app/client/src/configs/stage.config.ts | 5 +- app/client/src/configs/types.ts | 1 + app/client/src/constants/ApiConstants.tsx | 21 +- app/client/src/constants/Colors.tsx | 1 + app/client/src/constants/DefaultTheme.tsx | 53 +- .../src/constants/ReduxActionConstants.tsx | 16 + app/client/src/constants/SocialLogin.tsx | 44 + app/client/src/constants/forms.ts | 4 + app/client/src/constants/messages.ts | 74 + app/client/src/constants/routes.ts | 7 +- app/client/src/index.css | 4 + app/client/src/index.tsx | 9 +- .../Applications/CreateApplicationForm.tsx | 11 +- app/client/src/pages/Applications/helpers.ts | 24 + .../src/pages/UserAuth/ForgotPassword.tsx | 119 + app/client/src/pages/UserAuth/Login.tsx | 162 ++ .../src/pages/UserAuth/ResetPassword.tsx | 224 ++ app/client/src/pages/UserAuth/SignUp.tsx | 145 ++ .../src/pages/UserAuth/StyledComponents.tsx | 110 + .../src/pages/UserAuth/ThirdPartyAuth.tsx | 87 + app/client/src/pages/UserAuth/helpers.ts | 85 + app/client/src/pages/UserAuth/index.tsx | 43 + app/client/src/pages/common/LoginPage.tsx | 15 - .../src/pages/common/ProtectedRoute.tsx | 17 +- app/client/src/reducers/index.tsx | 2 + .../src/reducers/uiReducers/authReducer.ts | 32 + .../src/reducers/uiReducers/editorReducer.tsx | 6 +- app/client/src/reducers/uiReducers/index.tsx | 2 + app/client/src/sagas/ErrorSagas.tsx | 28 +- app/client/src/sagas/index.tsx | 2 + app/client/src/sagas/userSagas.tsx | 168 ++ app/client/src/selectors/authSelectors.tsx | 5 + app/client/src/utils/AppsmithUtils.tsx | 6 +- app/client/src/utils/formhelpers.ts | 36 +- app/client/yarn.lock | 2241 +++++++---------- 58 files changed, 2758 insertions(+), 1421 deletions(-) create mode 100644 app/client/src/api/UserApi.tsx create mode 100644 app/client/src/assets/images/Github.png create mode 100644 app/client/src/assets/images/Google.png create mode 100644 app/client/src/components/designSystems/blueprint/Checkbox.tsx create mode 100644 app/client/src/components/editorComponents/Divider.tsx create mode 100644 app/client/src/components/editorComponents/Form.tsx create mode 100644 app/client/src/components/editorComponents/FormButton.tsx create mode 100644 app/client/src/components/editorComponents/FormGroup.tsx create mode 100644 app/client/src/components/editorComponents/Spinner.tsx create mode 100644 app/client/src/components/editorComponents/form/MessageTag.tsx create mode 100644 app/client/src/components/editorComponents/form/fields/CheckboxField.tsx create mode 100644 app/client/src/constants/SocialLogin.tsx create mode 100644 app/client/src/pages/Applications/helpers.ts create mode 100644 app/client/src/pages/UserAuth/ForgotPassword.tsx create mode 100644 app/client/src/pages/UserAuth/Login.tsx create mode 100644 app/client/src/pages/UserAuth/ResetPassword.tsx create mode 100644 app/client/src/pages/UserAuth/SignUp.tsx create mode 100644 app/client/src/pages/UserAuth/StyledComponents.tsx create mode 100644 app/client/src/pages/UserAuth/ThirdPartyAuth.tsx create mode 100644 app/client/src/pages/UserAuth/helpers.ts create mode 100644 app/client/src/pages/UserAuth/index.tsx delete mode 100644 app/client/src/pages/common/LoginPage.tsx create mode 100644 app/client/src/reducers/uiReducers/authReducer.ts create mode 100644 app/client/src/sagas/userSagas.tsx create mode 100644 app/client/src/selectors/authSelectors.tsx diff --git a/app/client/.eslintrc.js b/app/client/.eslintrc.js index 805048b859..4518ef96ce 100644 --- a/app/client/.eslintrc.js +++ b/app/client/.eslintrc.js @@ -16,7 +16,7 @@ module.exports = { }, rules: { "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/no-explicit-any": 0 + "@typescript-eslint/no-explicit-any": 0, }, settings: { react: { diff --git a/app/client/package.json b/app/client/package.json index 3df7d547cb..c8dad3cf4c 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -19,7 +19,6 @@ "@types/lodash": "^4.14.120", "@types/moment-timezone": "^0.5.10", "@types/nanoid": "^2.0.0", - "@types/netlify-identity-widget": "^1.4.1", "@types/node": "^10.12.18", "@types/react": "^16.8.2", "@types/react-dom": "^16.8.0", @@ -27,6 +26,7 @@ "@types/react-redux": "^7.0.1", "@types/react-router-dom": "^5.1.2", "@types/styled-components": "^4.1.8", + "@types/tinycolor2": "^1.4.2", "@uppy/core": "^1.5.1", "@uppy/file-input": "^1.3.1", "@uppy/google-drive": "^1.3.2", @@ -50,7 +50,6 @@ "monaco-editor": "^0.15.1", "monaco-editor-webpack-plugin": "^1.7.0", "nanoid": "^2.0.4", - "netlify-identity-widget": "^1.5.5", "node-sass": "^4.11.0", "normalizr": "^3.3.0", "popper.js": "^1.15.0", @@ -64,13 +63,13 @@ "react-dom": "^16.7.0", "react-helmet": "^5.2.1", "react-monaco-editor": "^0.31.1", - "react-netlify-identity": "^0.1.9", "react-redux": "^6.0.0", "react-rnd": "^10.1.1", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", "react-scripts": "^3.1.1", "react-select": "^3.0.8", + "react-transition-group": "^4.3.0", "react-simple-tree-menu": "^1.1.9", "react-tabs": "^3.0.0", "redux": "^4.0.1", @@ -80,6 +79,7 @@ "shallowequal": "^1.1.0", "source-map-explorer": "^2.1.1", "styled-components": "^4.1.3", + "tinycolor2": "^1.4.1", "ts-loader": "^6.0.4", "typescript": "^3.6.3" }, diff --git a/app/client/public/index.html b/app/client/public/index.html index 2b9d087f2d..ec593cba40 100755 --- a/app/client/public/index.html +++ b/app/client/public/index.html @@ -2,7 +2,6 @@ - @@ -11,6 +10,10 @@ + + + + diff --git a/app/client/src/api/ActionAPI.tsx b/app/client/src/api/ActionAPI.tsx index 266e4ff0cc..f04e7522c4 100644 --- a/app/client/src/api/ActionAPI.tsx +++ b/app/client/src/api/ActionAPI.tsx @@ -112,7 +112,7 @@ class ActionAPI extends API { static updateAPI( apiConfig: Partial, ): AxiosPromise { - return API.put(`${ActionAPI.url}/${apiConfig.id}`, null, apiConfig); + return API.put(`${ActionAPI.url}/${apiConfig.id}`, apiConfig); } static deleteAction(id: string) { diff --git a/app/client/src/api/Api.tsx b/app/client/src/api/Api.tsx index a2736a456e..ace2e70327 100644 --- a/app/client/src/api/Api.tsx +++ b/app/client/src/api/Api.tsx @@ -1,21 +1,23 @@ import _ from "lodash"; -import axios from "axios"; +import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; import { getAppsmithConfigs } from "configs"; import { REQUEST_TIMEOUT_MS, - REQUEST_HEADERS, - AUTH_CREDENTIALS, + API_REQUEST_HEADERS, } from "constants/ApiConstants"; import { ActionApiResponse } from "./ActionAPI"; -const { apiUrl } = getAppsmithConfigs(); +import { AUTH_LOGIN_URL } from "constants/routes"; +const { apiUrl, baseUrl } = getAppsmithConfigs(); -const axiosInstance = axios.create({ - baseURL: apiUrl, +//TODO(abhinav): Refactor this to make more composable. +export const apiRequestConfig = { + baseURL: baseUrl + apiUrl, timeout: REQUEST_TIMEOUT_MS, - headers: REQUEST_HEADERS, + headers: API_REQUEST_HEADERS, withCredentials: true, - auth: AUTH_CREDENTIALS, -}); +}; + +const axiosInstance: AxiosInstance = axios.create(); const executeActionRegex = /actions\/execute/; axiosInstance.interceptors.request.use((config: any) => { @@ -45,9 +47,13 @@ axiosInstance.interceptors.response.use( if (error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx - console.log(error.response.data); - console.log(error.response.status); - console.log(error.response.headers); + // console.log(error.response.data); + // console.log(error.response.status); + // console.log(error.response.headers); + if (error.response.status === 401) { + window.location.href = AUTH_LOGIN_URL; + } + return Promise.reject(error.response.data); } else if (error.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of @@ -63,29 +69,51 @@ axiosInstance.interceptors.response.use( ); class Api { - static get(url: string, queryParams?: any) { + static get( + url: string, + queryParams?: any, + config?: Partial, + ) { return axiosInstance.get( url + this.convertObjectToQueryParams(queryParams), + _.merge(apiRequestConfig, config), ); } - static post(url: string, body?: any, queryParams?: any) { + static post( + url: string, + body?: any, + queryParams?: any, + config?: Partial, + ) { return axiosInstance.post( url + this.convertObjectToQueryParams(queryParams), body, + _.merge(apiRequestConfig, config), ); } - static put(url: string, queryParams?: any, body?: any) { + static put( + url: string, + body?: any, + queryParams?: any, + config?: Partial, + ) { return axiosInstance.put( url + this.convertObjectToQueryParams(queryParams), body, + _.merge(apiRequestConfig, config), ); } - static delete(url: string, queryParams?: any) { + static delete( + url: string, + queryParams?: any, + config?: Partial, + ) { return axiosInstance.delete( url + this.convertObjectToQueryParams(queryParams), + _.merge(apiRequestConfig, config), ); } diff --git a/app/client/src/api/PageApi.tsx b/app/client/src/api/PageApi.tsx index 3330c7f79f..0715fc5667 100644 --- a/app/client/src/api/PageApi.tsx +++ b/app/client/src/api/PageApi.tsx @@ -89,7 +89,6 @@ class PageApi extends Api { savePageRequest.pageId, savePageRequest.layoutId, ), - undefined, body, ); } diff --git a/app/client/src/api/UserApi.tsx b/app/client/src/api/UserApi.tsx new file mode 100644 index 0000000000..5cd9080f1d --- /dev/null +++ b/app/client/src/api/UserApi.tsx @@ -0,0 +1,67 @@ +import { AxiosPromise } from "axios"; +import Api from "./Api"; +import { ApiResponse } from "./ApiResponses"; + +export interface LoginUserRequest { + email: string; + password: string; +} + +export interface CreateUserRequest { + email: string; + password: string; +} + +export interface CreateUserResponse extends ApiResponse { + email: string; + id: string; +} + +export interface ForgotPasswordRequest { + email: string; +} + +export interface ResetPasswordRequest { + token: string; + user: { + password: string; + email: string; + }; +} + +export interface ResetPasswordVerifyTokenRequest { + email: string; + token: string; +} + +class UserApi extends Api { + static createURL = "v1/users"; + static forgotPasswordURL = "v1/users/forgotPassword"; + static verifyResetPasswordTokenURL = "v1/users/verifyPasswordResetToken"; + static resetPasswordURL = "v1/users/resetPassword"; + static createUser( + request: CreateUserRequest, + ): AxiosPromise { + return Api.post(UserApi.createURL, request); + } + + static forgotPassword( + request: ForgotPasswordRequest, + ): AxiosPromise { + return Api.get(UserApi.forgotPasswordURL, request); + } + + static resetPassword( + request: ResetPasswordRequest, + ): AxiosPromise { + return Api.put(UserApi.resetPasswordURL, request); + } + + static verifyResetPasswordToken( + request: ResetPasswordVerifyTokenRequest, + ): AxiosPromise { + return Api.get(UserApi.verifyResetPasswordTokenURL, request); + } +} + +export default UserApi; diff --git a/app/client/src/assets/images/Github.png b/app/client/src/assets/images/Github.png new file mode 100644 index 0000000000000000000000000000000000000000..ea6ff545a246caa64074ba809bbc86fcb8589071 GIT binary patch literal 4268 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 XLyRvu{aX3a{{tgEGu={c*U0|?Dtn-9 literal 0 HcmV?d00001 diff --git a/app/client/src/assets/images/Google.png b/app/client/src/assets/images/Google.png new file mode 100644 index 0000000000000000000000000000000000000000..f90e063212bcf38a0d4b84b41ed4e370b4c319b4 GIT binary patch literal 11446 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 literal 0 HcmV?d00001 diff --git a/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx b/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx index c814ff279d..8f807abf30 100644 --- a/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx +++ b/app/client/src/components/designSystems/appsmith/TextInputComponent.tsx @@ -77,6 +77,7 @@ export interface TextInputProps extends IInputGroupProps { showError?: boolean; /** Additional classname */ className?: string; + type?: string; refHandler?: (ref: HTMLInputElement | null) => void; } diff --git a/app/client/src/components/designSystems/blueprint/Checkbox.tsx b/app/client/src/components/designSystems/blueprint/Checkbox.tsx new file mode 100644 index 0000000000..a4f25f9f39 --- /dev/null +++ b/app/client/src/components/designSystems/blueprint/Checkbox.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import styled from "styled-components"; +import { + Checkbox as BlueprintCheckbox, + ICheckboxProps, +} from "@blueprintjs/core"; +import { + IntentColors, + Intent, + getBorderCSSShorthand, +} from "constants/DefaultTheme"; + +export type CheckboxProps = ICheckboxProps & { + intent: Intent; + align: "left" | "right"; +}; + +export const StyledCheckbox = styled(BlueprintCheckbox)` + &&&& { + span.bp3-control-indicator { + outline: none; + background: white; + box-shadow: none; + border-radius: ${props => props.theme.radii[1]}px; + border: ${props => getBorderCSSShorthand(props.theme.borders[3])}; + height: ${props => props.theme.fontSizes[5]}px; + width: ${props => props.theme.fontSizes[5]}px; + } + input:checked ~ span.bp3-control-indicator { + background: ${props => IntentColors[props.intent]}; + box-shadow: none; + outline: none; + } + } +`; + +export const Checkbox = (props: CheckboxProps) => { + return ; +}; + +export default Checkbox; diff --git a/app/client/src/components/editorComponents/ContextDropdown.tsx b/app/client/src/components/editorComponents/ContextDropdown.tsx index 1429ec6d84..4c9f21f3e8 100644 --- a/app/client/src/components/editorComponents/ContextDropdown.tsx +++ b/app/client/src/components/editorComponents/ContextDropdown.tsx @@ -1,7 +1,7 @@ import React, { ReactNode } from "react"; import styled from "styled-components"; import { ItemRenderer, Select } from "@blueprintjs/select"; -import { Button, MenuItem } from "@blueprintjs/core"; +import { Button, MenuItem, Intent as BlueprintIntent } from "@blueprintjs/core"; import { DropdownOption } from "widgets/DropdownWidget"; import { ControlIconName, ControlIcons } from "icons/ControlIcons"; import { noop } from "utils/AppsmithUtils"; @@ -54,7 +54,7 @@ export const ContextDropdown = (props: ContextDropdownProps) => { onClick={option.onSelect} shouldDismissPopover={true} text={option.label || option.value} - intent={option.intent as Intent} + intent={option.intent as BlueprintIntent} popoverProps={{ minimal: true, hoverCloseDelay: 0, diff --git a/app/client/src/components/editorComponents/Divider.tsx b/app/client/src/components/editorComponents/Divider.tsx new file mode 100644 index 0000000000..990c93a261 --- /dev/null +++ b/app/client/src/components/editorComponents/Divider.tsx @@ -0,0 +1,10 @@ +import { Divider } from "@blueprintjs/core"; +import styled from "styled-components"; + +export const StyledDivider = styled(Divider)` + && { + margin: 0; + } +`; + +export default StyledDivider; diff --git a/app/client/src/components/editorComponents/Form.tsx b/app/client/src/components/editorComponents/Form.tsx new file mode 100644 index 0000000000..8684e81ae2 --- /dev/null +++ b/app/client/src/components/editorComponents/Form.tsx @@ -0,0 +1,8 @@ +import { Form } from "redux-form"; +import styled from "styled-components"; + +const StyledForm = styled(Form)` + width: 100%; +`; + +export default StyledForm; diff --git a/app/client/src/components/editorComponents/FormButton.tsx b/app/client/src/components/editorComponents/FormButton.tsx new file mode 100644 index 0000000000..1f25d91372 --- /dev/null +++ b/app/client/src/components/editorComponents/FormButton.tsx @@ -0,0 +1,28 @@ +import { Button } from "@blueprintjs/core"; +import styled from "styled-components"; +import { Intent, IntentColors } from "constants/DefaultTheme"; +import tinycolor from "tinycolor2"; + +type FormButtonProps = { + intent: Intent; +}; + +export default styled(Button)` + &&& { + font-weight: ${props => props.theme.fontWeights[2]}; + border: none; + flex-grow: 1; + outline: none; + box-shadow: none; + background: ${props => IntentColors[props.intent]}; + &:hover { + background: ${props => + new tinycolor(IntentColors[props.intent]).darken(10).toString()}; + } + &:active { + outline: none; + background: ${props => + new tinycolor(IntentColors[props.intent]).darken(20).toString()}; + } + } +`; diff --git a/app/client/src/components/editorComponents/FormGroup.tsx b/app/client/src/components/editorComponents/FormGroup.tsx new file mode 100644 index 0000000000..913ab8b59e --- /dev/null +++ b/app/client/src/components/editorComponents/FormGroup.tsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; +import { FormGroup } from "@blueprintjs/core"; +const StyledFormGroup = styled(FormGroup)` + & { + width: 100%; + } +`; +export default StyledFormGroup; diff --git a/app/client/src/components/editorComponents/Spinner.tsx b/app/client/src/components/editorComponents/Spinner.tsx new file mode 100644 index 0000000000..0b3d1a1332 --- /dev/null +++ b/app/client/src/components/editorComponents/Spinner.tsx @@ -0,0 +1,3 @@ +import { Spinner } from "@blueprintjs/core"; +//TODO(abhinav): Style this when the designs are available. +export default Spinner; diff --git a/app/client/src/components/editorComponents/form/MessageTag.tsx b/app/client/src/components/editorComponents/form/MessageTag.tsx new file mode 100644 index 0000000000..a204a08069 --- /dev/null +++ b/app/client/src/components/editorComponents/form/MessageTag.tsx @@ -0,0 +1,86 @@ +import React from "react"; +import styled from "styled-components"; +import { + Tag, + Intent as BlueprintIntent, + AnchorButton, + Button, +} from "@blueprintjs/core"; +import { Intent, BlueprintIntentsCSS } from "constants/DefaultTheme"; + +export type MessageAction = { + url?: string; + onClick?: (e: React.SyntheticEvent) => void; + text: string; + intent: Intent; +}; + +const StyledTag = styled(Tag)` + &&& { + padding: ${props => props.theme.spaces[8]}px; + font-size: ${props => props.theme.fontSizes[4]}px; + text-align: center; + margin-bottom: ${props => props.theme.spaces[4]}px; + p { + white-space: normal; + margin: 0; + } + } +`; + +const ActionsContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + & .appsmith-message-action-button { + border: none; + ${BlueprintIntentsCSS} + } +`; + +const ActionButton = (props: MessageAction) => { + if (props.url) { + return ( + + ); + } else if (props.onClick) { + return ( +