From 7bfc00f10ea1318753d8fe555c0aaf3dd4a80972 Mon Sep 17 00:00:00 2001 From: darth-coder00 <86726556+darth-coder00@users.noreply.github.com> Date: Tue, 26 Apr 2022 02:48:02 +0530 Subject: [PATCH] Fixed user profile sync, test connection and toast progressbar issues (#4480) --- .../src/main/resources/ui/src/App.tsx | 3 +- .../auth-provider/AuthProvider.tsx | 79 ++++++++----------- .../ServiceConfig/ConnectionConfigForm.tsx | 4 +- .../resources/ui/src/constants/constants.ts | 1 - .../ui/src/constants/toast.constants.ts | 19 +++++ .../src/main/resources/ui/src/jsons/en.ts | 1 + .../resources/ui/src/pages/signup/index.tsx | 2 +- .../{UsedDataUtils.ts => UserDataUtils.ts} | 38 ++++++++- 8 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/constants/toast.constants.ts rename openmetadata-ui/src/main/resources/ui/src/utils/{UsedDataUtils.ts => UserDataUtils.ts} (66%) diff --git a/openmetadata-ui/src/main/resources/ui/src/App.tsx b/openmetadata-ui/src/main/resources/ui/src/App.tsx index 2f74136d153..a0cfc079ac8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/App.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/App.tsx @@ -27,6 +27,7 @@ import { BrowserRouter as Router } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.min.css'; import { AuthProvider } from './authentication/auth-provider/AuthProvider'; +import { toastOptions } from './constants/toast.constants'; import AppRouter from './router/AppRouter'; const App: FunctionComponent = () => { @@ -49,7 +50,7 @@ const App: FunctionComponent = () => { - + ); diff --git a/openmetadata-ui/src/main/resources/ui/src/authentication/auth-provider/AuthProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/authentication/auth-provider/AuthProvider.tsx index cf6ed4d8eb0..b39c10caeb5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/authentication/auth-provider/AuthProvider.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/authentication/auth-provider/AuthProvider.tsx @@ -16,7 +16,6 @@ import { Configuration } from '@azure/msal-browser'; import { MsalProvider } from '@azure/msal-react'; import { LoginCallback } from '@okta/okta-react'; import { AxiosError, AxiosResponse } from 'axios'; -import { CookieStorage } from 'cookie-storage'; import jwtDecode, { JwtPayload } from 'jwt-decode'; import { isEmpty, isNil } from 'lodash'; import { observer } from 'mobx-react'; @@ -44,11 +43,7 @@ import { } from '../../axiosAPIs/userAPI'; import Loader from '../../components/Loader/Loader'; import { NO_AUTH } from '../../constants/auth.constants'; -import { - isAdminUpdated, - oidcTokenKey, - ROUTES, -} from '../../constants/constants'; +import { oidcTokenKey, ROUTES } from '../../constants/constants'; import { ClientErrors } from '../../enums/axios.enum'; import { AuthTypes } from '../../enums/signin.enum'; import { User } from '../../generated/entity/teams/user'; @@ -62,9 +57,12 @@ import { msalInstance, setMsalInstance, } from '../../utils/AuthProvider.util'; -import { getImages } from '../../utils/CommonUtils'; import { showErrorToast } from '../../utils/ToastUtils'; -import { fetchAllUsers } from '../../utils/UsedDataUtils'; +import { + fetchAllUsers, + getUserDataFromOidc, + matchUserDetails, +} from '../../utils/UserDataUtils'; import Auth0Authenticator from '../authenticators/Auth0Authenticator'; import MsalAuthenticator from '../authenticators/MsalAuthenticator'; import OidcAuthenticator from '../authenticators/OidcAuthenticator'; @@ -78,7 +76,6 @@ interface AuthProviderProps { children: ReactNode; } -const cookieStorage = new CookieStorage(); const userAPIQueryFields = 'profile,teams,roles'; export const AuthProvider = ({ @@ -165,45 +162,33 @@ export const AuthProvider = ({ } }) .catch((err: AxiosError) => { - if (err.response?.data.code === 404) { - resetUserDetails(); + resetUserDetails(); + if (err.response?.data.code !== 404) { + showErrorToast( + err, + jsonData['api-error-messages']['fetch-logged-in-user-error'] + ); } }); }; - const getUpdatedUser = (data: User, user: OidcUser) => { - let getAdminCookie = localStorage.getItem(isAdminUpdated); - - // TODO: Remove when using cookie no more - if (!getAdminCookie) { - getAdminCookie = cookieStorage.getItem(isAdminUpdated); - if (getAdminCookie) { - localStorage.setItem(isAdminUpdated, getAdminCookie); - } - } - - if (getAdminCookie) { - appState.updateUserDetails(data); - } else { - const updatedData = { - isAdmin: data.isAdmin, - email: data.email, - name: data.name, - displayName: user.profile.name, - profile: { images: getImages(user.profile.picture ?? '') }, - }; - updateUser(updatedData) - .then((res: AxiosResponse) => { + const getUpdatedUser = (updatedData: User, existingData: User) => { + const { isAdmin, name, displayName, profile, email } = updatedData; + updateUser({ isAdmin, name, displayName, profile, email }) + .then((res: AxiosResponse) => { + if (res.data) { appState.updateUserDetails(res.data); - localStorage.setItem(isAdminUpdated, 'true'); - }) - .catch((error: AxiosError) => { - showErrorToast( - error, - jsonData['api-error-messages']['update-admin-profile-error'] - ); - }); - } + } else { + throw jsonData['api-error-messages']['unexpected-server-response']; + } + }) + .catch((error: AxiosError) => { + appState.updateUserDetails(existingData); + showErrorToast( + error, + jsonData['api-error-messages']['update-admin-profile-error'] + ); + }); }; const handleSuccessfulLogin = (user: OidcUser) => { @@ -211,11 +196,13 @@ export const AuthProvider = ({ getUserByName(getNameFromEmail(user.profile.email), userAPIQueryFields) .then((res: AxiosResponse) => { if (res.data) { - if (res.data?.isAdmin) { - getUpdatedUser(res.data, user); + const updatedUserData = getUserDataFromOidc(res.data, user); + if (!matchUserDetails(res.data, updatedUserData, ['profile'])) { + getUpdatedUser(updatedUserData, res.data); + } else { + appState.updateUserDetails(res.data); } getUserPermissions(); - appState.updateUserDetails(res.data); fetchAllUsers(); handledVerifiedUser(); } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx index 857cb267be7..159b96eaf85 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ServiceConfig/ConnectionConfigForm.tsx @@ -89,8 +89,10 @@ const ConnectionConfigForm: FunctionComponent = ({ }; const handleTestConnection = (formData: ConfigData) => { + const updatedFormData = escapeBackwardSlashChar(formData); + return new Promise((resolve, reject) => { - TestConnection(formData, 'Database') + TestConnection(updatedFormData, 'Database') .then((res) => { // This api only responds with status 200 on success // No data sent on api success diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts index c3180f24344..c2e4dd4c636 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts @@ -25,7 +25,6 @@ export const SIDEBAR_WIDTH_EXPANDED = 290; export const LOCALSTORAGE_RECENTLY_VIEWED = `recentlyViewedData_${COOKIE_VERSION}`; export const LOCALSTORAGE_RECENTLY_SEARCHED = `recentlySearchedData_${COOKIE_VERSION}`; export const oidcTokenKey = 'oidcIdToken'; -export const isAdminUpdated = 'isAdminUpdated'; export const TERM_ADMIN = 'Admin'; export const TERM_USER = 'User'; export const imageTypes = { diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/toast.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/toast.constants.ts new file mode 100644 index 00000000000..8568a42a2f8 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/constants/toast.constants.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2021 Collate + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ToastOptions } from 'react-toastify'; + +export const toastOptions: ToastOptions = { + autoClose: false, + hideProgressBar: true, +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/jsons/en.ts b/openmetadata-ui/src/main/resources/ui/src/jsons/en.ts index 29d45b82930..63769092912 100644 --- a/openmetadata-ui/src/main/resources/ui/src/jsons/en.ts +++ b/openmetadata-ui/src/main/resources/ui/src/jsons/en.ts @@ -82,6 +82,7 @@ const jsonData = { 'fetch-ingestion-error': 'Error while fetching ingestion workflow!', 'fetch-lineage-error': 'Error while fetching lineage data!', 'fetch-lineage-node-error': 'Error while fetching lineage node!', + 'fetch-logged-in-user-error': 'Error while fetching logged-in user!', 'fetch-pipeline-details-error': 'Error while fetching pipeline details!', 'fetch-pipeline-status-error': 'Error while fetching pipeline status!', 'fetch-policy-error': 'Error while fetching policy details!', diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/signup/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/signup/index.tsx index 2f48b98b098..4a47d11ff18 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/signup/index.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/signup/index.tsx @@ -30,7 +30,7 @@ import { getNameFromEmail } from '../../utils/AuthProvider.util'; import { getImages } from '../../utils/CommonUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; import { showErrorToast } from '../../utils/ToastUtils'; -import { fetchAllUsers } from '../../utils/UsedDataUtils'; +import { fetchAllUsers } from '../../utils/UserDataUtils'; const Signup = () => { const [selectedTeams, setSelectedTeams] = useState>( diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/UsedDataUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/UserDataUtils.ts similarity index 66% rename from openmetadata-ui/src/main/resources/ui/src/utils/UsedDataUtils.ts rename to openmetadata-ui/src/main/resources/ui/src/utils/UserDataUtils.ts index d035efe8cba..d184edac67d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/UsedDataUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/UserDataUtils.ts @@ -12,11 +12,15 @@ */ import { AxiosResponse } from 'axios'; +import { isEmpty, isEqual } from 'lodash'; import AppState from '../AppState'; +import { OidcUser } from '../authentication/auth-provider/AuthProvider.interface'; import { getRoles } from '../axiosAPIs/rolesAPI'; import { getTeams } from '../axiosAPIs/teamsAPI'; import { getUsers } from '../axiosAPIs/userAPI'; import { API_RES_MAX_SIZE } from '../constants/constants'; +import { User } from '../generated/entity/teams/user'; +import { getImages } from './CommonUtils'; // Moving this code here from App.tsx const getAllUsersList = (arrQueryFields = ''): void => { @@ -53,6 +57,36 @@ export const fetchAllUsers = () => { getAllUsersList('profile,teams,roles'); getAllTeams(); getAllRoles(); - // TODO: uncomment below line to update users list in real time. - // setInterval(getAllUsersList, TIMEOUT.USER_LIST); +}; + +export const getUserDataFromOidc = ( + userData: User, + oidcUser: OidcUser +): User => { + const images = oidcUser.profile.picture + ? getImages(oidcUser.profile.picture) + : undefined; + + return { + ...userData, + displayName: oidcUser.profile.name, + profile: !isEmpty(images) ? { images } : userData.profile, + }; +}; + +export const matchUserDetails = ( + userData: User, + newUser: User, + mapFields: Array +) => { + let isMatch = true; + for (const field of mapFields) { + if (!isEqual(userData[field], newUser[field])) { + isMatch = false; + + break; + } + } + + return isMatch; };