diff options
175 files changed, 940 insertions, 1523 deletions
diff --git a/server/sonar-web/src/main/js/api/quality-gates.ts b/server/sonar-web/src/main/js/api/quality-gates.ts index cc3d83be8e0..e28492899cd 100644 --- a/server/sonar-web/src/main/js/api/quality-gates.ts +++ b/server/sonar-web/src/main/js/api/quality-gates.ts @@ -28,7 +28,8 @@ import { QualityGateProjectStatus, SearchPermissionsParameters } from '../types/quality-gates'; -import { Condition, Paging, QualityGate, UserBase } from '../types/types'; +import { Condition, Paging, QualityGate } from '../types/types'; +import { UserBase } from '../types/users'; export function fetchQualityGates(): Promise<{ actions: { create: boolean }; diff --git a/server/sonar-web/src/main/js/api/security-hotspots.ts b/server/sonar-web/src/main/js/api/security-hotspots.ts index e1f45cb1a19..2f2608b2b3b 100644 --- a/server/sonar-web/src/main/js/api/security-hotspots.ts +++ b/server/sonar-web/src/main/js/api/security-hotspots.ts @@ -29,7 +29,7 @@ import { HotspotSetStatusRequest, HotspotStatus } from '../types/security-hotspots'; -import { UserBase } from '../types/types'; +import { UserBase } from '../types/users'; const HOTSPOTS_SEARCH_URL = '/api/hotspots/search'; diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index 6da4a35d8e0..272c2c73295 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -19,14 +19,8 @@ */ import throwGlobalError from '../app/utils/throwGlobalError'; import { getJSON, post, postJSON } from '../helpers/request'; -import { - CurrentUser, - CurrentUserSetting, - HomePage, - IdentityProvider, - Paging, - User -} from '../types/types'; +import { IdentityProvider, Paging } from '../types/types'; +import { CurrentUser, HomePage, User } from '../types/users'; export function getCurrentUser(): Promise<CurrentUser> { return getJSON('/api/users/current'); @@ -102,10 +96,6 @@ export function setHomePage(homepage: HomePage): Promise<void | Response> { return post('/api/users/set_homepage', homepage).catch(throwGlobalError); } -export function setUserSetting(setting: CurrentUserSetting): Promise<void | Response> { - return post('/api/users/set_setting', setting).catch(throwGlobalError); -} - export function dismissSonarlintAd(): Promise<void | Response> { return post('/api/users/dismiss_sonarlint_ad').catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/app/components/Landing.tsx b/server/sonar-web/src/main/js/app/components/Landing.tsx index ede739b43fe..13109175290 100644 --- a/server/sonar-web/src/main/js/app/components/Landing.tsx +++ b/server/sonar-web/src/main/js/app/components/Landing.tsx @@ -18,11 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { withCurrentUser } from '../../components/hoc/withCurrentUser'; import { Router, withRouter } from '../../components/hoc/withRouter'; import { getHomePageUrl } from '../../helpers/urls'; -import { isLoggedIn } from '../../helpers/users'; -import { CurrentUser } from '../../types/types'; +import { CurrentUser, isLoggedIn } from '../../types/users'; +import withCurrentUserContext from './current-user/withCurrentUserContext'; export interface LandingProps { currentUser: CurrentUser; @@ -45,4 +44,4 @@ export class Landing extends React.PureComponent<LandingProps> { } } -export default withRouter(withCurrentUser(Landing)); +export default withRouter(withCurrentUserContext(Landing)); diff --git a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx b/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx index ab85767d669..6b560a90ca2 100644 --- a/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx +++ b/server/sonar-web/src/main/js/app/components/PluginRiskConsent.tsx @@ -27,7 +27,7 @@ import { hasGlobalPermission } from '../../helpers/users'; import { Permissions } from '../../types/permissions'; import { RiskConsent } from '../../types/plugins'; import { SettingsKey } from '../../types/settings'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import GlobalMessagesContainer from './GlobalMessagesContainer'; import './PluginRiskConsent.css'; diff --git a/server/sonar-web/src/main/js/app/components/ResetPassword.tsx b/server/sonar-web/src/main/js/app/components/ResetPassword.tsx index 800b9e05c3b..183cd2accb8 100644 --- a/server/sonar-web/src/main/js/app/components/ResetPassword.tsx +++ b/server/sonar-web/src/main/js/app/components/ResetPassword.tsx @@ -22,7 +22,7 @@ import ResetPasswordForm from '../../components/common/ResetPasswordForm'; import { whenLoggedIn } from '../../components/hoc/whenLoggedIn'; import { translate } from '../../helpers/l10n'; import { getBaseUrl } from '../../helpers/system'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import GlobalMessagesContainer from './GlobalMessagesContainer'; export interface ResetPasswordProps { diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index 5b7c3915672..ebbdebed587 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -19,19 +19,17 @@ */ import { differenceInDays } from 'date-fns'; import * as React from 'react'; -import { connect } from 'react-redux'; import { showLicense } from '../../api/marketplace'; import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import { lazyLoadComponent } from '../../components/lazyLoadComponent'; import { parseDate, toShortNotSoISOString } from '../../helpers/dates'; import { hasMessage } from '../../helpers/l10n'; import { get, save } from '../../helpers/storage'; -import { isLoggedIn } from '../../helpers/users'; -import { getCurrentUser, Store } from '../../store/rootReducer'; import { AppState } from '../../types/appstate'; import { EditionKey } from '../../types/editions'; -import { CurrentUser } from '../../types/types'; +import { CurrentUser, isLoggedIn } from '../../types/users'; import withAppStateContext from './app-state/withAppStateContext'; +import withCurrentUserContext from './current-user/withCurrentUserContext'; const LicensePromptModal = lazyLoadComponent( () => import('../../apps/marketplace/components/LicensePromptModal'), @@ -98,8 +96,4 @@ export class StartupModal extends React.PureComponent<Props & StateProps, State> } } -const mapStateToProps = (state: Store): StateProps => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(withRouter(withAppStateContext(StartupModal))); +export default withCurrentUserContext(withRouter(withAppStateContext(StartupModal))); diff --git a/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx index 102f5f819fa..437ef87cf29 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/Landing-test.tsx @@ -20,7 +20,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { mockCurrentUser, mockLoggedInUser, mockRouter } from '../../../helpers/testMocks'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; import { Landing } from '../Landing'; it.each([ diff --git a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx index 4a07e47012b..0813389c9ba 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/StartupModal-test.tsx @@ -27,7 +27,7 @@ import { get, save } from '../../../helpers/storage'; import { mockAppState } from '../../../helpers/testMocks'; import { waitAndUpdate } from '../../../helpers/testUtils'; import { EditionKey } from '../../../types/editions'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import { StartupModal } from '../StartupModal'; jest.mock('../../../api/marketplace', () => ({ diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap index cf997f458f2..ab5e5905229 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap @@ -3,7 +3,7 @@ exports[`should render correctly 1`] = ` <SuggestionsProvider> <A11yProvider> - <Connect(withRouter(withAppStateContext(StartupModal)))> + <withCurrentUserContext(withRouter(withAppStateContext(StartupModal)))> <A11ySkipLinks /> <div className="global-container" @@ -19,7 +19,7 @@ exports[`should render correctly 1`] = ` <withAppStateContext(IndexationContextProvider)> <LanguagesContextProvider> <MetricsContextProvider> - <Connect(GlobalNav) + <withCurrentUserContext(GlobalNav) location={ Object { "action": "PUSH", @@ -33,8 +33,8 @@ exports[`should render correctly 1`] = ` } /> <Connect(GlobalMessages) /> - <Connect(withCurrentUser(withIndexationContext(IndexationNotification))) /> - <Connect(withCurrentUser(withAppStateContext(UpdateNotification))) + <withCurrentUserContext(withIndexationContext(IndexationNotification)) /> + <withCurrentUserContext(withAppStateContext(UpdateNotification)) dismissable={true} /> <ChildComponent /> @@ -43,11 +43,11 @@ exports[`should render correctly 1`] = ` </withAppStateContext(IndexationContextProvider)> </Workspace> </div> - <Connect(Connect(withCurrentUser(PromotionNotification))) /> + <withCurrentUserContext(PromotionNotification) /> </div> <withAppStateContext(GlobalFooter) /> </div> - </Connect(withRouter(withAppStateContext(StartupModal)))> + </withCurrentUserContext(withRouter(withAppStateContext(StartupModal)))> </A11yProvider> </SuggestionsProvider> `; diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts index 79a2fc63d9d..efb10534705 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilterContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts @@ -17,12 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { connect } from 'react-redux'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; -import FavoriteFilter from './FavoriteFilter'; +import * as React from 'react'; +import { CurrentUser, HomePage } from '../../../types/users'; -function mapStateToProps(state: Store) { - return { currentUser: getCurrentUser(state) }; +export interface CurrentUserContextInterface { + currentUser: CurrentUser; + updateCurrentUserHomepage: (homepage: HomePage) => void; + updateCurrentUserSonarLintAdSeen: () => void; } -export default connect(mapStateToProps)(FavoriteFilter); +export const CurrentUserContext = React.createContext<CurrentUserContextInterface | undefined>( + undefined +); diff --git a/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx new file mode 100644 index 00000000000..9ffe3d1ec59 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContextProvider.tsx @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { CurrentUser, HomePage } from '../../../types/users'; +import { CurrentUserContext } from './CurrentUserContext'; + +interface Props { + currentUser?: CurrentUser; +} + +interface State { + currentUser: CurrentUser; +} + +export default class CurrentUserContextProvider extends React.PureComponent<Props, State> { + constructor(props: Props) { + super(props); + this.state = { currentUser: props.currentUser ?? { isLoggedIn: false } }; + } + + updateCurrentUserHomepage = (homepage: HomePage) => { + this.setState(prevState => ({ + currentUser: { ...prevState.currentUser, homepage } + })); + }; + + updateCurrentUserSonarLintAdSeen = () => { + this.setState(prevState => ({ + currentUser: { ...prevState.currentUser, sonarLintAdSeen: true } + })); + }; + + render() { + return ( + <CurrentUserContext.Provider + value={{ + currentUser: this.state.currentUser, + updateCurrentUserHomepage: this.updateCurrentUserHomepage, + updateCurrentUserSonarLintAdSeen: this.updateCurrentUserSonarLintAdSeen + }}> + {this.props.children} + </CurrentUserContext.Provider> + ); + } +} diff --git a/server/sonar-web/src/main/js/components/hoc/withCurrentUser.tsx b/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx index 221b3cc788d..e2621f072ac 100644 --- a/server/sonar-web/src/main/js/components/hoc/withCurrentUser.tsx +++ b/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx @@ -18,25 +18,25 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; -import { getCurrentUser, Store } from '../../store/rootReducer'; -import { CurrentUser } from '../../types/types'; -import { getWrappedDisplayName } from './utils'; +import { getWrappedDisplayName } from '../../../components/hoc/utils'; +import { CurrentUserContext, CurrentUserContextInterface } from './CurrentUserContext'; -export function withCurrentUser<P>( - WrappedComponent: React.ComponentType<P & { currentUser: CurrentUser }> +export default function withCurrentUserContext<P>( + WrappedComponent: React.ComponentType<P & Pick<CurrentUserContextInterface, 'currentUser'>> ) { - class Wrapper extends React.Component<P & { currentUser: CurrentUser }> { - static displayName = getWrappedDisplayName(WrappedComponent, 'withCurrentUser'); + return class WithCurrentUserContext extends React.PureComponent< + Omit<P, keyof CurrentUserContextInterface> + > { + static displayName = getWrappedDisplayName(WrappedComponent, 'withCurrentUserContext'); render() { - return <WrappedComponent {...this.props} />; + return ( + <CurrentUserContext.Consumer> + {(currentUserContext: CurrentUserContextInterface) => ( + <WrappedComponent {...currentUserContext} {...(this.props as P)} /> + )} + </CurrentUserContext.Consumer> + ); } - } - - function mapStateToProps(state: Store) { - return { currentUser: getCurrentUser(state) }; - } - - return connect(mapStateToProps)(Wrapper); + }; } diff --git a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx index db90d3e0342..695cd5f3efc 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/Extension.tsx @@ -26,13 +26,14 @@ import { getExtensionStart } from '../../../helpers/extensions'; import { getCurrentL10nBundle, translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; import { addGlobalErrorMessage } from '../../../store/globalMessages'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; import { AppState } from '../../../types/appstate'; import { ExtensionStartMethod } from '../../../types/extension'; -import { CurrentUser, Dict, Extension as TypeExtension } from '../../../types/types'; +import { Dict, Extension as TypeExtension } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; import * as theme from '../../theme'; import getStore from '../../utils/getStore'; import withAppStateContext from '../app-state/withAppStateContext'; +import withCurrentUserContext from '../current-user/withCurrentUserContext'; interface Props extends WrappedComponentProps { appState: AppState; @@ -126,9 +127,10 @@ export class Extension extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: Store) => ({ currentUser: getCurrentUser(state) }); -const mapDispatchToProps = { onFail: addGlobalErrorMessage }; - export default injectIntl( - withRouter(withAppStateContext(connect(mapStateToProps, mapDispatchToProps)(Extension))) + withRouter( + withAppStateContext( + withCurrentUserContext(connect(null, { onFail: addGlobalErrorMessage })(Extension)) + ) + ) ); diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap index bb720539c93..41c11c85e36 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectAdminPageExtension-test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render correctly: extension exists 1`] = ` -<injectIntl(withRouter(withAppStateContext(Connect(Extension)))) +<injectIntl(withRouter(withAppStateContext(withCurrentUserContext(Connect(Extension))))) extension={ Object { "key": "foo/bar", diff --git a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap index 53b7d0d8243..bb710428d4c 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/extensions/__tests__/__snapshots__/ProjectPageExtension-test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render correctly 1`] = ` -<injectIntl(withRouter(withAppStateContext(Connect(Extension)))) +<injectIntl(withRouter(withAppStateContext(withCurrentUserContext(Connect(Extension))))) extension={ Object { "key": "plugin-key/extension-key", diff --git a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx b/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx index 391bb0a7c52..52bb015e917 100644 --- a/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx +++ b/server/sonar-web/src/main/js/app/components/indexation/IndexationNotification.tsx @@ -18,14 +18,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import withIndexationContext, { WithIndexationContextProps } from '../../../components/hoc/withIndexationContext'; -import { hasGlobalPermission, isLoggedIn } from '../../../helpers/users'; +import { hasGlobalPermission } from '../../../helpers/users'; import { IndexationNotificationType } from '../../../types/indexation'; import { Permissions } from '../../../types/permissions'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; +import withCurrentUserContext from '../current-user/withCurrentUserContext'; import './IndexationNotification.css'; import IndexationNotificationHelper from './IndexationNotificationHelper'; import IndexationNotificationRenderer from './IndexationNotificationRenderer'; @@ -104,4 +104,4 @@ export class IndexationNotification extends React.PureComponent<Props, State> { } } -export default withCurrentUser(withIndexationContext(IndexationNotification)); +export default withCurrentUserContext(withIndexationContext(IndexationNotification)); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx b/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx index 7cc1e130c0c..f17925c709b 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/Header.tsx @@ -19,13 +19,12 @@ */ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; import Favorite from '../../../../components/controls/Favorite'; -import { isLoggedIn } from '../../../../helpers/users'; -import { getCurrentUser, Store } from '../../../../store/rootReducer'; import { ProjectAlmBindingResponse } from '../../../../types/alm-settings'; import { BranchLike } from '../../../../types/branch-like'; -import { Component, CurrentUser } from '../../../../types/types'; +import { Component } from '../../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../../types/users'; +import withCurrentUserContext from '../../current-user/withCurrentUserContext'; import BranchLikeNavigation from './branch-like/BranchLikeNavigation'; import CurrentBranchLikeMergeInformation from './branch-like/CurrentBranchLikeMergeInformation'; import { Breadcrumb } from './Breadcrumb'; @@ -70,8 +69,4 @@ export function Header(props: HeaderProps) { ); } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(React.memo(Header)); +export default withCurrentUserContext(React.memo(Header)); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/HeaderMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/HeaderMeta.tsx index cf2f755debb..f77c4429974 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/HeaderMeta.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/HeaderMeta.tsx @@ -18,19 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import BranchStatus from '../../../../components/common/BranchStatus'; import HomePageSelect from '../../../../components/controls/HomePageSelect'; import DetachIcon from '../../../../components/icons/DetachIcon'; import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter'; import { isBranch, isPullRequest } from '../../../../helpers/branch-like'; import { translate } from '../../../../helpers/l10n'; -import { isLoggedIn } from '../../../../helpers/users'; -import { getCurrentUser, Store } from '../../../../store/rootReducer'; import { BranchLike } from '../../../../types/branch-like'; import { ComponentQualifier } from '../../../../types/component'; import { TaskWarning } from '../../../../types/tasks'; -import { Component, CurrentUser, HomePage } from '../../../../types/types'; +import { Component } from '../../../../types/types'; +import { CurrentUser, HomePage, isLoggedIn } from '../../../../types/users'; +import withCurrentUserContext from '../../current-user/withCurrentUserContext'; import ComponentNavWarnings from './ComponentNavWarnings'; import './HeaderMeta.css'; @@ -124,8 +123,4 @@ export function getCurrentPage(component: Component, branchLike: BranchLike | un return currentPage; } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(HeaderMeta); +export default withCurrentUserContext(HeaderMeta); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap index 0a372d2d7b8..02a675e164a 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap @@ -9,7 +9,7 @@ exports[`renders correctly: default 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top padded-bottom" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -40,7 +40,7 @@ exports[`renders correctly: default 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -112,7 +112,7 @@ exports[`renders correctly: default 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ @@ -203,7 +203,7 @@ exports[`renders correctly: has failed notification 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top padded-bottom" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -234,7 +234,7 @@ exports[`renders correctly: has failed notification 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -306,7 +306,7 @@ exports[`renders correctly: has failed notification 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ @@ -383,7 +383,7 @@ exports[`renders correctly: has failed project binding 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top padded-bottom" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -414,7 +414,7 @@ exports[`renders correctly: has failed project binding 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -486,7 +486,7 @@ exports[`renders correctly: has failed project binding 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ @@ -565,7 +565,7 @@ exports[`renders correctly: has in progress notification 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top padded-bottom" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -596,7 +596,7 @@ exports[`renders correctly: has in progress notification 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -668,7 +668,7 @@ exports[`renders correctly: has in progress notification 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ @@ -747,7 +747,7 @@ exports[`renders correctly: has pending notification 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top padded-bottom" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -778,7 +778,7 @@ exports[`renders correctly: has pending notification 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -850,7 +850,7 @@ exports[`renders correctly: has pending notification 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ @@ -894,7 +894,7 @@ exports[`renders correctly: has warnings 1`] = ` <div className="display-flex-center display-flex-space-between little-padded-top" > - <Connect(Component) + <withCurrentUserContext(Component) branchLikes={Array []} component={ Object { @@ -925,7 +925,7 @@ exports[`renders correctly: has warnings 1`] = ` } } /> - <Connect(HeaderMeta) + <withCurrentUserContext(HeaderMeta) component={ Object { "breadcrumbs": Array [ @@ -1005,7 +1005,7 @@ exports[`renders correctly: has warnings 1`] = ` onClose={[Function]} top={120} > - <Connect(withMetricsContext(ProjectInformation)) + <withCurrentUserContext(withMetricsContext(ProjectInformation)) component={ Object { "breadcrumbs": Array [ diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/HeaderMeta-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/HeaderMeta-test.tsx.snap index fd0e0ab897d..14a257a1b3c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/HeaderMeta-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/HeaderMeta-test.tsx.snap @@ -39,7 +39,7 @@ exports[`should render correctly for a branch 1`] = ` > version 0.0.1 </span> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="spacer-left" currentPage={ Object { @@ -92,7 +92,7 @@ exports[`should render correctly for a main project branch 1`] = ` > version 0.0.1 </span> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="spacer-left" currentPage={ Object { @@ -133,7 +133,7 @@ exports[`should render correctly for a portfolio 1`] = ` } /> </span> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="spacer-left" currentPage={ Object { diff --git a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx index 6f28bae6697..952b65e7d1e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/projectInformation/ProjectInformation.tsx @@ -18,14 +18,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import { getMeasures } from '../../../../../api/measures'; -import { isLoggedIn } from '../../../../../helpers/users'; -import { getCurrentUser, Store } from '../../../../../store/rootReducer'; import { BranchLike } from '../../../../../types/branch-like'; import { ComponentQualifier } from '../../../../../types/component'; import { MetricKey } from '../../../../../types/metrics'; -import { Component, CurrentUser, Dict, Measure, Metric } from '../../../../../types/types'; +import { Component, Dict, Measure, Metric } from '../../../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../../../types/users'; +import withCurrentUserContext from '../../../current-user/withCurrentUserContext'; import withMetricsContext from '../../../metrics/withMetricsContext'; import ProjectBadges from './badges/ProjectBadges'; import InfoDrawerPage from './InfoDrawerPage'; @@ -121,8 +120,4 @@ export class ProjectInformation extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(withMetricsContext(ProjectInformation)); +export default withCurrentUserContext(withMetricsContext(ProjectInformation)); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx index 488135ebd8b..45288c9ef07 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx @@ -18,11 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import NavBar from '../../../../components/ui/NavBar'; -import { getCurrentUser, Store } from '../../../../store/rootReducer'; -import { CurrentUser } from '../../../../types/types'; +import { CurrentUser } from '../../../../types/users'; import { rawSizes } from '../../../theme'; +import withCurrentUserContext from '../../current-user/withCurrentUserContext'; import EmbedDocsPopupHelper from '../../embed-docs-modal/EmbedDocsPopupHelper'; import Search from '../../search/Search'; import './GlobalNav.css'; @@ -52,10 +51,4 @@ export function GlobalNav(props: GlobalNavProps) { ); } -const mapStateToProps = (state: Store) => { - return { - currentUser: getCurrentUser(state) - }; -}; - -export default connect(mapStateToProps)(GlobalNav); +export default withCurrentUserContext(GlobalNav); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx index 230bdffe274..e608efc5955 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx @@ -27,7 +27,8 @@ import { translate } from '../../../../helpers/l10n'; import { getQualityGatesUrl } from '../../../../helpers/urls'; import { AppState } from '../../../../types/appstate'; import { ComponentQualifier } from '../../../../types/component'; -import { CurrentUser, Extension } from '../../../../types/types'; +import { Extension } from '../../../../types/types'; +import { CurrentUser } from '../../../../types/users'; import withAppStateContext from '../../app-state/withAppStateContext'; interface Props { diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx index 2e6e24706b4..91079564dbe 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.tsx @@ -24,8 +24,7 @@ import { Router, withRouter } from '../../../../components/hoc/withRouter'; import Avatar from '../../../../components/ui/Avatar'; import { translate } from '../../../../helpers/l10n'; import { getBaseUrl } from '../../../../helpers/system'; -import { isLoggedIn } from '../../../../helpers/users'; -import { CurrentUser, LoggedInUser } from '../../../../types/types'; +import { CurrentUser, isLoggedIn, LoggedInUser } from '../../../../types/users'; import { rawSizes } from '../../../theme'; interface Props { diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx index 8f9e68a3b01..924b1da4cae 100644 --- a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx +++ b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx @@ -18,21 +18,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import { dismissSonarlintAd } from '../../../api/users'; import { ButtonLink } from '../../../components/controls/buttons'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; -import { isLoggedIn } from '../../../helpers/users'; -import { setSonarlintAd } from '../../../store/users'; -import { CurrentUser } from '../../../types/types'; +import { isLoggedIn } from '../../../types/users'; +import { CurrentUserContextInterface } from '../current-user/CurrentUserContext'; +import withCurrentUserContext from '../current-user/withCurrentUserContext'; import './PromotionNotification.css'; -export interface PromotionNotificationProps { - setSonarlintAd: () => void; - currentUser: CurrentUser; -} +export interface PromotionNotificationProps + extends Pick<CurrentUserContextInterface, 'currentUser' | 'updateCurrentUserSonarLintAdSeen'> {} export function PromotionNotification(props: PromotionNotificationProps) { const { currentUser } = props; @@ -43,7 +39,7 @@ export function PromotionNotification(props: PromotionNotificationProps) { const onClick = () => { dismissSonarlintAd(); - props.setSonarlintAd(); + props.updateCurrentUserSonarLintAdSeen(); }; return ( @@ -74,6 +70,4 @@ export function PromotionNotification(props: PromotionNotificationProps) { ); } -const dispatchToProps = { setSonarlintAd }; - -export default connect(null, dispatchToProps)(withCurrentUser(PromotionNotification)); +export default withCurrentUserContext(PromotionNotification); diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx index c39dd065ca1..059d0560dbf 100644 --- a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx +++ b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx @@ -40,29 +40,33 @@ it('should render correctly', () => { }); it('should remove the toaster when click on dismiss', () => { - const setSonarlintAd = jest.fn(); + const updateCurrentUserSonarLintAdSeen = jest.fn(); const wrapper = shallowRender({ currentUser: mockLoggedInUser({ sonarLintAdSeen: false }), - setSonarlintAd + updateCurrentUserSonarLintAdSeen }); wrapper.find('.toaster-actions ButtonLink').simulate('click'); expect(dismissSonarlintAd).toBeCalled(); - expect(setSonarlintAd).toBeCalled(); + expect(updateCurrentUserSonarLintAdSeen).toBeCalled(); }); it('should remove the toaster and navigate to sonarlint when click on learn more', () => { - const setSonarlintAd = jest.fn(); + const updateCurrentUserSonarLintAdSeen = jest.fn(); const wrapper = shallowRender({ currentUser: mockLoggedInUser({ sonarLintAdSeen: false }), - setSonarlintAd + updateCurrentUserSonarLintAdSeen }); wrapper.find('.toaster-actions .button-primary').simulate('click'); expect(dismissSonarlintAd).toBeCalled(); - expect(setSonarlintAd).toBeCalled(); + expect(updateCurrentUserSonarLintAdSeen).toBeCalled(); }); function shallowRender(props: Partial<PromotionNotificationProps> = {}) { return shallow( - <PromotionNotification currentUser={mockCurrentUser()} setSonarlintAd={jest.fn()} {...props} /> + <PromotionNotification + currentUser={mockCurrentUser()} + updateCurrentUserSonarLintAdSeen={jest.fn()} + {...props} + /> ); } diff --git a/server/sonar-web/src/main/js/app/components/search/Search.tsx b/server/sonar-web/src/main/js/app/components/search/Search.tsx index 0140d17e0b1..9e8664ef0fc 100644 --- a/server/sonar-web/src/main/js/app/components/search/Search.tsx +++ b/server/sonar-web/src/main/js/app/components/search/Search.tsx @@ -34,7 +34,8 @@ import { translate, translateWithParameters } from '../../../helpers/l10n'; import { scrollToElement } from '../../../helpers/scrolling'; import { getComponentOverviewUrl } from '../../../helpers/urls'; import { ComponentQualifier } from '../../../types/component'; -import { CurrentUser, Dict } from '../../../types/types'; +import { Dict } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; import RecentHistory from '../RecentHistory'; import './Search.css'; import { ComponentResult, More, Results, sortQualifiers } from './utils'; diff --git a/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx b/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx index b399276ddf0..123260509da 100644 --- a/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx +++ b/server/sonar-web/src/main/js/app/components/update-notification/UpdateNotification.tsx @@ -20,18 +20,19 @@ import { groupBy, isEmpty, mapValues } from 'lodash'; import * as React from 'react'; import { getSystemUpgrades } from '../../../api/system'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { Alert, AlertVariant } from '../../../components/ui/Alert'; import DismissableAlert from '../../../components/ui/DismissableAlert'; import SystemUpgradeButton from '../../../components/upgrade/SystemUpgradeButton'; import { sortUpgrades, UpdateUseCase } from '../../../components/upgrade/utils'; import { translate } from '../../../helpers/l10n'; -import { hasGlobalPermission, isLoggedIn } from '../../../helpers/users'; +import { hasGlobalPermission } from '../../../helpers/users'; import { AppState } from '../../../types/appstate'; import { Permissions } from '../../../types/permissions'; import { SystemUpgrade } from '../../../types/system'; -import { CurrentUser, Dict } from '../../../types/types'; +import { Dict } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import withAppStateContext from '../app-state/withAppStateContext'; +import withCurrentUserContext from '../current-user/withCurrentUserContext'; import './UpdateNotification.css'; const MONTH_BEFOR_PREVIOUS_LTS_NOTIFICATION = 6; @@ -74,20 +75,12 @@ export class UpdateNotification extends React.PureComponent<Props, State> { canSeeNotification: false, useCase: UpdateUseCase.NewMinorVersion }; - this.fetchSystemUpgradeInformation(); } componentDidMount() { this.mounted = true; - } - componentDidUpdate(prevProps: Props) { - if ( - prevProps.currentUser !== this.props.currentUser || - this.props.appState.version !== prevProps.appState.version - ) { - this.fetchSystemUpgradeInformation(); - } + this.fetchSystemUpgradeInformation(); } componentWillUnmount() { @@ -250,4 +243,4 @@ export class UpdateNotification extends React.PureComponent<Props, State> { } } -export default withCurrentUser(withAppStateContext(UpdateNotification)); +export default withCurrentUserContext(withAppStateContext(UpdateNotification)); diff --git a/server/sonar-web/src/main/js/app/components/update-notification/__tests__/UpdateNotification-test.tsx b/server/sonar-web/src/main/js/app/components/update-notification/__tests__/UpdateNotification-test.tsx index b5d9edd0b3b..f63a4aee7f7 100644 --- a/server/sonar-web/src/main/js/app/components/update-notification/__tests__/UpdateNotification-test.tsx +++ b/server/sonar-web/src/main/js/app/components/update-notification/__tests__/UpdateNotification-test.tsx @@ -42,13 +42,18 @@ function formatDate(date: Date): string { } it('should render correctly', async () => { - const wrapper = shallowRender({ + let wrapper = shallowRender({ appState: mockAppState({ version: '9.0' }), currentUser: mockLoggedInUser({ permissions: { global: [Permissions.Admin] } }) }); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot('default'); - expect(wrapper.setProps({ currentUser: mockCurrentUser() })).toMatchSnapshot('anonymous user'); + + wrapper = shallowRender({ + appState: mockAppState({ version: '9.0' }), + currentUser: mockCurrentUser() + }); + expect(wrapper.type()).toBeNull(); }); it('should not show prompt when not admin', async () => { diff --git a/server/sonar-web/src/main/js/app/components/update-notification/__tests__/__snapshots__/UpdateNotification-test.tsx.snap b/server/sonar-web/src/main/js/app/components/update-notification/__tests__/__snapshots__/UpdateNotification-test.tsx.snap index c788a784593..a6d9f0767dd 100644 --- a/server/sonar-web/src/main/js/app/components/update-notification/__tests__/__snapshots__/UpdateNotification-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/update-notification/__tests__/__snapshots__/UpdateNotification-test.tsx.snap @@ -1,7 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly: anonymous user 1`] = `""`; - exports[`should render correctly: default 1`] = ` <DismissableAlert alertKey="new_minor_version9.1" diff --git a/server/sonar-web/src/main/js/app/utils/getStore.ts b/server/sonar-web/src/main/js/app/utils/getStore.ts index 63b5701d0d1..251dd073983 100644 --- a/server/sonar-web/src/main/js/app/utils/getStore.ts +++ b/server/sonar-web/src/main/js/app/utils/getStore.ts @@ -19,18 +19,13 @@ */ import { Store } from 'redux'; import rootReducer, { Store as State } from '../../store/rootReducer'; -import { receiveCurrentUser } from '../../store/users'; import configureStore from '../../store/utils/configureStore'; -import { CurrentUser } from '../../types/types'; let store: Store<State, any>; -const createStore = (currentUser?: CurrentUser) => { +const createStore = () => { store = configureStore(rootReducer); - if (currentUser) { - store.dispatch(receiveCurrentUser(currentUser)); - } return store; }; -export default (currentUser?: CurrentUser) => (store ? store : createStore(currentUser)); +export default () => (store ? store : createStore()); diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index 6854fa5fbb7..0c8dc2ab1d5 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* eslint-disable react/jsx-sort-props */ + import { Location } from 'history'; import { pick } from 'lodash'; import * as React from 'react'; @@ -61,9 +61,10 @@ import withIndexationGuard from '../../components/hoc/withIndexationGuard'; import { lazyLoadComponent } from '../../components/lazyLoadComponent'; import getHistory from '../../helpers/getHistory'; import { AppState } from '../../types/appstate'; -import { CurrentUser } from '../../types/types'; +import { CurrentUser } from '../../types/users'; import App from '../components/App'; import AppStateContextProvider from '../components/app-state/AppStateContextProvider'; +import CurrentUserContextProvider from '../components/current-user/CurrentUserContextProvider'; import GlobalContainer from '../components/GlobalContainer'; import { PageContext } from '../components/indexation/PageUnavailableDueToIndexation'; import MigrationContainer from '../components/MigrationContainer'; @@ -286,100 +287,105 @@ export default function startReactApp(lang: string, appState: AppState, currentU const el = document.getElementById('content'); const history = getHistory(); - const store = getStore(currentUser); + const store = getStore(); render( <HelmetProvider> <Provider store={store}> <AppStateContextProvider appState={appState}> - <IntlProvider defaultLocale={lang} locale={lang}> - <Router history={history} onUpdate={handleUpdate}> - {renderRedirects()} - - <Route - path="formatting/help" - component={lazyLoadComponent(() => import('../components/FormattingHelp'))} - /> + <CurrentUserContextProvider currentUser={currentUser}> + <IntlProvider defaultLocale={lang} locale={lang}> + <Router history={history} onUpdate={handleUpdate}> + {renderRedirects()} - <Route component={lazyLoadComponent(() => import('../components/SimpleContainer'))}> - <Route path="maintenance">{maintenanceRoutes}</Route> - <Route path="setup">{setupRoutes}</Route> - </Route> - - <Route component={MigrationContainer}> <Route - component={lazyLoadComponent(() => - import('../components/SimpleSessionsContainer') - )}> - <RouteWithChildRoutes path="/sessions" childRoutes={sessionsRoutes} /> + path="formatting/help" + component={lazyLoadComponent(() => import('../components/FormattingHelp'))} + /> + + <Route component={lazyLoadComponent(() => import('../components/SimpleContainer'))}> + <Route path="maintenance">{maintenanceRoutes}</Route> + <Route path="setup">{setupRoutes}</Route> </Route> - <Route path="/" component={App}> - <IndexRoute - component={lazyLoadComponent(() => import('../components/Landing'))} - /> + <Route component={MigrationContainer}> + <Route + component={lazyLoadComponent(() => + import('../components/SimpleSessionsContainer') + )}> + <RouteWithChildRoutes path="/sessions" childRoutes={sessionsRoutes} /> + </Route> - <Route component={GlobalContainer}> - <RouteWithChildRoutes path="account" childRoutes={accountRoutes} /> - <RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} /> - <RouteWithChildRoutes path="documentation" childRoutes={documentationRoutes} /> + <Route path="/" component={App}> + <IndexRoute + component={lazyLoadComponent(() => import('../components/Landing'))} + /> + + <Route component={GlobalContainer}> + <RouteWithChildRoutes path="account" childRoutes={accountRoutes} /> + <RouteWithChildRoutes path="coding_rules" childRoutes={codingRulesRoutes} /> + <RouteWithChildRoutes + path="documentation" + childRoutes={documentationRoutes} + /> + <Route + path="extension/:pluginKey/:extensionKey" + component={lazyLoadComponent(() => + import('../components/extensions/GlobalPageExtension') + )} + /> + <Route + path="issues" + component={withIndexationGuard(Issues, PageContext.Issues)} + /> + <RouteWithChildRoutes path="projects" childRoutes={projectsRoutes} /> + <RouteWithChildRoutes path="quality_gates" childRoutes={qualityGatesRoutes} /> + <Route + path="portfolios" + component={lazyLoadComponent(() => + import('../components/extensions/PortfoliosPage') + )} + /> + <RouteWithChildRoutes path="profiles" childRoutes={qualityProfilesRoutes} /> + <RouteWithChildRoutes path="web_api" childRoutes={webAPIRoutes} /> + + {renderComponentRoutes()} + + {renderAdminRoutes()} + </Route> + <Route + // We don't want this route to have any menu. + // That is why we can not have it under the accountRoutes + path="account/reset_password" + component={lazyLoadComponent(() => import('../components/ResetPassword'))} + /> <Route - path="extension/:pluginKey/:extensionKey" + // We don't want this route to have any menu. This is why we define it here + // rather than under the admin routes. + path="admin/change_admin_password" component={lazyLoadComponent(() => - import('../components/extensions/GlobalPageExtension') + import('../../apps/change-admin-password/ChangeAdminPasswordApp') )} /> <Route - path="issues" - component={withIndexationGuard(Issues, PageContext.Issues)} + // We don't want this route to have any menu. This is why we define it here + // rather than under the admin routes. + path="admin/plugin_risk_consent" + component={lazyLoadComponent(() => import('../components/PluginRiskConsent'))} /> - <RouteWithChildRoutes path="projects" childRoutes={projectsRoutes} /> - <RouteWithChildRoutes path="quality_gates" childRoutes={qualityGatesRoutes} /> <Route - path="portfolios" - component={lazyLoadComponent(() => - import('../components/extensions/PortfoliosPage') - )} + path="not_found" + component={lazyLoadComponent(() => import('../components/NotFound'))} + /> + <Route + path="*" + component={lazyLoadComponent(() => import('../components/NotFound'))} /> - <RouteWithChildRoutes path="profiles" childRoutes={qualityProfilesRoutes} /> - <RouteWithChildRoutes path="web_api" childRoutes={webAPIRoutes} /> - - {renderComponentRoutes()} - - {renderAdminRoutes()} </Route> - <Route - // We don't want this route to have any menu. - // That is why we can not have it under the accountRoutes - path="account/reset_password" - component={lazyLoadComponent(() => import('../components/ResetPassword'))} - /> - <Route - // We don't want this route to have any menu. This is why we define it here - // rather than under the admin routes. - path="admin/change_admin_password" - component={lazyLoadComponent(() => - import('../../apps/change-admin-password/ChangeAdminPasswordApp') - )} - /> - <Route - // We don't want this route to have any menu. This is why we define it here - // rather than under the admin routes. - path="admin/plugin_risk_consent" - component={lazyLoadComponent(() => import('../components/PluginRiskConsent'))} - /> - <Route - path="not_found" - component={lazyLoadComponent(() => import('../components/NotFound'))} - /> - <Route - path="*" - component={lazyLoadComponent(() => import('../components/NotFound'))} - /> </Route> - </Route> - </Router> - </IntlProvider> + </Router> + </IntlProvider> + </CurrentUserContextProvider> </AppStateContextProvider> </Provider> </HelmetProvider>, diff --git a/server/sonar-web/src/main/js/apps/account/components/Account.tsx b/server/sonar-web/src/main/js/apps/account/components/Account.tsx index 88741f793a4..672f3fa3da8 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Account.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/Account.tsx @@ -20,11 +20,11 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication'; import { translate } from '../../../helpers/l10n'; -import { CurrentUser, LoggedInUser } from '../../../types/types'; +import { CurrentUser, LoggedInUser } from '../../../types/users'; import '../account.css'; import Nav from './Nav'; import UserCard from './UserCard'; @@ -66,4 +66,4 @@ export class Account extends React.PureComponent<Props> { } } -export default withCurrentUser(Account); +export default withCurrentUserContext(Account); diff --git a/server/sonar-web/src/main/js/apps/account/components/Security.tsx b/server/sonar-web/src/main/js/apps/account/components/Security.tsx index 00706eb6489..1cc827ceeea 100644 --- a/server/sonar-web/src/main/js/apps/account/components/Security.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/Security.tsx @@ -19,34 +19,29 @@ */ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import ResetPasswordForm from '../../../components/common/ResetPasswordForm'; import { translate } from '../../../helpers/l10n'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import Tokens from './Tokens'; export interface SecurityProps { - user: LoggedInUser; + currentUser: LoggedInUser; } -export function Security({ user }: SecurityProps) { +export function Security({ currentUser }: SecurityProps) { return ( <div className="account-body account-container"> <Helmet defer={false} title={translate('my_account.security')} /> - <Tokens login={user.login} /> - {user.local && ( + <Tokens login={currentUser.login} /> + {currentUser.local && ( <section className="boxed-group"> <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2> - <ResetPasswordForm className="boxed-group-inner" user={user} /> + <ResetPasswordForm className="boxed-group-inner" user={currentUser} /> </section> )} </div> ); } -const mapStateToProps = (state: Store) => ({ - user: getCurrentUser(state) as LoggedInUser -}); - -export default connect(mapStateToProps)(Security); +export default withCurrentUserContext(Security); diff --git a/server/sonar-web/src/main/js/apps/account/components/UserCard.tsx b/server/sonar-web/src/main/js/apps/account/components/UserCard.tsx index 4f73fcdd974..e53c2d39c48 100644 --- a/server/sonar-web/src/main/js/apps/account/components/UserCard.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/UserCard.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import Avatar from '../../../components/ui/Avatar'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; interface Props { user: LoggedInUser; diff --git a/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx b/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx index 2420ac91bc3..30c1668fe1e 100644 --- a/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx +++ b/server/sonar-web/src/main/js/apps/account/components/__tests__/Security-test.tsx @@ -24,11 +24,11 @@ import { Security, SecurityProps } from '../Security'; it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('local user'); - expect(shallowRender({ user: mockLoggedInUser({ local: false }) })).toMatchSnapshot( + expect(shallowRender({ currentUser: mockLoggedInUser({ local: false }) })).toMatchSnapshot( 'non-local user' ); }); function shallowRender(props: Partial<SecurityProps> = {}) { - return shallow(<Security user={mockLoggedInUser({ local: true })} {...props} />); + return shallow(<Security currentUser={mockLoggedInUser({ local: true })} {...props} />); } diff --git a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.tsx b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.tsx index d8432f83169..c6dd5a8d5e2 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.tsx +++ b/server/sonar-web/src/main/js/apps/account/notifications/GlobalNotifications.tsx @@ -19,10 +19,8 @@ */ import * as React from 'react'; import { translate } from '../../../helpers/l10n'; -import { isSonarCloud } from '../../../helpers/system'; import { Notification } from '../../../types/types'; import NotificationsList from './NotificationsList'; -import SonarCloudNotifications from './SonarCloudNotifications'; interface Props { addNotification: (n: Notification) => void; @@ -34,36 +32,33 @@ interface Props { export default function GlobalNotifications(props: Props) { return ( - <> - <section className="boxed-group"> - <h2>{translate('my_profile.overall_notifications.title')}</h2> + <section className="boxed-group"> + <h2>{translate('my_profile.overall_notifications.title')}</h2> - <div className="boxed-group-inner"> - <table className="data zebra"> - <thead> - <tr> - <th /> - {props.channels.map(channel => ( - <th className="text-center" key={channel}> - <h4>{translate('notification.channel', channel)}</h4> - </th> - ))} - </tr> - </thead> + <div className="boxed-group-inner"> + <table className="data zebra"> + <thead> + <tr> + <th /> + {props.channels.map(channel => ( + <th className="text-center" key={channel}> + <h4>{translate('notification.channel', channel)}</h4> + </th> + ))} + </tr> + </thead> - <NotificationsList - channels={props.channels} - checkboxId={getCheckboxId} - notifications={props.notifications} - onAdd={props.addNotification} - onRemove={props.removeNotification} - types={props.types} - /> - </table> - </div> - </section> - {isSonarCloud() && <SonarCloudNotifications />} - </> + <NotificationsList + channels={props.channels} + checkboxId={getCheckboxId} + notifications={props.notifications} + onAdd={props.addNotification} + onRemove={props.removeNotification} + types={props.types} + /> + </table> + </div> + </section> ); } diff --git a/server/sonar-web/src/main/js/apps/account/notifications/SonarCloudNotifications.tsx b/server/sonar-web/src/main/js/apps/account/notifications/SonarCloudNotifications.tsx deleted file mode 100644 index b9ab3705190..00000000000 --- a/server/sonar-web/src/main/js/apps/account/notifications/SonarCloudNotifications.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { connect } from 'react-redux'; -import Checkbox from '../../../components/controls/Checkbox'; -import { translate } from '../../../helpers/l10n'; -import { getCurrentUserSetting, Store } from '../../../store/rootReducer'; -import { setCurrentUserSetting } from '../../../store/users'; -import { CurrentUserSetting } from '../../../types/types'; - -interface Props { - notificationsOptOut?: boolean; - setCurrentUserSetting: (setting: CurrentUserSetting) => void; -} - -export class SonarCloudNotifications extends React.PureComponent<Props> { - handleCheckOptOut = (checked: boolean) => { - this.props.setCurrentUserSetting({ - key: 'notifications.optOut', - value: checked ? 'false' : 'true' - }); - }; - - render() { - return ( - <section className="boxed-group"> - <h2>{translate('my_profile.sonarcloud_feature_notifications.title')}</h2> - <div className="boxed-group-inner"> - <table className="data zebra"> - <thead> - <tr> - <th /> - <th className="text-center"> - <h4>{translate('activate')}</h4> - </th> - </tr> - </thead> - <tbody> - <tr> - <td>{translate('my_profile.sonarcloud_feature_notifications.description')}</td> - <td className="text-center"> - <Checkbox - checked={!this.props.notificationsOptOut} - onCheck={this.handleCheckOptOut} - /> - </td> - </tr> - </tbody> - </table> - </div> - </section> - ); - } -} - -const mapStateToProps = (state: Store) => { - const notificationsOptOut = getCurrentUserSetting(state, 'notifications.optOut') === 'true'; - - return { - notificationsOptOut - }; -}; - -const mapDispatchToProps = { - setCurrentUserSetting -}; - -export default connect(mapStateToProps, mapDispatchToProps)(SonarCloudNotifications); diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/SonarCloudNotifications-test.tsx b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/SonarCloudNotifications-test.tsx deleted file mode 100644 index 5f39c574658..00000000000 --- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/SonarCloudNotifications-test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { SonarCloudNotifications } from '../SonarCloudNotifications'; - -it('should match snapshot', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -function shallowRender(props: Partial<SonarCloudNotifications['props']> = {}) { - return shallow( - <SonarCloudNotifications - notificationsOptOut={true} - setCurrentUserSetting={jest.fn()} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.tsx.snap index 2eb1e232053..59424c1894d 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/GlobalNotifications-test.tsx.snap @@ -1,150 +1,145 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should match snapshot 1`] = ` -<Fragment> - <section - className="boxed-group" +<section + className="boxed-group" +> + <h2> + my_profile.overall_notifications.title + </h2> + <div + className="boxed-group-inner" > - <h2> - my_profile.overall_notifications.title - </h2> - <div - className="boxed-group-inner" + <table + className="data zebra" > - <table - className="data zebra" - > - <thead> - <tr> - <th /> - <th - className="text-center" - key="channel1" - > - <h4> - notification.channel.channel1 - </h4> - </th> - <th - className="text-center" - key="channel2" - > - <h4> - notification.channel.channel2 - </h4> - </th> - </tr> - </thead> - <NotificationsList - channels={ - Array [ - "channel1", - "channel2", - ] - } - checkboxId={[Function]} - notifications={ - Array [ - Object { - "channel": "channel1", - "type": "type1", - }, - Object { - "channel": "channel1", - "type": "type2", - }, - Object { - "channel": "channel2", - "type": "type2", - }, - ] - } - onAdd={[MockFunction]} - onRemove={[MockFunction]} - types={ - Array [ - "type1", - "type2", - ] - } - /> - </table> - </div> - </section> -</Fragment> + <thead> + <tr> + <th /> + <th + className="text-center" + key="channel1" + > + <h4> + notification.channel.channel1 + </h4> + </th> + <th + className="text-center" + key="channel2" + > + <h4> + notification.channel.channel2 + </h4> + </th> + </tr> + </thead> + <NotificationsList + channels={ + Array [ + "channel1", + "channel2", + ] + } + checkboxId={[Function]} + notifications={ + Array [ + Object { + "channel": "channel1", + "type": "type1", + }, + Object { + "channel": "channel1", + "type": "type2", + }, + Object { + "channel": "channel2", + "type": "type2", + }, + ] + } + onAdd={[MockFunction]} + onRemove={[MockFunction]} + types={ + Array [ + "type1", + "type2", + ] + } + /> + </table> + </div> +</section> `; exports[`should show SonarCloud options if in SC context 1`] = ` -<Fragment> - <section - className="boxed-group" +<section + className="boxed-group" +> + <h2> + my_profile.overall_notifications.title + </h2> + <div + className="boxed-group-inner" > - <h2> - my_profile.overall_notifications.title - </h2> - <div - className="boxed-group-inner" + <table + className="data zebra" > - <table - className="data zebra" - > - <thead> - <tr> - <th /> - <th - className="text-center" - key="channel1" - > - <h4> - notification.channel.channel1 - </h4> - </th> - <th - className="text-center" - key="channel2" - > - <h4> - notification.channel.channel2 - </h4> - </th> - </tr> - </thead> - <NotificationsList - channels={ - Array [ - "channel1", - "channel2", - ] - } - checkboxId={[Function]} - notifications={ - Array [ - Object { - "channel": "channel1", - "type": "type1", - }, - Object { - "channel": "channel1", - "type": "type2", - }, - Object { - "channel": "channel2", - "type": "type2", - }, - ] - } - onAdd={[MockFunction]} - onRemove={[MockFunction]} - types={ - Array [ - "type1", - "type2", - ] - } - /> - </table> - </div> - </section> - <Connect(SonarCloudNotifications) /> -</Fragment> + <thead> + <tr> + <th /> + <th + className="text-center" + key="channel1" + > + <h4> + notification.channel.channel1 + </h4> + </th> + <th + className="text-center" + key="channel2" + > + <h4> + notification.channel.channel2 + </h4> + </th> + </tr> + </thead> + <NotificationsList + channels={ + Array [ + "channel1", + "channel2", + ] + } + checkboxId={[Function]} + notifications={ + Array [ + Object { + "channel": "channel1", + "type": "type1", + }, + Object { + "channel": "channel1", + "type": "type2", + }, + Object { + "channel": "channel2", + "type": "type2", + }, + ] + } + onAdd={[MockFunction]} + onRemove={[MockFunction]} + types={ + Array [ + "type1", + "type2", + ] + } + /> + </table> + </div> +</section> `; diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/SonarCloudNotifications-test.tsx.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/SonarCloudNotifications-test.tsx.snap deleted file mode 100644 index f70cefb6e58..00000000000 --- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/SonarCloudNotifications-test.tsx.snap +++ /dev/null @@ -1,47 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should match snapshot 1`] = ` -<section - className="boxed-group" -> - <h2> - my_profile.sonarcloud_feature_notifications.title - </h2> - <div - className="boxed-group-inner" - > - <table - className="data zebra" - > - <thead> - <tr> - <th /> - <th - className="text-center" - > - <h4> - activate - </h4> - </th> - </tr> - </thead> - <tbody> - <tr> - <td> - my_profile.sonarcloud_feature_notifications.description - </td> - <td - className="text-center" - > - <Checkbox - checked={false} - onCheck={[Function]} - thirdState={false} - /> - </td> - </tr> - </tbody> - </table> - </div> -</section> -`; diff --git a/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx b/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx index e8d94c041e2..45fb5a5ffd5 100644 --- a/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx +++ b/server/sonar-web/src/main/js/apps/account/profile/Profile.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import HelpTooltip from '../../../components/controls/HelpTooltip'; import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn'; import { translate } from '../../../helpers/l10n'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import UserExternalIdentity from './UserExternalIdentity'; export interface ProfileProps { diff --git a/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.tsx b/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.tsx index f6c17d12201..c97fb3e6adb 100644 --- a/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.tsx +++ b/server/sonar-web/src/main/js/apps/account/profile/UserExternalIdentity.tsx @@ -22,7 +22,8 @@ import { getIdentityProviders } from '../../../api/users'; import { colors } from '../../../app/theme'; import { getTextColor } from '../../../helpers/colors'; import { getBaseUrl } from '../../../helpers/system'; -import { IdentityProvider, LoggedInUser } from '../../../types/types'; +import { IdentityProvider } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; export interface UserExternalIdentityProps { user: LoggedInUser; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx index a49dfd37afd..53a3f6da600 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx @@ -21,11 +21,11 @@ import key from 'keymaster'; import { keyBy } from 'lodash'; import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; import { withRouter, WithRouterProps } from 'react-router'; import { Profile, searchQualityProfiles } from '../../../api/quality-profiles'; import { getRulesApp, searchRules } from '../../../api/rules'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import FiltersHeader from '../../../components/common/FiltersHeader'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; @@ -41,10 +41,9 @@ import { removeWhitePageClass } from '../../../helpers/pages'; import { scrollToElement } from '../../../helpers/scrolling'; -import { isLoggedIn } from '../../../helpers/users'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; import { SecurityStandard } from '../../../types/security'; -import { CurrentUser, Dict, Paging, RawQuery, Rule, RuleActivation } from '../../../types/types'; +import { Dict, Paging, RawQuery, Rule, RuleActivation } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import { shouldOpenSonarSourceSecurityFacet, shouldOpenStandardsChildFacet, @@ -690,8 +689,4 @@ function parseFacets(rawFacets: { property: string; values: { count: number; val return facets; } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default withRouter(connect(mapStateToProps)(App)); +export default withRouter(withCurrentUserContext(App)); diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx index 4c4a3d7bbb6..1f9706f2148 100644 --- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx @@ -28,7 +28,7 @@ import { translate } from '../../../helpers/l10n'; import { getProjectUrl } from '../../../helpers/urls'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { AppState } from '../../../types/appstate'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AlmBindingDefinitionForm from '../../settings/components/almIntegration/AlmBindingDefinitionForm'; import AzureProjectCreate from './AzureProjectCreate'; import BitbucketCloudProjectCreate from './BitbucketCloudProjectCreate'; diff --git a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx index 2423ee9687a..1e3578afcb1 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx @@ -19,21 +19,17 @@ */ import { connect } from 'react-redux'; import { searchIssues } from '../../../api/issues'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { withRouter } from '../../../components/hoc/withRouter'; import { lazyLoadComponent } from '../../../components/lazyLoadComponent'; import { parseIssueFromResponse } from '../../../helpers/issues'; import { fetchBranchStatus } from '../../../store/rootActions'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; +import { Store } from '../../../store/rootReducer'; import { FetchIssuesPromise } from '../../../types/issues'; import { RawQuery } from '../../../types/types'; const IssuesAppContainer = lazyLoadComponent(() => import('./IssuesApp'), 'IssuesAppContainer'); -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state), - fetchIssues -}); - const fetchIssues = (query: RawQuery) => { return searchIssues({ ...query, @@ -47,6 +43,12 @@ const fetchIssues = (query: RawQuery) => { }); }; +const mapStateToProps = (_state: Store) => ({ + fetchIssues +}); + const mapDispatchToProps = { fetchBranchStatus }; -export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IssuesAppContainer)); +export default withRouter( + withCurrentUserContext(connect(mapStateToProps, mapDispatchToProps)(IssuesAppContainer)) +); diff --git a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx index 52b4dc306b8..fe751666118 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx @@ -36,8 +36,8 @@ import SeverityHelper from '../../../components/shared/SeverityHelper'; import { Alert } from '../../../components/ui/Alert'; import Avatar from '../../../components/ui/Avatar'; import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { isLoggedIn, isUserActive } from '../../../helpers/users'; -import { Component, CurrentUser, Dict, Issue, IssueType, Paging } from '../../../types/types'; +import { Component, Dict, Issue, IssueType, Paging } from '../../../types/types'; +import { CurrentUser, isLoggedIn, isUserActive } from '../../../types/users'; import { searchAssignees } from '../utils'; interface AssigneeOption { diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx index 60a57ed3c92..848b4da99fe 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx @@ -62,15 +62,8 @@ import { ReferencedRule } from '../../../types/issues'; import { SecurityStandard } from '../../../types/security'; -import { - Component, - CurrentUser, - Dict, - Issue, - Paging, - RawQuery, - UserBase -} from '../../../types/types'; +import { Component, Dict, Issue, Paging, RawQuery } from '../../../types/types'; +import { CurrentUser, UserBase } from '../../../types/users'; import * as actions from '../actions'; import ConciseIssuesList from '../conciseIssuesList/ConciseIssuesList'; import ConciseIssuesListHeader from '../conciseIssuesList/ConciseIssuesListHeader'; diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/AppContainer-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/AppContainer-test.tsx index 84b7426c79b..b1543639017 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/AppContainer-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/AppContainer-test.tsx @@ -19,7 +19,6 @@ */ import { connect } from 'react-redux'; import { searchIssues } from '../../../../api/issues'; -import { mockCurrentUser } from '../../../../helpers/testMocks'; import { fetchBranchStatus } from '../../../../store/rootActions'; import '../AppContainer'; @@ -35,19 +34,11 @@ jest.mock('../../../../helpers/issues', () => ({ parseIssueFromResponse: jest.fn(() => 'parsedIssue') })); -jest.mock('../../../../store/rootReducer', () => { - const { mockCurrentUser } = jest.requireActual('../../../../helpers/testMocks'); - return { - getCurrentUser: jest.fn(() => mockCurrentUser()) - }; -}); - describe('redux', () => { it('should correctly map state and dispatch props', async () => { const [mapStateToProps, mapDispatchToProps] = (connect as jest.Mock).mock.calls[0]; - const { currentUser, fetchIssues } = mapStateToProps({}); + const { fetchIssues } = mapStateToProps({}); - expect(currentUser).toEqual(mockCurrentUser()); expect(mapDispatchToProps).toEqual(expect.objectContaining({ fetchBranchStatus })); const result = await fetchIssues({ foo: 'bar' }); diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/PageActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/PageActions-test.tsx.snap index 7424582257a..1f7f77d4a93 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/PageActions-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/PageActions-test.tsx.snap @@ -15,7 +15,7 @@ exports[`should render 1`] = ` effort={125} /> </div> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="huge-spacer-left" currentPage={ Object { diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx index 7a9c8a49ae2..9412a6395f7 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx @@ -23,9 +23,9 @@ import ListStyleFacet from '../../../components/facet/ListStyleFacet'; import Avatar from '../../../components/ui/Avatar'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { highlightTerm } from '../../../helpers/search'; -import { isUserActive } from '../../../helpers/users'; import { Facet } from '../../../types/issues'; -import { Dict, UserBase } from '../../../types/types'; +import { Dict } from '../../../types/types'; +import { isUserActive, UserBase } from '../../../types/users'; import { Query, searchAssignees } from '../utils'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx index 4a80bd6dd96..e15af101eac 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx @@ -30,7 +30,8 @@ import { ReferencedRule } from '../../../types/issues'; import { GlobalSettingKeys } from '../../../types/settings'; -import { Component, Dict, UserBase } from '../../../types/types'; +import { Component, Dict } from '../../../types/types'; +import { UserBase } from '../../../types/users'; import { Query } from '../utils'; import AssigneeFacet from './AssigneeFacet'; import AuthorFacet from './AuthorFacet'; diff --git a/server/sonar-web/src/main/js/apps/issues/utils.ts b/server/sonar-web/src/main/js/apps/issues/utils.ts index b022a30dc8b..7b478ec8559 100644 --- a/server/sonar-web/src/main/js/apps/issues/utils.ts +++ b/server/sonar-web/src/main/js/apps/issues/utils.ts @@ -36,7 +36,8 @@ import { get, save } from '../../helpers/storage'; import { isDefined } from '../../helpers/types'; import { Facet, RawFacet } from '../../types/issues'; import { SecurityStandard, StandardType } from '../../types/security'; -import { Dict, Issue, Paging, RawQuery, UserBase } from '../../types/types'; +import { Dict, Issue, Paging, RawQuery } from '../../types/types'; +import { UserBase } from '../../types/users'; export interface Query { assigned: boolean; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/FirstAnalysisNextStepsNotif.tsx b/server/sonar-web/src/main/js/apps/overview/branches/FirstAnalysisNextStepsNotif.tsx index 75a755a2975..fa57e1b9d0f 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/FirstAnalysisNextStepsNotif.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/FirstAnalysisNextStepsNotif.tsx @@ -20,13 +20,13 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import DismissableAlert from '../../../components/ui/DismissableAlert'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; import { ProjectAlmBindingResponse } from '../../../types/alm-settings'; import { ComponentQualifier } from '../../../types/component'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import { PULL_REQUEST_DECORATION_BINDING_CATEGORY } from '../../settings/components/AdditionalCategoryKeys'; export interface FirstAnalysisNextStepsNotifProps { @@ -130,4 +130,4 @@ export function FirstAnalysisNextStepsNotif(props: FirstAnalysisNextStepsNotifPr ); } -export default withCurrentUser(FirstAnalysisNextStepsNotif); +export default withCurrentUserContext(FirstAnalysisNextStepsNotif); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap index 0ceef54903a..2b0909eaafe 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/BranchOverviewRenderer-test.tsx.snap @@ -2,7 +2,7 @@ exports[`should render correctly: default 1`] = ` <Fragment> - <Connect(withCurrentUser(FirstAnalysisNextStepsNotif)) + <withCurrentUserContext(FirstAnalysisNextStepsNotif) component={ Object { "breadcrumbs": Array [], @@ -173,7 +173,7 @@ exports[`should render correctly: default 1`] = ` exports[`should render correctly: empty project 1`] = ` <Fragment> - <Connect(withCurrentUser(FirstAnalysisNextStepsNotif)) + <withCurrentUserContext(FirstAnalysisNextStepsNotif) component={ Object { "breadcrumbs": Array [], @@ -265,7 +265,7 @@ exports[`should render correctly: empty project 1`] = ` exports[`should render correctly: loading 1`] = ` <Fragment> - <Connect(withCurrentUser(FirstAnalysisNextStepsNotif)) + <withCurrentUserContext(FirstAnalysisNextStepsNotif) component={ Object { "breadcrumbs": Array [], diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap index f274625ecca..d274642205a 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap @@ -13,7 +13,7 @@ exports[`should render correctly for applications 1`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -735,7 +735,7 @@ exports[`should render correctly for applications 2`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -1667,7 +1667,7 @@ exports[`should render correctly for projects 1`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -2389,7 +2389,7 @@ exports[`should render correctly for projects 2`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -3321,7 +3321,7 @@ exports[`should render correctly if branch is misconfigured: hide settings 1`] = > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -3462,7 +3462,7 @@ exports[`should render correctly if branch is misconfigured: show settings 1`] = > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -3609,7 +3609,7 @@ exports[`should render correctly if the data is still loading 1`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -3665,7 +3665,7 @@ exports[`should render correctly if there is no coverage 1`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", @@ -4119,7 +4119,7 @@ exports[`should render correctly if there is no new code measures 1`] = ` > overview.measures </h2> - <Connect(withCurrentUser(withAppStateContext(ComponentReportActions))) + <withCurrentUserContext(withAppStateContext(ComponentReportActions)) branch={ Object { "analysisDate": "2018-01-01", diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap index 4c5d74724c9..bc040b08461 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap @@ -182,7 +182,7 @@ exports[`should render correctly for applications 1`] = ` /> </div> </div> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={ Array [ Object { @@ -395,7 +395,7 @@ exports[`should render correctly for applications 2`] = ` /> </div> </div> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={ Array [ Object { @@ -528,7 +528,7 @@ exports[`should render correctly for projects 1`] = ` /> </div> </div> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={ Array [ Object { @@ -599,7 +599,7 @@ exports[`should render correctly for projects 2`] = ` </span> </div> </div> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={Array []} /> </div> @@ -721,7 +721,7 @@ exports[`should render correctly for projects 3`] = ` /> </div> </div> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={ Array [ Object { diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx index fcf72dd063e..d85ec9885b1 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx @@ -19,17 +19,16 @@ */ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import TutorialSelection from '../../../components/tutorials/TutorialSelection'; import { Alert } from '../../../components/ui/Alert'; import { getBranchLikeDisplayName, isBranch, isMainBranch } from '../../../helpers/branch-like'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; import { ProjectAlmBindingResponse } from '../../../types/alm-settings'; import { BranchLike } from '../../../types/branch-like'; import { ComponentQualifier } from '../../../types/component'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; export interface EmptyOverviewProps { branchLike?: BranchLike; @@ -106,8 +105,4 @@ export function EmptyOverview(props: EmptyOverviewProps) { ); } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(EmptyOverview); +export default withCurrentUserContext(EmptyOverview); diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx index f40fafe645b..e183f17cc6e 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx @@ -19,12 +19,12 @@ */ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import SonarLintIcon from '../../../components/icons/SonarLintIcon'; import { translate } from '../../../helpers/l10n'; import { MetricKey } from '../../../types/metrics'; import { QualityGateStatusCondition } from '../../../types/quality-gates'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; export interface SonarLintPromotionProps { currentUser: CurrentUser; @@ -77,4 +77,4 @@ export function SonarLintPromotion({ currentUser, qgConditions }: SonarLintPromo ); } -export default withCurrentUser(SonarLintPromotion); +export default withCurrentUserContext(SonarLintPromotion); diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap index c3348c42010..4b272aefe8c 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap @@ -53,7 +53,7 @@ exports[`should render correctly for a failed QG 1`] = ` } level="ERROR" /> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={ Array [ Object { @@ -1424,7 +1424,7 @@ exports[`should render correctly for a passed QG 1`] = ` } level="OK" /> - <Connect(withCurrentUser(SonarLintPromotion)) + <withCurrentUserContext(SonarLintPromotion) qgConditions={Array []} /> </div> diff --git a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts b/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts deleted file mode 100644 index ff02df040d5..00000000000 --- a/server/sonar-web/src/main/js/apps/permissions/project/components/AppContainer.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { connect } from 'react-redux'; -import { getCurrentUser, Store } from '../../../../store/rootReducer'; -import App from './App'; - -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(mapStateToProps)(App); diff --git a/server/sonar-web/src/main/js/apps/permissions/routes.ts b/server/sonar-web/src/main/js/apps/permissions/routes.ts index 1f5d65fea2d..98674c85e9f 100644 --- a/server/sonar-web/src/main/js/apps/permissions/routes.ts +++ b/server/sonar-web/src/main/js/apps/permissions/routes.ts @@ -27,6 +27,6 @@ export const globalPermissionsRoutes = [ export const projectPermissionsRoutes = [ { - indexRoute: { component: lazyLoadComponent(() => import('./project/components/AppContainer')) } + indexRoute: { component: lazyLoadComponent(() => import('./project/components/App')) } } ]; diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx index ed14cc84902..202a721c916 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx @@ -22,6 +22,7 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; import ListFooter from '../../../components/controls/ListFooter'; @@ -32,10 +33,10 @@ import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthent import { translate } from '../../../helpers/l10n'; import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages'; import { get, save } from '../../../helpers/storage'; -import { isLoggedIn } from '../../../helpers/users'; import { AppState } from '../../../types/appstate'; import { ComponentQualifier } from '../../../types/component'; -import { CurrentUser, RawQuery } from '../../../types/types'; +import { RawQuery } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import { hasFilterParams, hasViewParams, parseUrlQuery, Query } from '../query'; import '../styles.css'; import { Facets, Project } from '../types'; @@ -317,4 +318,4 @@ export class AllProjects extends React.PureComponent<Props, State> { } } -export default withRouter(withAppStateContext(AllProjects)); +export default withRouter(withCurrentUserContext(withAppStateContext(AllProjects))); diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx index c1d5e5491ca..01d581d97a7 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx @@ -17,12 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { connect } from 'react-redux'; import { lazyLoadComponent } from '../../../components/lazyLoadComponent'; -import { getCurrentUser, Store } from '../../../store/rootReducer'; -const stateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) -}); - -export default connect(stateToProps)(lazyLoadComponent(() => import('./AllProjects'))); +export default lazyLoadComponent(() => import('./AllProjects')); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx b/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx index dac6645952c..f58be34596e 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ApplicationCreation.tsx @@ -20,9 +20,9 @@ import * as React from 'react'; import { getComponentNavigation } from '../../../api/nav'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import CreateApplicationForm from '../../../app/components/extensions/CreateApplicationForm'; import { Button } from '../../../components/controls/buttons'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { Router, withRouter } from '../../../components/hoc/withRouter'; import { translate } from '../../../helpers/l10n'; import { getComponentAdminUrl, getComponentOverviewUrl } from '../../../helpers/urls'; @@ -30,7 +30,7 @@ import { hasGlobalPermission } from '../../../helpers/users'; import { AppState } from '../../../types/appstate'; import { ComponentQualifier } from '../../../types/component'; import { Permissions } from '../../../types/permissions'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; export interface ApplicationCreationProps { appState: AppState; @@ -85,4 +85,4 @@ export function ApplicationCreation(props: ApplicationCreationProps) { ); } -export default withCurrentUser(withRouter(withAppStateContext(ApplicationCreation))); +export default withCurrentUserContext(withRouter(withAppStateContext(ApplicationCreation))); diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx index dedb51d3b81..d8886bd7be4 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx @@ -19,11 +19,11 @@ */ import * as React from 'react'; import { searchProjects } from '../../../api/components'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { Location, Router, withRouter } from '../../../components/hoc/withRouter'; import { get } from '../../../helpers/storage'; -import { hasGlobalPermission, isLoggedIn } from '../../../helpers/users'; -import { CurrentUser } from '../../../types/types'; +import { hasGlobalPermission } from '../../../helpers/users'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import { PROJECTS_ALL, PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE } from '../utils'; import AllProjectsContainer from './AllProjectsContainer'; @@ -98,4 +98,4 @@ export class DefaultPageSelector extends React.PureComponent<Props, State> { } } -export default withCurrentUser(withRouter(DefaultPageSelector)); +export default withCurrentUserContext(withRouter(DefaultPageSelector)); diff --git a/server/sonar-web/src/main/js/apps/projects/components/EmptyInstance.tsx b/server/sonar-web/src/main/js/apps/projects/components/EmptyInstance.tsx index af4d77863d4..6a201c2eb1b 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/EmptyInstance.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/EmptyInstance.tsx @@ -22,9 +22,9 @@ import { WithRouterProps } from 'react-router'; import { Button } from '../../../components/controls/buttons'; import { withRouter } from '../../../components/hoc/withRouter'; import { translate } from '../../../helpers/l10n'; -import { hasGlobalPermission, isLoggedIn } from '../../../helpers/users'; +import { hasGlobalPermission } from '../../../helpers/users'; import { Permissions } from '../../../types/permissions'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; export interface EmptyInstanceProps { currentUser: CurrentUser; diff --git a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.tsx b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.tsx index 7faf236ac6f..2b5374afe61 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/FavoriteFilter.tsx @@ -19,10 +19,11 @@ */ import * as React from 'react'; import { IndexLink, Link } from 'react-router'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { translate } from '../../../helpers/l10n'; import { save } from '../../../helpers/storage'; -import { isLoggedIn } from '../../../helpers/users'; -import { CurrentUser, RawQuery } from '../../../types/types'; +import { RawQuery } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import { PROJECTS_ALL, PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE } from '../utils'; interface Props { @@ -30,7 +31,7 @@ interface Props { query?: RawQuery; } -export default class FavoriteFilter extends React.PureComponent<Props> { +export class FavoriteFilter extends React.PureComponent<Props> { handleSaveFavorite = () => { save(PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE); }; @@ -71,3 +72,5 @@ export default class FavoriteFilter extends React.PureComponent<Props> { ); } } + +export default withCurrentUserContext(FavoriteFilter); diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx index 594cea686cb..1fc7c467d40 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx @@ -21,8 +21,8 @@ import classNames from 'classnames'; import * as React from 'react'; import HomePageSelect from '../../../components/controls/HomePageSelect'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; -import { CurrentUser, RawQuery } from '../../../types/types'; +import { RawQuery } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import SearchFilterContainer from '../filters/SearchFilterContainer'; import ApplicationCreation from './ApplicationCreation'; import PerspectiveSelect from './PerspectiveSelect'; diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx index 0c487635681..56df9dbde61 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageSidebar.tsx @@ -41,7 +41,7 @@ import TagsFilter from '../filters/TagsFilter'; import { hasFilterParams } from '../query'; import { Facets } from '../types'; import ClearAll from './ClearAll'; -import FavoriteFilterContainer from './FavoriteFilterContainer'; +import FavoriteFilter from './FavoriteFilter'; export interface PageSidebarProps { applicationsEnabled: boolean; @@ -66,7 +66,7 @@ export default function PageSidebar(props: PageSidebarProps) { return ( <div> - <FavoriteFilterContainer query={linkQuery} /> + <FavoriteFilter query={linkQuery} /> <div className="projects-facets-header clearfix"> {isFiltered && <ClearAll onClearAll={props.onClearAll} />} diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx index aec4f5d6acc..b1cd167c7f5 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx @@ -20,9 +20,9 @@ import * as React from 'react'; import { Link } from 'react-router'; import { getAlmSettings } from '../../../api/alm-settings'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { Button } from '../../../components/controls/buttons'; import Dropdown from '../../../components/controls/Dropdown'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import DropdownIcon from '../../../components/icons/DropdownIcon'; import EllipsisIcon from '../../../components/icons/EllipsisIcon'; import { IMPORT_COMPATIBLE_ALMS, IMPORT_COMPATIBLE_ALM_COUNT } from '../../../helpers/constants'; @@ -30,7 +30,7 @@ import { translate } from '../../../helpers/l10n'; import { hasGlobalPermission } from '../../../helpers/users'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { Permissions } from '../../../types/permissions'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import ProjectCreationMenuItem from './ProjectCreationMenuItem'; interface Props { @@ -143,4 +143,4 @@ export class ProjectCreationMenu extends React.PureComponent<Props, State> { } } -export default withCurrentUser(ProjectCreationMenu); +export default withCurrentUserContext(ProjectCreationMenu); diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx index 82b3be45bc0..38c646cc9eb 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx @@ -23,7 +23,7 @@ import { List, ListRowProps } from 'react-virtualized/dist/commonjs/List'; import { WindowScroller } from 'react-virtualized/dist/commonjs/WindowScroller'; import EmptySearch from '../../../components/common/EmptySearch'; import { translate } from '../../../helpers/l10n'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; import { Query } from '../query'; import { Project } from '../types'; import EmptyFavoriteSearch from './EmptyFavoriteSearch'; diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx index a37123a9c40..2dacccf17b2 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx @@ -29,7 +29,7 @@ import { } from '../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../helpers/testUtils'; import { hasGlobalPermission } from '../../../../helpers/users'; -import { CurrentUser } from '../../../../types/types'; +import { CurrentUser } from '../../../../types/users'; import { DefaultPageSelector } from '../DefaultPageSelector'; jest.mock( diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/FavoriteFilter-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/FavoriteFilter-test.tsx index 12fb0289be6..58da88c51a5 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/FavoriteFilter-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/FavoriteFilter-test.tsx @@ -21,7 +21,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { save } from '../../../../helpers/storage'; import { click } from '../../../../helpers/testUtils'; -import FavoriteFilter from '../FavoriteFilter'; +import { FavoriteFilter } from '../FavoriteFilter'; jest.mock('../../../../helpers/storage', () => ({ save: jest.fn() diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap index 8dff4f4dd70..7d4af9871aa 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageHeader-test.tsx.snap @@ -18,13 +18,13 @@ exports[`should render correctly 1`] = ` <div className="display-flex-center" > - <Connect(withCurrentUser(ProjectCreationMenu)) + <withCurrentUserContext(ProjectCreationMenu) className="little-spacer-right" /> - <Connect(withCurrentUser(withRouter(withAppStateContext(ApplicationCreation)))) + <withCurrentUserContext(withRouter(withAppStateContext(ApplicationCreation))) className="little-spacer-right" /> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="spacer-left little-spacer-right" currentPage={ Object { @@ -94,13 +94,13 @@ exports[`should render correctly while loading 1`] = ` <div className="display-flex-center" > - <Connect(withCurrentUser(ProjectCreationMenu)) + <withCurrentUserContext(ProjectCreationMenu) className="little-spacer-right" /> - <Connect(withCurrentUser(withRouter(withAppStateContext(ApplicationCreation)))) + <withCurrentUserContext(withRouter(withAppStateContext(ApplicationCreation))) className="little-spacer-right" /> - <Connect(HomePageSelect) + <withCurrentUserContext(HomePageSelect) className="spacer-left little-spacer-right" currentPage={ Object { diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap index ed70b96f32f..f1b995718ab 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/PageSidebar-test.tsx.snap @@ -2,7 +2,7 @@ exports[`should render \`leak\` view correctly 1`] = ` <div> - <Connect(FavoriteFilter) + <withCurrentUserContext(FavoriteFilter) query={ Object { "view": "leak", @@ -68,7 +68,7 @@ exports[`should render \`leak\` view correctly 1`] = ` exports[`should render \`leak\` view correctly with no applications 1`] = ` <div> - <Connect(FavoriteFilter) + <withCurrentUserContext(FavoriteFilter) query={ Object { "view": "leak", @@ -131,7 +131,7 @@ exports[`should render \`leak\` view correctly with no applications 1`] = ` exports[`should render correctly 1`] = ` <div> - <Connect(FavoriteFilter) /> + <withCurrentUserContext(FavoriteFilter) /> <div className="projects-facets-header clearfix" > @@ -193,7 +193,7 @@ exports[`should render correctly 1`] = ` exports[`should render correctly with no applications 1`] = ` <div> - <Connect(FavoriteFilter) /> + <withCurrentUserContext(FavoriteFilter) /> <div className="projects-facets-header clearfix" > diff --git a/server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx b/server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx index d8e0dc3f0dd..473850bda5f 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx @@ -32,10 +32,9 @@ import TagsList from '../../../../components/tags/TagsList'; import SizeRating from '../../../../components/ui/SizeRating'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; import { getProjectUrl } from '../../../../helpers/urls'; -import { isLoggedIn } from '../../../../helpers/users'; import { ComponentQualifier } from '../../../../types/component'; import { MetricKey } from '../../../../types/metrics'; -import { CurrentUser } from '../../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../../types/users'; import { Project } from '../../types'; import './ProjectCard.css'; import ProjectCardLanguages from './ProjectCardLanguages'; diff --git a/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx index f98763cc16b..11e5941ac64 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx @@ -23,7 +23,7 @@ import PrivacyBadgeContainer from '../../../../../components/common/PrivacyBadge import TagsList from '../../../../../components/tags/TagsList'; import { mockCurrentUser, mockLoggedInUser } from '../../../../../helpers/testMocks'; import { ComponentQualifier } from '../../../../../types/component'; -import { CurrentUser } from '../../../../../types/types'; +import { CurrentUser } from '../../../../../types/users'; import { Project } from '../../../types'; import ProjectCard from '../ProjectCard'; import ProjectCardQualityGate from '../ProjectCardQualityGate'; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx index be9c7f03620..8c4c13d024f 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/App.tsx @@ -20,19 +20,19 @@ import { debounce, uniq, without } from 'lodash'; import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { connect } from 'react-redux'; import { getComponents, Project } from '../../api/components'; import { changeProjectDefaultVisibility } from '../../api/permissions'; import { getValues } from '../../api/settings'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import Suggestions from '../../app/components/embed-docs-modal/Suggestions'; import ListFooter from '../../components/controls/ListFooter'; import { toShortNotSoISOString } from '../../helpers/dates'; import { translate } from '../../helpers/l10n'; import { hasGlobalPermission } from '../../helpers/users'; -import { getCurrentUser, Store } from '../../store/rootReducer'; import { Permissions } from '../../types/permissions'; import { SettingsKey } from '../../types/settings'; -import { LoggedInUser, Visibility } from '../../types/types'; +import { Visibility } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import CreateProjectForm from './CreateProjectForm'; import Header from './Header'; import Projects from './Projects'; @@ -259,8 +259,4 @@ export class App extends React.PureComponent<Props, State> { } } -const mapStateToProps = (state: Store) => ({ - currentUser: getCurrentUser(state) as LoggedInUser -}); - -export default connect(mapStateToProps)(App); +export default withCurrentUserContext(App); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx index a3a3cc20122..7f96d1b14ff 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRow.tsx @@ -26,7 +26,7 @@ import Tooltip from '../../components/controls/Tooltip'; import QualifierIcon from '../../components/icons/QualifierIcon'; import DateFormatter from '../../components/intl/DateFormatter'; import { getComponentOverviewUrl } from '../../helpers/urls'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import './ProjectRow.css'; import ProjectRowActions from './ProjectRowActions'; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx index f454e0cb80d..6a592edf6d9 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/ProjectRowActions.tsx @@ -24,7 +24,7 @@ import ActionsDropdown, { ActionsDropdownItem } from '../../components/controls/ import DeferredSpinner from '../../components/ui/DeferredSpinner'; import { translate } from '../../helpers/l10n'; import { getComponentPermissionsUrl } from '../../helpers/urls'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import ApplyTemplate from '../permissions/project/components/ApplyTemplate'; import RestoreAccessModal from './RestoreAccessModal'; diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx index c4bd4661a4f..577ae936ddd 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/Projects.tsx @@ -21,7 +21,7 @@ import classNames from 'classnames'; import * as React from 'react'; import { Project } from '../../api/components'; import { translate } from '../../helpers/l10n'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import ProjectRow from './ProjectRow'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx index 10c6c8d111c..7c19085d7b9 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/RestoreAccessModal.tsx @@ -24,7 +24,7 @@ import { grantPermissionToUser } from '../../api/permissions'; import { ResetButtonLink, SubmitButton } from '../../components/controls/buttons'; import Modal from '../../components/controls/Modal'; import { translate } from '../../helpers/l10n'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; interface Props { currentUser: Pick<LoggedInUser, 'login'>; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx index 1cf8c3504ca..3acb730163f 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx @@ -22,7 +22,7 @@ import { DeleteButton } from '../../../components/controls/buttons'; import GroupIcon from '../../../components/icons/GroupIcon'; import Avatar from '../../../components/ui/Avatar'; import { Group, isUser } from '../../../types/quality-gates'; -import { UserBase } from '../../../types/types'; +import { UserBase } from '../../../types/users'; export interface PermissionItemProps { onClickDelete: (item: UserBase | Group) => void; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissions.tsx index ea81a999981..3a9c7e0cc1b 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissions.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissions.tsx @@ -28,7 +28,8 @@ import { searchUsers } from '../../../api/quality-gates'; import { Group, isUser, SearchPermissionsParameters } from '../../../types/quality-gates'; -import { QualityGate, UserBase } from '../../../types/types'; +import { QualityGate } from '../../../types/types'; +import { UserBase } from '../../../types/users'; import QualityGatePermissionsRenderer from './QualityGatePermissionsRenderer'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModal.tsx index de564c13adb..81bb2ec4ad0 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModal.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModal.tsx @@ -21,7 +21,8 @@ import { debounce } from 'lodash'; import * as React from 'react'; import { searchGroups, searchUsers } from '../../../api/quality-gates'; import { Group, SearchPermissionsParameters } from '../../../types/quality-gates'; -import { QualityGate, UserBase } from '../../../types/types'; +import { QualityGate } from '../../../types/types'; +import { UserBase } from '../../../types/users'; import QualityGatePermissionsAddModalRenderer from './QualityGatePermissionsAddModalRenderer'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx index 441f47666fd..ea2f2fbd70c 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx @@ -25,7 +25,7 @@ import GroupIcon from '../../../components/icons/GroupIcon'; import Avatar from '../../../components/ui/Avatar'; import { translate } from '../../../helpers/l10n'; import { Group, isUser } from '../../../types/quality-gates'; -import { UserBase } from '../../../types/types'; +import { UserBase } from '../../../types/users'; export interface QualityGatePermissionsAddModalRendererProps { onClose: () => void; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx index f061811ccb0..708c24269de 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx @@ -24,7 +24,8 @@ import ConfirmModal from '../../../components/controls/ConfirmModal'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; import { Group, isUser } from '../../../types/quality-gates'; -import { QualityGate, UserBase } from '../../../types/types'; +import { QualityGate } from '../../../types/types'; +import { UserBase } from '../../../types/users'; import PermissionItem from './PermissionItem'; import QualityGatePermissionsAddModal from './QualityGatePermissionsAddModal'; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx index 66c0f94b6a7..50fa7a08089 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsApp.tsx @@ -24,14 +24,13 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { getMeasures } from '../../api/measures'; import { getSecurityHotspotList, getSecurityHotspots } from '../../api/security-hotspots'; -import { withCurrentUser } from '../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import { Router } from '../../components/hoc/withRouter'; import { getLeakValue } from '../../components/measure/utils'; import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../helpers/branch-like'; import { KeyboardCodes, KeyboardKeys } from '../../helpers/keycodes'; import { scrollToElement } from '../../helpers/scrolling'; import { getStandards } from '../../helpers/security-standard'; -import { isLoggedIn } from '../../helpers/users'; import { fetchBranchStatus } from '../../store/rootActions'; import { BranchLike } from '../../types/branch-like'; import { SecurityStandard, Standards } from '../../types/security'; @@ -42,7 +41,8 @@ import { HotspotStatusFilter, RawHotspot } from '../../types/security-hotspots'; -import { Component, CurrentUser, Dict } from '../../types/types'; +import { Component, Dict } from '../../types/types'; +import { CurrentUser, isLoggedIn } from '../../types/users'; import SecurityHotspotsAppRenderer from './SecurityHotspotsAppRenderer'; import './styles.css'; import { getLocations, SECURITY_STANDARDS } from './utils'; @@ -547,4 +547,4 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> { const mapDispatchToProps = { fetchBranchStatus }; -export default withCurrentUser(connect(null, mapDispatchToProps)(SecurityHotspotsApp)); +export default withCurrentUserContext(connect(null, mapDispatchToProps)(SecurityHotspotsApp)); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/__snapshots__/SecurityHotspotsAppRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/__snapshots__/SecurityHotspotsAppRenderer-test.tsx.snap index bd4730c4110..fa7b43b13fa 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/__snapshots__/SecurityHotspotsAppRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/__tests__/__snapshots__/SecurityHotspotsAppRenderer-test.tsx.snap @@ -16,7 +16,7 @@ exports[`should render correctly 1`] = ` <A11ySkipTarget anchor="security_hotspots_main" /> - <Connect(withCurrentUser(FilterBar)) + <withCurrentUserContext(FilterBar) component={ Object { "breadcrumbs": Array [], @@ -323,7 +323,7 @@ exports[`should render correctly with hotspots 1`] = ` <A11ySkipTarget anchor="security_hotspots_main" /> - <Connect(withCurrentUser(FilterBar)) + <withCurrentUserContext(FilterBar) component={ Object { "breadcrumbs": Array [], @@ -461,7 +461,7 @@ exports[`should render correctly: loading 1`] = ` <A11ySkipTarget anchor="security_hotspots_main" /> - <Connect(withCurrentUser(FilterBar)) + <withCurrentUserContext(FilterBar) component={ Object { "breadcrumbs": Array [], @@ -527,7 +527,7 @@ exports[`should render correctly: no hotspots with filters 1`] = ` <A11ySkipTarget anchor="security_hotspots_main" /> - <Connect(withCurrentUser(FilterBar)) + <withCurrentUserContext(FilterBar) component={ Object { "breadcrumbs": Array [], diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx index 720b7fd5454..ccbb2979f25 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/FilterBar.tsx @@ -18,18 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import HelpTooltip from '../../../components/controls/HelpTooltip'; import RadioToggle from '../../../components/controls/RadioToggle'; import SelectLegacy from '../../../components/controls/SelectLegacy'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import Measure from '../../../components/measure/Measure'; import CoverageRating from '../../../components/ui/CoverageRating'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; import { ComponentQualifier } from '../../../types/component'; import { HotspotFilters, HotspotStatusFilter } from '../../../types/security-hotspots'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; export interface FilterBarProps { currentUser: CurrentUser; @@ -169,4 +169,4 @@ export function FilterBar(props: FilterBarProps) { ); } -export default withCurrentUser(FilterBar); +export default withCurrentUserContext(FilterBar); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx index 6ae043aa9ca..1720cd7d77e 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx @@ -19,12 +19,11 @@ */ import classNames from 'classnames'; import * as React from 'react'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { ButtonLink } from '../../../components/controls/buttons'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; import { Hotspot } from '../../../types/security-hotspots'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import './HotspotPrimaryLocationBox.css'; export interface HotspotPrimaryLocationBoxProps { @@ -67,4 +66,4 @@ export function HotspotPrimaryLocationBox(props: HotspotPrimaryLocationBoxProps) ); } -export default withCurrentUser(HotspotPrimaryLocationBox); +export default withCurrentUserContext(HotspotPrimaryLocationBox); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx index 38454514e9c..68813b61263 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistoryAndComments.tsx @@ -26,9 +26,8 @@ import { import FormattingTips from '../../../components/common/FormattingTips'; import { Button } from '../../../components/controls/buttons'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn } from '../../../helpers/users'; import { Hotspot } from '../../../types/security-hotspots'; -import { CurrentUser } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import HotspotReviewHistory from './HotspotReviewHistory'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx index a79ed7659fc..7a00dfede1e 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetHeader.tsx @@ -20,20 +20,20 @@ import styled from '@emotion/styled'; import React from 'react'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { colors, sizes } from '../../../app/theme'; import { ClipboardButton, ClipboardIconButton } from '../../../components/controls/clipboard'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import LinkIcon from '../../../components/icons/LinkIcon'; import QualifierIcon from '../../../components/icons/QualifierIcon'; import { getBranchLikeQuery } from '../../../helpers/branch-like'; import { translate } from '../../../helpers/l10n'; import { collapsedDirFromPath, fileFromPath } from '../../../helpers/path'; import { getComponentSecurityHotspotsUrl, getPathUrlAsString } from '../../../helpers/urls'; -import { isLoggedIn } from '../../../helpers/users'; import { BranchLike } from '../../../types/branch-like'; import { ComponentQualifier } from '../../../types/component'; import { Hotspot } from '../../../types/security-hotspots'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; import HotspotOpenInIdeButton from './HotspotOpenInIdeButton'; export interface HotspotSnippetHeaderProps { @@ -113,4 +113,4 @@ const FilePath = styled.div` } `; -export default withCurrentUser(HotspotSnippetHeader); +export default withCurrentUserContext(HotspotSnippetHeader); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx index 0fc2f8540b0..81ee7616719 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewerRenderer.tsx @@ -18,11 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { fillBranchLike } from '../../../helpers/branch-like'; import { Hotspot, HotspotStatusOption } from '../../../types/security-hotspots'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser } from '../../../types/users'; import { HotspotHeader } from './HotspotHeader'; import HotspotReviewHistoryAndComments from './HotspotReviewHistoryAndComments'; import HotspotSnippetContainer from './HotspotSnippetContainer'; @@ -100,4 +101,4 @@ export function HotspotViewerRenderer(props: HotspotViewerRendererProps) { ); } -export default withCurrentUser(HotspotViewerRenderer); +export default withCurrentUserContext(HotspotViewerRenderer); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx index b360e9d574f..5f0e61cae10 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotReviewHistoryAndComments-test.tsx @@ -27,7 +27,7 @@ import { import { mockHotspot } from '../../../../helpers/mocks/security-hotspots'; import { mockCurrentUser } from '../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../helpers/testUtils'; -import { isLoggedIn } from '../../../../helpers/users'; +import { isLoggedIn } from '../../../../types/users'; import HotspotReviewHistory from '../HotspotReviewHistory'; import HotspotReviewHistoryAndComments from '../HotspotReviewHistoryAndComments'; @@ -37,7 +37,7 @@ jest.mock('../../../../api/security-hotspots', () => ({ editSecurityHotspotComment: jest.fn().mockResolvedValue({}) })); -jest.mock('../../../../helpers/users', () => ({ isLoggedIn: jest.fn(() => true) })); +jest.mock('../../../../types/users', () => ({ isLoggedIn: jest.fn(() => true) })); it('should render correctly', () => { const wrapper = shallowRender(); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotHeader-test.tsx.snap index 2f09502b284..eb76f5685b9 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotHeader-test.tsx.snap @@ -42,7 +42,7 @@ exports[`should render correctly 1`] = ` <div className="display-flex-space-between" > - <Connect(withCurrentUser(Status)) + <withCurrentUserContext(Status) hotspot={ Object { "assignee": "assignee", @@ -142,7 +142,7 @@ exports[`should render correctly 1`] = ` > assignee: </div> - <Connect(withCurrentUser(Assignee)) + <withCurrentUserContext(Assignee) hotspot={ Object { "assignee": "assignee", diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap index 4303a691128..65a827e5192 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotSnippetContainerRenderer-test.tsx.snap @@ -7,7 +7,7 @@ exports[`should render correctly 1`] = ` > hotspots.no_associated_lines </p> - <Connect(withCurrentUser(HotspotSnippetHeader)) + <withCurrentUserContext(HotspotSnippetHeader) branchLike={ Object { "analysisDate": "2018-01-01", @@ -143,7 +143,7 @@ exports[`should render correctly when secondary location is selected: with selec > hotspots.no_associated_lines </p> - <Connect(withCurrentUser(HotspotSnippetHeader)) + <withCurrentUserContext(HotspotSnippetHeader) branchLike={ Object { "analysisDate": "2018-01-01", @@ -274,7 +274,7 @@ exports[`should render correctly when secondary location is selected: with selec exports[`should render correctly: with sourcelines 1`] = ` <Fragment> - <Connect(withCurrentUser(HotspotSnippetHeader)) + <withCurrentUserContext(HotspotSnippetHeader) branchLike={ Object { "analysisDate": "2018-01-01", diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap index 1e5149058ec..0e615b87137 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render correctly 1`] = ` -<Connect(withCurrentUser(HotspotViewerRenderer)) +<withCurrentUserContext(HotspotViewerRenderer) commentTextRef={ Object { "current": null, @@ -40,7 +40,7 @@ exports[`should render correctly 1`] = ` `; exports[`should render correctly 2`] = ` -<Connect(withCurrentUser(HotspotViewerRenderer)) +<withCurrentUserContext(HotspotViewerRenderer) commentTextRef={ Object { "current": null, diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx index 2d8a0e9fc02..89a43531b3b 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/Assignee.tsx @@ -19,12 +19,11 @@ */ import * as React from 'react'; import { assignSecurityHotspot } from '../../../../api/security-hotspots'; +import withCurrentUserContext from '../../../../app/components/current-user/withCurrentUserContext'; import addGlobalSuccessMessage from '../../../../app/utils/addGlobalSuccessMessage'; -import { withCurrentUser } from '../../../../components/hoc/withCurrentUser'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; -import { isLoggedIn } from '../../../../helpers/users'; import { Hotspot, HotspotStatus } from '../../../../types/security-hotspots'; -import { CurrentUser, UserActive } from '../../../../types/types'; +import { CurrentUser, isLoggedIn, UserActive } from '../../../../types/users'; import AssigneeRenderer from './AssigneeRenderer'; interface Props { @@ -107,4 +106,4 @@ export class Assignee extends React.PureComponent<Props, State> { } } -export default withCurrentUser(Assignee); +export default withCurrentUserContext(Assignee); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx index 03a658e5e69..f226c2f0912 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeRenderer.tsx @@ -23,7 +23,7 @@ import EscKeydownHandler from '../../../../components/controls/EscKeydownHandler import OutsideClickHandler from '../../../../components/controls/OutsideClickHandler'; import DeferredSpinner from '../../../../components/ui/DeferredSpinner'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; -import { LoggedInUser, UserActive, UserBase } from '../../../../types/types'; +import { LoggedInUser, UserActive, UserBase } from '../../../../types/users'; import AssigneeSelection from './AssigneeSelection'; export interface AssigneeRendererProps { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx index 6707ca208cf..70058208c50 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelection.tsx @@ -22,8 +22,7 @@ import * as React from 'react'; import { searchUsers } from '../../../../api/users'; import { KeyboardCodes } from '../../../../helpers/keycodes'; import { translate } from '../../../../helpers/l10n'; -import { isUserActive } from '../../../../helpers/users'; -import { LoggedInUser, UserActive } from '../../../../types/types'; +import { isUserActive, LoggedInUser, UserActive } from '../../../../types/users'; import AssigneeSelectionRenderer from './AssigneeSelectionRenderer'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx index 30f2c0838ec..3610cfdc376 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/AssigneeSelectionRenderer.tsx @@ -25,7 +25,7 @@ import Avatar from '../../../../components/ui/Avatar'; import DeferredSpinner from '../../../../components/ui/DeferredSpinner'; import { PopupPlacement } from '../../../../components/ui/popups'; import { translate } from '../../../../helpers/l10n'; -import { UserActive } from '../../../../types/types'; +import { UserActive } from '../../../../types/users'; import './AssigneeSelection.css'; export interface HotspotAssigneeSelectRendererProps { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx index 298b12abeff..4bf5b33262e 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/Assignee-test.tsx @@ -25,7 +25,7 @@ import { mockHotspot } from '../../../../../helpers/mocks/security-hotspots'; import { mockCurrentUser, mockUser } from '../../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../../helpers/testUtils'; import { HotspotStatus } from '../../../../../types/security-hotspots'; -import { UserActive } from '../../../../../types/types'; +import { UserActive } from '../../../../../types/users'; import { Assignee } from '../Assignee'; import AssigneeRenderer from '../AssigneeRenderer'; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx index 0fe366d7618..32e3de350ee 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeRenderer-test.tsx @@ -23,7 +23,7 @@ import { EditButton } from '../../../../../components/controls/buttons'; import OutsideClickHandler from '../../../../../components/controls/OutsideClickHandler'; import { mockLoggedInUser, mockUser } from '../../../../../helpers/testMocks'; import { click } from '../../../../../helpers/testUtils'; -import { UserActive } from '../../../../../types/types'; +import { UserActive } from '../../../../../types/users'; import AssigneeRenderer, { AssigneeRendererProps } from '../AssigneeRenderer'; import AssigneeSelection from '../AssigneeSelection'; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx index 8835bcea815..0e59e23a6e2 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelection-test.tsx @@ -23,7 +23,7 @@ import { searchUsers } from '../../../../../api/users'; import { KeyboardCodes } from '../../../../../helpers/keycodes'; import { mockLoggedInUser, mockUser } from '../../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../../helpers/testUtils'; -import { UserActive } from '../../../../../types/types'; +import { UserActive } from '../../../../../types/users'; import AssigneeSelection from '../AssigneeSelection'; jest.mock('../../../../../api/users', () => ({ diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx index 19bfc3bc967..f686f2fc639 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/assignee/__tests__/AssigneeSelectionRenderer-test.tsx @@ -20,7 +20,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { mockUser } from '../../../../../helpers/testMocks'; -import { UserActive } from '../../../../../types/types'; +import { UserActive } from '../../../../../types/users'; import AssigneeSelectionRenderer, { HotspotAssigneeSelectRendererProps } from '../AssigneeSelectionRenderer'; diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx index 078e5023db5..eb075fb4aa6 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/status/Status.tsx @@ -18,17 +18,16 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import withCurrentUserContext from '../../../../app/components/current-user/withCurrentUserContext'; import { Button } from '../../../../components/controls/buttons'; import { DropdownOverlay } from '../../../../components/controls/Dropdown'; import Toggler from '../../../../components/controls/Toggler'; import Tooltip from '../../../../components/controls/Tooltip'; -import { withCurrentUser } from '../../../../components/hoc/withCurrentUser'; import DropdownIcon from '../../../../components/icons/DropdownIcon'; import { PopupPlacement } from '../../../../components/ui/popups'; import { translate } from '../../../../helpers/l10n'; -import { isLoggedIn } from '../../../../helpers/users'; import { Hotspot, HotspotStatusOption } from '../../../../types/security-hotspots'; -import { CurrentUser } from '../../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../../types/users'; import { getStatusOptionFromStatusAndResolution } from '../../utils'; import StatusDescription from './StatusDescription'; import StatusSelection from './StatusSelection'; @@ -87,4 +86,4 @@ export function Status(props: StatusProps) { ); } -export default withCurrentUser(Status); +export default withCurrentUserContext(Status); diff --git a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx index f65dc0988a2..2e9bfed908d 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx @@ -19,15 +19,15 @@ */ import * as React from 'react'; import { sendTestEmail } from '../../../api/settings'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { SubmitButton } from '../../../components/controls/buttons'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; import { Alert } from '../../../components/ui/Alert'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker'; import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { parseError } from '../../../helpers/request'; -import { LoggedInUser } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; interface Props { currentUser: LoggedInUser; @@ -175,4 +175,4 @@ export class EmailForm extends React.PureComponent<Props, State> { } } -export default withCurrentUser(EmailForm); +export default withCurrentUserContext(EmailForm); diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap index 8787399d313..cb5c37892f5 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/AdditionalCategories-test.tsx.snap @@ -93,7 +93,7 @@ exports[`should render additional categories component correctly 4`] = ` `; exports[`should render additional categories component correctly 5`] = ` -<Connect(withCurrentUser(PRDecorationBinding)) +<withCurrentUserContext(PRDecorationBinding) component={ Object { "breadcrumbs": Array [], diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap index c0449cc8a04..ff66d64f6a4 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/SubCategoryDefinitionsList-test.tsx.snap @@ -36,7 +36,7 @@ exports[`should render correctly 1`] = ` ] } /> - <Connect(withCurrentUser(EmailForm)) /> + <withCurrentUserContext(EmailForm) /> </li> <li key="qg" diff --git a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx index 885689f50c9..dcd43858157 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/PRDecorationBinding.tsx @@ -29,8 +29,8 @@ import { setProjectGitlabBinding, validateProjectAlmBinding } from '../../../../api/alm-settings'; +import withCurrentUserContext from '../../../../app/components/current-user/withCurrentUserContext'; import throwGlobalError from '../../../../app/utils/throwGlobalError'; -import { withCurrentUser } from '../../../../components/hoc/withCurrentUser'; import { HttpStatus } from '../../../../helpers/request'; import { hasGlobalPermission } from '../../../../helpers/users'; import { @@ -40,7 +40,8 @@ import { ProjectAlmBindingResponse } from '../../../../types/alm-settings'; import { Permissions } from '../../../../types/permissions'; -import { Component, CurrentUser } from '../../../../types/types'; +import { Component } from '../../../../types/types'; +import { CurrentUser } from '../../../../types/users'; import PRDecorationBindingRenderer from './PRDecorationBindingRenderer'; type FormData = Omit<ProjectAlmBindingResponse, 'alm'>; @@ -351,4 +352,4 @@ export class PRDecorationBinding extends React.PureComponent<Props, State> { } } -export default withCurrentUser(PRDecorationBinding); +export default withCurrentUserContext(PRDecorationBinding); diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/App-test.tsx.snap index 274ea824bba..f439306338c 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/App-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/App-test.tsx.snap @@ -16,7 +16,7 @@ exports[`should render correctly: cluster sysinfo 1`] = ` <div className="page-notifs" > - <Connect(withCurrentUser(withAppStateContext(UpdateNotification))) + <withCurrentUserContext(withAppStateContext(UpdateNotification)) dismissable={false} /> </div> @@ -209,7 +209,7 @@ exports[`should render correctly: loading 1`] = ` <div className="page-notifs" > - <Connect(withCurrentUser(withAppStateContext(UpdateNotification))) + <withCurrentUserContext(withAppStateContext(UpdateNotification)) dismissable={false} /> </div> @@ -232,7 +232,7 @@ exports[`should render correctly: stand-alone sysinfo 1`] = ` <div className="page-notifs" > - <Connect(withCurrentUser(withAppStateContext(UpdateNotification))) + <withCurrentUserContext(withAppStateContext(UpdateNotification)) dismissable={false} /> </div> diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/TutorialsApp.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/TutorialsApp.tsx index 8cf1218ab0e..bce81dc134d 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/components/TutorialsApp.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/components/TutorialsApp.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import TutorialSelection from '../../../components/tutorials/TutorialSelection'; import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication'; -import { isLoggedIn } from '../../../helpers/users'; import { ProjectAlmBindingResponse } from '../../../types/alm-settings'; -import { Component, CurrentUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { CurrentUser, isLoggedIn } from '../../../types/users'; export interface TutorialsAppProps { component: Component; @@ -50,4 +50,4 @@ export function TutorialsApp(props: TutorialsAppProps) { ); } -export default withCurrentUser(TutorialsApp); +export default withCurrentUserContext(TutorialsApp); diff --git a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx index 932e5e11f5d..a7e2877cec7 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersApp.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersApp.tsx @@ -20,12 +20,13 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; import { getIdentityProviders, searchUsers } from '../../api/users'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import Suggestions from '../../app/components/embed-docs-modal/Suggestions'; import ListFooter from '../../components/controls/ListFooter'; -import { withCurrentUser } from '../../components/hoc/withCurrentUser'; import { Location, Router, withRouter } from '../../components/hoc/withRouter'; import { translate } from '../../helpers/l10n'; -import { IdentityProvider, Paging, User } from '../../types/types'; +import { IdentityProvider, Paging } from '../../types/types'; +import { User } from '../../types/users'; import Header from './Header'; import Search from './Search'; import UsersList from './UsersList'; @@ -141,4 +142,4 @@ export class UsersApp extends React.PureComponent<Props, State> { } } -export default withRouter(withCurrentUser(UsersApp)); +export default withRouter(withCurrentUserContext(UsersApp)); diff --git a/server/sonar-web/src/main/js/apps/users/UsersList.tsx b/server/sonar-web/src/main/js/apps/users/UsersList.tsx index 5de6057fde4..d4761fc7c60 100644 --- a/server/sonar-web/src/main/js/apps/users/UsersList.tsx +++ b/server/sonar-web/src/main/js/apps/users/UsersList.tsx @@ -19,7 +19,8 @@ */ import * as React from 'react'; import { translate } from '../../helpers/l10n'; -import { IdentityProvider, User } from '../../types/types'; +import { IdentityProvider } from '../../types/types'; +import { User } from '../../types/users'; import UserListItem from './components/UserListItem'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx index 34909a28c5a..8f4b6414e0f 100644 --- a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx @@ -22,7 +22,7 @@ import { deactivateUser } from '../../../api/users'; import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { UserActive } from '../../../types/types'; +import { UserActive } from '../../../types/users'; export interface Props { onClose: () => void; diff --git a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx index 82e1a4938b6..0a112561f3a 100644 --- a/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/GroupsForm.tsx @@ -27,7 +27,7 @@ import SelectList, { SelectListSearchParams } from '../../../components/controls/SelectList'; import { translate } from '../../../helpers/l10n'; -import { User } from '../../../types/types'; +import { User } from '../../../types/users'; interface Props { onClose: () => void; diff --git a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx index 8c4a3bbc806..b4b0d24b776 100644 --- a/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/PasswordForm.tsx @@ -28,7 +28,7 @@ import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker'; import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation'; import { translate } from '../../../helpers/l10n'; import { parseError } from '../../../helpers/request'; -import { User } from '../../../types/types'; +import { User } from '../../../types/users'; interface Props { isCurrentUser: boolean; diff --git a/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx b/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx index 448e54cde47..85981cf315e 100644 --- a/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx @@ -22,7 +22,7 @@ import { FormattedMessage } from 'react-intl'; import { ResetButtonLink } from '../../../components/controls/buttons'; import Modal from '../../../components/controls/Modal'; import { translate } from '../../../helpers/l10n'; -import { User } from '../../../types/types'; +import { User } from '../../../types/users'; import TokensForm from './TokensForm'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx b/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx index dc718645298..32d01fd35c5 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserActions.tsx @@ -23,8 +23,7 @@ import ActionsDropdown, { ActionsDropdownItem } from '../../../components/controls/ActionsDropdown'; import { translate } from '../../../helpers/l10n'; -import { isUserActive } from '../../../helpers/users'; -import { User } from '../../../types/types'; +import { isUserActive, User } from '../../../types/users'; import DeactivateForm from './DeactivateForm'; import PasswordForm from './PasswordForm'; import UserForm from './UserForm'; diff --git a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx index c61a68f94be..e0d954293d6 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserForm.tsx @@ -28,7 +28,7 @@ import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker'; import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { parseError } from '../../../helpers/request'; -import { User } from '../../../types/types'; +import { User } from '../../../types/users'; import UserScmAccountInput from './UserScmAccountInput'; export interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx b/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx index c35ef36a9e2..cea99845583 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserGroups.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import { ButtonIcon } from '../../../components/controls/buttons'; import BulletListIcon from '../../../components/icons/BulletListIcon'; import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { User } from '../../../types/types'; +import { User } from '../../../types/users'; import GroupsForm from './GroupsForm'; interface Props { diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx index ad0cc57e727..8dd7b8784f9 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItem.tsx @@ -23,7 +23,8 @@ import BulletListIcon from '../../../components/icons/BulletListIcon'; import DateFromNow from '../../../components/intl/DateFromNow'; import Avatar from '../../../components/ui/Avatar'; import { translate } from '../../../helpers/l10n'; -import { IdentityProvider, User } from '../../../types/types'; +import { IdentityProvider } from '../../../types/types'; +import { User } from '../../../types/users'; import TokensFormModal from './TokensFormModal'; import UserActions from './UserActions'; import UserGroups from './UserGroups'; diff --git a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx index 3980cad5176..6cb47ae2a3a 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/UserListItemIdentity.tsx @@ -21,7 +21,8 @@ import * as React from 'react'; import { colors } from '../../../app/theme'; import { getTextColor } from '../../../helpers/colors'; import { getBaseUrl } from '../../../helpers/system'; -import { IdentityProvider, User } from '../../../types/types'; +import { IdentityProvider } from '../../../types/types'; +import { User } from '../../../types/users'; export interface Props { identityProvider?: IdentityProvider; diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx index 1a713c128b2..ab949c308f9 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/UserListItem-test.tsx @@ -20,7 +20,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { click } from '../../../../helpers/testUtils'; -import { User } from '../../../../types/types'; +import { User } from '../../../../types/users'; import UserListItem from '../UserListItem'; jest.mock('../../../../components/intl/DateFromNow'); diff --git a/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx b/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx index c058cb7a660..f0a776dcf43 100644 --- a/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx +++ b/server/sonar-web/src/main/js/components/common/AnalysisWarningsModal.tsx @@ -19,6 +19,7 @@ */ import * as React from 'react'; import { dismissAnalysisWarning, getTask } from '../../api/ce'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import { ButtonLink } from '../../components/controls/buttons'; import Modal from '../../components/controls/Modal'; import WarningIcon from '../../components/icons/WarningIcon'; @@ -26,8 +27,7 @@ import DeferredSpinner from '../../components/ui/DeferredSpinner'; import { translate } from '../../helpers/l10n'; import { sanitizeStringRestricted } from '../../helpers/sanitize'; import { TaskWarning } from '../../types/tasks'; -import { CurrentUser } from '../../types/types'; -import { withCurrentUser } from '../hoc/withCurrentUser'; +import { CurrentUser } from '../../types/users'; interface Props { componentKey?: string; @@ -171,4 +171,4 @@ export class AnalysisWarningsModal extends React.PureComponent<Props, State> { } } -export default withCurrentUser(AnalysisWarningsModal); +export default withCurrentUserContext(AnalysisWarningsModal); diff --git a/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx b/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx index 8d845271f11..a9f7dd0fa7c 100644 --- a/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx +++ b/server/sonar-web/src/main/js/components/common/ResetPasswordForm.tsx @@ -24,7 +24,7 @@ import { Alert } from '../../components/ui/Alert'; import MandatoryFieldMarker from '../../components/ui/MandatoryFieldMarker'; import MandatoryFieldsExplanation from '../../components/ui/MandatoryFieldsExplanation'; import { translate } from '../../helpers/l10n'; -import { LoggedInUser } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; interface Props { className?: string; diff --git a/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx b/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx index 88c25f5d75d..dcb3359e167 100644 --- a/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx +++ b/server/sonar-web/src/main/js/components/controls/ComponentReportActions.tsx @@ -24,15 +24,15 @@ import { unsubscribeFromEmailReport } from '../../api/component-report'; import withAppStateContext from '../../app/components/app-state/withAppStateContext'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import addGlobalSuccessMessage from '../../app/utils/addGlobalSuccessMessage'; import { translate, translateWithParameters } from '../../helpers/l10n'; -import { isLoggedIn } from '../../helpers/users'; import { AppState } from '../../types/appstate'; import { Branch } from '../../types/branch-like'; import { ComponentQualifier } from '../../types/component'; import { ComponentReportStatus } from '../../types/component-report'; -import { Component, CurrentUser } from '../../types/types'; -import { withCurrentUser } from '../hoc/withCurrentUser'; +import { Component } from '../../types/types'; +import { CurrentUser, isLoggedIn } from '../../types/users'; import ComponentReportActionsRenderer from './ComponentReportActionsRenderer'; interface Props { @@ -134,4 +134,4 @@ export class ComponentReportActions extends React.PureComponent<Props, State> { } } -export default withCurrentUser(withAppStateContext(ComponentReportActions)); +export default withCurrentUserContext(withAppStateContext(ComponentReportActions)); diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx index d7be205eb0a..73e3a217c6d 100644 --- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx +++ b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx @@ -19,25 +19,18 @@ */ import classNames from 'classnames'; import * as React from 'react'; -import { connect } from 'react-redux'; +import { setHomePage } from '../../api/users'; +import { CurrentUserContextInterface } from '../../app/components/current-user/CurrentUserContext'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import { ButtonLink } from '../../components/controls/buttons'; import Tooltip from '../../components/controls/Tooltip'; import HomeIcon from '../../components/icons/HomeIcon'; import { translate } from '../../helpers/l10n'; -import { isLoggedIn } from '../../helpers/users'; -import { getCurrentUser, Store } from '../../store/rootReducer'; -import { setHomePage } from '../../store/users'; -import { CurrentUser, HomePage } from '../../types/types'; +import { isSameHomePage } from '../../helpers/users'; +import { HomePage, isLoggedIn } from '../../types/users'; -interface StateProps { - currentUser: CurrentUser; -} - -interface DispatchProps { - setHomePage: (homepage: HomePage) => void; -} - -interface Props extends StateProps, DispatchProps { +interface Props + extends Pick<CurrentUserContextInterface, 'currentUser' | 'updateCurrentUserHomepage'> { className?: string; currentPage: HomePage; } @@ -45,12 +38,22 @@ interface Props extends StateProps, DispatchProps { export const DEFAULT_HOMEPAGE: HomePage = { type: 'PROJECTS' }; export class HomePageSelect extends React.PureComponent<Props> { + async setCurrentUserHomepage(homepage: HomePage) { + const { currentUser } = this.props; + + if (currentUser && isLoggedIn(currentUser)) { + await setHomePage(homepage); + + this.props.updateCurrentUserHomepage(homepage); + } + } + handleClick = () => { - this.props.setHomePage(this.props.currentPage); + this.setCurrentUserHomepage(this.props.currentPage); }; handleReset = () => { - this.props.setHomePage(DEFAULT_HOMEPAGE); + this.setCurrentUserHomepage(DEFAULT_HOMEPAGE); }; render() { @@ -88,18 +91,4 @@ export class HomePageSelect extends React.PureComponent<Props> { } } -const mapStateToProps = (state: Store): StateProps => ({ - currentUser: getCurrentUser(state) -}); - -const mapDispatchToProps: DispatchProps = { setHomePage }; - -export default connect(mapStateToProps, mapDispatchToProps)(HomePageSelect); - -function isSameHomePage(a: HomePage, b: HomePage) { - return ( - a.type === b.type && - (a as any).branch === (b as any).branch && - (a as any).component === (b as any).component - ); -} +export default withCurrentUserContext(HomePageSelect); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx index 6726447c6c7..c43d6d17506 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx @@ -22,9 +22,13 @@ import * as React from 'react'; import { ButtonLink } from '../../../components/controls/buttons'; import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks'; import { click, waitAndUpdate } from '../../../helpers/testUtils'; -import { HomePage } from '../../../types/types'; +import { HomePage } from '../../../types/users'; import { DEFAULT_HOMEPAGE, HomePageSelect } from '../HomePageSelect'; +jest.mock('../../../api/users', () => ({ + setHomePage: jest.fn().mockResolvedValue(null) +})); + it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('unchecked'); expect( @@ -40,20 +44,20 @@ it('should render correctly', () => { }); it('should correctly call webservices', async () => { - const setHomePage = jest.fn(); + const updateCurrentUserHomepage = jest.fn(); const currentPage: HomePage = { type: 'MY_ISSUES' }; - const wrapper = shallowRender({ setHomePage, currentPage }); + const wrapper = shallowRender({ updateCurrentUserHomepage, currentPage }); // Set homepage. click(wrapper.find(ButtonLink)); await waitAndUpdate(wrapper); - expect(setHomePage).toHaveBeenLastCalledWith(currentPage); + expect(updateCurrentUserHomepage).toHaveBeenLastCalledWith(currentPage); // Reset. wrapper.setProps({ currentUser: mockLoggedInUser({ homepage: currentPage }) }); click(wrapper.find(ButtonLink)); await waitAndUpdate(wrapper); - expect(setHomePage).toHaveBeenLastCalledWith(DEFAULT_HOMEPAGE); + expect(updateCurrentUserHomepage).toHaveBeenLastCalledWith(DEFAULT_HOMEPAGE); }); function shallowRender(props: Partial<HomePageSelect['props']> = {}) { @@ -61,7 +65,7 @@ function shallowRender(props: Partial<HomePageSelect['props']> = {}) { <HomePageSelect currentPage={{ type: 'MY_PROJECTS' }} currentUser={mockLoggedInUser()} - setHomePage={jest.fn()} + updateCurrentUserHomepage={jest.fn()} {...props} /> ); diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx index 6ac87a1e266..caa9afc503f 100644 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx +++ b/server/sonar-web/src/main/js/components/hoc/__tests__/whenLoggedIn-test.tsx @@ -19,8 +19,8 @@ */ import { shallow, ShallowWrapper } from 'enzyme'; import * as React from 'react'; +import { CurrentUserContext } from '../../../app/components/current-user/CurrentUserContext'; import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication'; -import { mockStore } from '../../../helpers/testMocks'; import { whenLoggedIn } from '../whenLoggedIn'; jest.mock('../../../helpers/handleRequiredAuthentication', () => jest.fn()); @@ -47,11 +47,19 @@ function getRenderedType(wrapper: ShallowWrapper) { return wrapper .dive() .dive() + .dive() .type(); } function shallowRender(isLoggedIn = true) { - return shallow(<UnderTest />, { - context: { store: mockStore({ users: { currentUser: { isLoggedIn } } }) } - }); + return shallow( + <CurrentUserContext.Provider + value={{ + currentUser: { isLoggedIn }, + updateCurrentUserHomepage: () => {}, + updateCurrentUserSonarLintAdSeen: () => {} + }}> + <UnderTest /> + </CurrentUserContext.Provider> + ); } diff --git a/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx b/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx deleted file mode 100644 index ab529ecd234..00000000000 --- a/server/sonar-web/src/main/js/components/hoc/__tests__/withCurrentUser-test.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { mockStore } from '../../../helpers/testMocks'; -import { CurrentUser } from '../../../types/types'; -import { withCurrentUser } from '../withCurrentUser'; - -class X extends React.Component<{ currentUser: CurrentUser }> { - render() { - return <div />; - } -} - -const UnderTest = withCurrentUser(X); - -it('should pass logged in user', () => { - const currentUser = { isLoggedIn: false }; - const wrapper = shallow(<UnderTest />, { - context: { store: mockStore({ users: { currentUser } }) } - }); - expect(wrapper.dive().type()).toBe(X); - expect(wrapper.dive().prop('currentUser')).toBe(currentUser); -}); diff --git a/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx b/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx index e07a0627b7d..6568ccb8582 100644 --- a/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx +++ b/server/sonar-web/src/main/js/components/hoc/whenLoggedIn.tsx @@ -18,11 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext'; import handleRequiredAuthentication from '../../helpers/handleRequiredAuthentication'; -import { isLoggedIn } from '../../helpers/users'; -import { CurrentUser } from '../../types/types'; +import { CurrentUser, isLoggedIn } from '../../types/users'; import { getWrappedDisplayName } from './utils'; -import { withCurrentUser } from './withCurrentUser'; export function whenLoggedIn<P>(WrappedComponent: React.ComponentType<P>) { class Wrapper extends React.Component<P & { currentUser: CurrentUser }> { @@ -37,11 +36,10 @@ export function whenLoggedIn<P>(WrappedComponent: React.ComponentType<P>) { render() { if (isLoggedIn(this.props.currentUser)) { return <WrappedComponent {...this.props} />; - } else { - return null; } + return null; } } - return withCurrentUser(Wrapper); + return withCurrentUserContext(Wrapper); } diff --git a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap index 69b5f81e7f5..87c990089c2 100644 --- a/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap @@ -18,7 +18,7 @@ exports[`should open the popup when the button is clicked 2`] = ` onRequestClose={[Function]} open={true} overlay={ - <Connect(withCurrentUser(SetAssigneePopup)) + <withCurrentUserContext(SetAssigneePopup) onSelect={[MockFunction]} /> } @@ -61,7 +61,7 @@ exports[`should render a fallback assignee display if assignee info are not avai onRequestClose={[Function]} open={false} overlay={ - <Connect(withCurrentUser(SetAssigneePopup)) + <withCurrentUserContext(SetAssigneePopup) onSelect={[MockFunction]} /> } @@ -94,7 +94,7 @@ exports[`should render with the action 1`] = ` onRequestClose={[Function]} open={false} overlay={ - <Connect(withCurrentUser(SetAssigneePopup)) + <withCurrentUserContext(SetAssigneePopup) onSelect={[MockFunction]} /> } diff --git a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx index 5b10940ed5e..28260c4d74d 100644 --- a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx +++ b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx @@ -20,14 +20,13 @@ import { map } from 'lodash'; import * as React from 'react'; import { searchUsers } from '../../../api/users'; +import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import { DropdownOverlay } from '../../../components/controls/Dropdown'; import SearchBox from '../../../components/controls/SearchBox'; import { translate } from '../../../helpers/l10n'; -import { isLoggedIn, isUserActive } from '../../../helpers/users'; -import { CurrentUser, UserActive, UserBase } from '../../../types/types'; +import { CurrentUser, isLoggedIn, isUserActive, UserActive, UserBase } from '../../../types/users'; import SelectList from '../../common/SelectList'; import SelectListItem from '../../common/SelectListItem'; -import { withCurrentUser } from '../../hoc/withCurrentUser'; import Avatar from '../../ui/Avatar'; interface Props { @@ -121,4 +120,4 @@ export class SetAssigneePopup extends React.PureComponent<Props, State> { } } -export default withCurrentUser(SetAssigneePopup); +export default withCurrentUserContext(SetAssigneePopup); diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx index d1f823bac0b..b8cea65d8a0 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelection.tsx @@ -24,7 +24,8 @@ import { getValues } from '../../api/settings'; import { getHostUrl } from '../../helpers/urls'; import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings'; import { SettingsKey } from '../../types/settings'; -import { Component, LoggedInUser } from '../../types/types'; +import { Component } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import { withRouter } from '../hoc/withRouter'; import TutorialSelectionRenderer from './TutorialSelectionRenderer'; import { TutorialModes } from './types'; diff --git a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx index 0cc4c1bc6e5..bf261c639f3 100644 --- a/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/TutorialSelectionRenderer.tsx @@ -22,7 +22,8 @@ import EllipsisIcon from '../../components/icons/EllipsisIcon'; import { translate } from '../../helpers/l10n'; import { getBaseUrl } from '../../helpers/system'; import { AlmKeys, AlmSettingsInstance, ProjectAlmBindingResponse } from '../../types/alm-settings'; -import { Component, LoggedInUser } from '../../types/types'; +import { Component } from '../../types/types'; +import { LoggedInUser } from '../../types/users'; import AzurePipelinesTutorial from './azure-pipelines/AzurePipelinesTutorial'; import BitbucketPipelinesTutorial from './bitbucket-pipelines/BitbucketPipelinesTutorial'; import GitHubActionTutorial from './github-action/GitHubActionTutorial'; diff --git a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap index e9acf7bd30b..0e4c0c77b8a 100644 --- a/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/tutorials/__tests__/__snapshots__/TutorialSelectionRenderer-test.tsx.snap @@ -487,7 +487,7 @@ exports[`should render correctly: gitlab tutorial 1`] = ` exports[`should render correctly: jenkins tutorial 1`] = ` <Fragment> - <Connect(withAppStateContext(JenkinsTutorial)) + <withAppStateContext(JenkinsTutorial) almBinding={ Object { "alm": "github", diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx index 002724e3efc..c42e621e248 100644 --- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/AzurePipelinesTutorial.tsx @@ -21,7 +21,8 @@ import * as React from 'react'; import { Button } from '../../../components/controls/buttons'; import { translate } from '../../../helpers/l10n'; import { AlmKeys } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AllSetStep from '../components/AllSetStep'; import FinishButton from '../components/FinishButton'; import Step from '../components/Step'; diff --git a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx index 309dad41c80..e9e3f7a60cd 100644 --- a/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/azure-pipelines/ServiceEndpointStepContent.tsx @@ -22,7 +22,8 @@ import { FormattedMessage } from 'react-intl'; import { Button } from '../../../components/controls/buttons'; import { ClipboardIconButton } from '../../../components/controls/clipboard'; import { translate } from '../../../helpers/l10n'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import EditTokenModal from '../components/EditTokenModal'; import SentenceWithHighlights from '../components/SentenceWithHighlights'; diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx index f493f17d216..2ac61ddcf79 100644 --- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/BitbucketPipelinesTutorial.tsx @@ -24,7 +24,8 @@ import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AllSetStep from '../components/AllSetStep'; import FinishButton from '../components/FinishButton'; import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories'; diff --git a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx index ee9775e3823..9fa7e0f5b7a 100644 --- a/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/RepositoryVariables.tsx @@ -23,7 +23,8 @@ import { Button } from '../../../components/controls/buttons'; import { ClipboardIconButton } from '../../../components/controls/clipboard'; import { translate } from '../../../helpers/l10n'; import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import SentenceWithHighlights from '../components/SentenceWithHighlights'; import TokenStepGenerator from '../components/TokenStepGenerator'; import { buildBitbucketCloudLink } from '../utils'; diff --git a/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx b/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx index d373131ebcb..77d8e349700 100644 --- a/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/components/EditTokenModal.tsx @@ -27,7 +27,8 @@ import SimpleModal from '../../../components/controls/SimpleModal'; import { Alert } from '../../../components/ui/Alert'; import DeferredSpinner from '../../../components/ui/DeferredSpinner'; import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import { getUniqueTokenName } from '../utils'; interface State { diff --git a/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx b/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx index 9c84462ce6e..265a04b1636 100644 --- a/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/components/TokenStepGenerator.tsx @@ -21,7 +21,8 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { Button } from '../../../components/controls/buttons'; import { translate } from '../../../helpers/l10n'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import EditTokenModal from './EditTokenModal'; export interface TokenStepGeneratorProps { diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx index 3544d8b6e08..efa89c8d623 100644 --- a/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/github-action/GitHubActionTutorial.tsx @@ -24,7 +24,8 @@ import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AllSetStep from '../components/AllSetStep'; import Step from '../components/Step'; import YamlFileStep from '../components/YamlFileStep'; diff --git a/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx b/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx index 590c7ab9a7d..9eb8006ddf4 100644 --- a/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/github-action/SecretStep.tsx @@ -23,7 +23,8 @@ import { Button } from '../../../components/controls/buttons'; import { ClipboardIconButton } from '../../../components/controls/clipboard'; import { translate } from '../../../helpers/l10n'; import { AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import SentenceWithHighlights from '../components/SentenceWithHighlights'; import TokenStepGenerator from '../components/TokenStepGenerator'; import { buildGithubLink } from '../utils'; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx index c08d7f99c41..03506a29536 100644 --- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/EnvironmentVariablesStep.tsx @@ -22,7 +22,8 @@ import { FormattedMessage } from 'react-intl'; import { Button } from '../../../components/controls/buttons'; import { ClipboardIconButton } from '../../../components/controls/clipboard'; import { translate } from '../../../helpers/l10n'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import Step from '../components/Step'; import TokenStepGenerator from '../components/TokenStepGenerator'; diff --git a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx index bdc68c3558d..faf5190efd7 100644 --- a/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/gitlabci/GitLabCITutorial.tsx @@ -20,7 +20,8 @@ import * as React from 'react'; import { translate } from '../../../helpers/l10n'; import { AlmKeys } from '../../../types/alm-settings'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AllSetStep from '../components/AllSetStep'; import { BuildTools } from '../types'; import EnvironmentVariablesStep from './EnvironmentVariablesStep'; diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx index bb65db801d6..c0aee40c051 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/JenkinsTutorial.tsx @@ -18,18 +18,15 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; import { translate } from '../../../helpers/l10n'; -import { getCurrentUserSetting, Store } from '../../../store/rootReducer'; -import { setCurrentUserSetting } from '../../../store/users'; import { AlmKeys, AlmSettingsInstance, ProjectAlmBindingResponse } from '../../../types/alm-settings'; import { AppState } from '../../../types/appstate'; -import { Component, CurrentUserSetting } from '../../../types/types'; +import { Component } from '../../../types/types'; import AllSetStep from '../components/AllSetStep'; import JenkinsfileStep from './JenkinsfileStep'; import MultiBranchPipelineStep from './MultiBranchPipelineStep'; @@ -44,8 +41,6 @@ export interface JenkinsTutorialProps { appState: AppState; component: Component; projectBinding?: ProjectAlmBindingResponse; - setCurrentUserSetting: (setting: CurrentUserSetting) => void; - skipPreReqs: boolean; willRefreshAutomatically?: boolean; } @@ -58,8 +53,6 @@ enum Steps { AllSet = 5 } -const USER_SETTING_SKIP_BITBUCKET_PREREQS = 'tutorials.jenkins.skipBitbucketPreReqs'; - export function JenkinsTutorial(props: JenkinsTutorialProps) { const { almBinding, @@ -67,19 +60,11 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) { appState, component, projectBinding, - skipPreReqs, willRefreshAutomatically } = props; const hasSelectAlmStep = projectBinding?.alm === undefined; const [alm, setAlm] = React.useState<AlmKeys | undefined>(projectBinding?.alm); - - let startStep; - if (alm) { - startStep = skipPreReqs ? Steps.MultiBranchPipeline : Steps.PreRequisites; - } else { - startStep = Steps.SelectAlm; - } - const [step, setStep] = React.useState(startStep); + const [step, setStep] = React.useState(alm ? Steps.PreRequisites : Steps.SelectAlm); return ( <> @@ -107,14 +92,7 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) { finished={step > Steps.PreRequisites} onDone={() => setStep(Steps.MultiBranchPipeline)} onOpen={() => setStep(Steps.PreRequisites)} - onChangeSkipNextTime={skip => { - props.setCurrentUserSetting({ - key: USER_SETTING_SKIP_BITBUCKET_PREREQS, - value: skip.toString() - }); - }} open={step === Steps.PreRequisites} - skipNextTime={skipPreReqs} /> {appState.branchesEnabled ? ( @@ -169,12 +147,4 @@ export function JenkinsTutorial(props: JenkinsTutorialProps) { ); } -const mapStateToProps = (state: Store): Pick<JenkinsTutorialProps, 'skipPreReqs'> => { - return { - skipPreReqs: getCurrentUserSetting(state, USER_SETTING_SKIP_BITBUCKET_PREREQS) === 'true' - }; -}; - -const mapDispatchToProps = { setCurrentUserSetting }; - -export default connect(mapStateToProps, mapDispatchToProps)(withAppStateContext(JenkinsTutorial)); +export default withAppStateContext(JenkinsTutorial); diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx index cdcca3647a8..0f391b0bf53 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx @@ -22,7 +22,6 @@ import { FormattedMessage } from 'react-intl'; import { Link } from 'react-router'; import { rawSizes } from '../../../app/theme'; import { Button } from '../../../components/controls/buttons'; -import Checkbox from '../../../components/controls/Checkbox'; import ChevronRightIcon from '../../../components/icons/ChevronRightIcon'; import { Alert } from '../../../components/ui/Alert'; import { translate } from '../../../helpers/l10n'; @@ -34,15 +33,13 @@ export interface PreRequisitesStepProps { alm: AlmKeys; branchesEnabled: boolean; finished: boolean; - onChangeSkipNextTime: (skip: boolean) => void; onDone: () => void; onOpen: () => void; open: boolean; - skipNextTime: boolean; } export default function PreRequisitesStep(props: PreRequisitesStepProps) { - const { alm, branchesEnabled, finished, open, skipNextTime } = props; + const { alm, branchesEnabled, finished, open } = props; return ( <Step finished={finished} @@ -85,22 +82,6 @@ export default function PreRequisitesStep(props: PreRequisitesStepProps) { <p className="big-spacer-bottom"> {translate('onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations')} </p> - <p className="big-spacer-bottom display-flex-center"> - <label - className="cursor-pointer" - htmlFor="skip-prereqs" - onClick={() => { - props.onChangeSkipNextTime(!skipNextTime); - }}> - {translate('onboarding.tutorial.with.jenkins.prereqs.skip_next_time')} - </label> - <Checkbox - checked={skipNextTime} - className="little-spacer-left" - id="skip-prereqs" - onCheck={props.onChangeSkipNextTime} - /> - </p> <Button className="big-spacer-top" onClick={props.onDone}> {translate('onboarding.tutorial.with.jenkins.prereqs.done')} <ChevronRightIcon size={rawSizes.baseFontSizeRaw} /> diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx index beb1264b452..e4d121ac0fa 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/JenkinsTutorial-test.tsx @@ -98,29 +98,6 @@ it('should correctly navigate between steps', () => { expect(wrapper.find(WebhookStep).props().open).toBe(true); }); -it('should correctly store the user setting', () => { - const setCurrentUserSetting = jest.fn(); - const wrapper = shallowRender({ setCurrentUserSetting }); - - wrapper.find(PreRequisitesStep).prop('onChangeSkipNextTime')(true); - expect(setCurrentUserSetting).toBeCalledWith({ - key: 'tutorials.jenkins.skipBitbucketPreReqs', - value: 'true' - }); - - wrapper.find(PreRequisitesStep).prop('onChangeSkipNextTime')(false); - expect(setCurrentUserSetting).toBeCalledWith({ - key: 'tutorials.jenkins.skipBitbucketPreReqs', - value: 'false' - }); -}); - -it('should correctly skip the pre-reqs step if the user requested it', () => { - const wrapper = shallowRender({ skipPreReqs: true }); - expect(wrapper.find(PreRequisitesStep).props().open).toBe(false); - expect(wrapper.find(MultiBranchPipelineStep).props().open).toBe(true); -}); - it('should correctly select an ALM if no project is bound', () => { const wrapper = shallowRender({ projectBinding: undefined }); expect(wrapper.find(PreRequisitesStep).exists()).toBe(false); @@ -139,8 +116,6 @@ function shallowRender(props: Partial<JenkinsTutorialProps> = {}) { appState={mockAppState({ branchesEnabled: true })} component={mockComponent()} projectBinding={mockProjectBitbucketBindingResponse()} - setCurrentUserSetting={jest.fn()} - skipPreReqs={false} willRefreshAutomatically={true} {...props} /> diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx index 237dd9c9aa1..5494dc59df8 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/PreRequisitesStep-test.tsx @@ -42,11 +42,9 @@ function shallowRender(props: Partial<PreRequisitesStepProps> = {}) { alm={AlmKeys.BitbucketServer} branchesEnabled={true} finished={false} - onChangeSkipNextTime={jest.fn()} onDone={jest.fn()} onOpen={jest.fn()} open={false} - skipNextTime={true} {...props} /> ); diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap index eed4fce8e5d..7c2907baa6c 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/JenkinsTutorial-test.tsx.snap @@ -15,11 +15,9 @@ exports[`should render correctly: branches not enabled 1`] = ` alm="bitbucket" branchesEnabled={false} finished={false} - onChangeSkipNextTime={[Function]} onDone={[Function]} onOpen={[Function]} open={true} - skipNextTime={false} /> <PipelineStep alm="bitbucket" @@ -98,11 +96,9 @@ exports[`should render correctly: default 1`] = ` alm="bitbucket" branchesEnabled={true} finished={false} - onChangeSkipNextTime={[Function]} onDone={[Function]} onOpen={[Function]} open={true} - skipNextTime={false} /> <MultiBranchPipelineStep alm="bitbucket" diff --git a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap index e3c6038f47a..33d44479d74 100644 --- a/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/tutorials/jenkins/__tests__/__snapshots__/PreRequisitesStep-test.tsx.snap @@ -63,24 +63,6 @@ exports[`should render correctly: content 1`] = ` > onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations </p> - <p - className="big-spacer-bottom display-flex-center" - > - <label - className="cursor-pointer" - htmlFor="skip-prereqs" - onClick={[Function]} - > - onboarding.tutorial.with.jenkins.prereqs.skip_next_time - </label> - <Checkbox - checked={true} - className="little-spacer-left" - id="skip-prereqs" - onCheck={[MockFunction]} - thirdState={false} - /> - </p> <Button className="big-spacer-top" onClick={[MockFunction]} @@ -143,24 +125,6 @@ exports[`should render correctly: content for branches disabled 1`] = ` > onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations </p> - <p - className="big-spacer-bottom display-flex-center" - > - <label - className="cursor-pointer" - htmlFor="skip-prereqs" - onClick={[Function]} - > - onboarding.tutorial.with.jenkins.prereqs.skip_next_time - </label> - <Checkbox - checked={true} - className="little-spacer-left" - id="skip-prereqs" - onCheck={[MockFunction]} - thirdState={false} - /> - </p> <Button className="big-spacer-top" onClick={[MockFunction]} @@ -226,24 +190,6 @@ exports[`should render correctly: content for branches disabled, gitlab 1`] = ` > onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations </p> - <p - className="big-spacer-bottom display-flex-center" - > - <label - className="cursor-pointer" - htmlFor="skip-prereqs" - onClick={[Function]} - > - onboarding.tutorial.with.jenkins.prereqs.skip_next_time - </label> - <Checkbox - checked={true} - className="little-spacer-left" - id="skip-prereqs" - onCheck={[MockFunction]} - thirdState={false} - /> - </p> <Button className="big-spacer-top" onClick={[MockFunction]} diff --git a/server/sonar-web/src/main/js/components/tutorials/manual/ManualTutorial.tsx b/server/sonar-web/src/main/js/components/tutorials/manual/ManualTutorial.tsx index 16408ef15c1..5e3f818714d 100644 --- a/server/sonar-web/src/main/js/components/tutorials/manual/ManualTutorial.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/manual/ManualTutorial.tsx @@ -19,7 +19,8 @@ */ import * as React from 'react'; import { translate } from '../../../helpers/l10n'; -import { Component, LoggedInUser } from '../../../types/types'; +import { Component } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import InstanceMessage from '../../common/InstanceMessage'; import ProjectAnalysisStep from './ProjectAnalysisStep'; import TokenStep from './TokenStep'; diff --git a/server/sonar-web/src/main/js/components/tutorials/manual/TokenStep.tsx b/server/sonar-web/src/main/js/components/tutorials/manual/TokenStep.tsx index 622b45ab817..df9e3b63869 100644 --- a/server/sonar-web/src/main/js/components/tutorials/manual/TokenStep.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/manual/TokenStep.tsx @@ -25,7 +25,8 @@ import { Button, DeleteButton, SubmitButton } from '../../../components/controls import Radio from '../../../components/controls/Radio'; import AlertSuccessIcon from '../../../components/icons/AlertSuccessIcon'; import { translate } from '../../../helpers/l10n'; -import { LoggedInUser, UserToken } from '../../../types/types'; +import { UserToken } from '../../../types/types'; +import { LoggedInUser } from '../../../types/users'; import AlertErrorIcon from '../../icons/AlertErrorIcon'; import Step from '../components/Step'; import { getUniqueTokenName } from '../utils'; diff --git a/server/sonar-web/src/main/js/components/tutorials/manual/__tests__/TokenStep-test.tsx b/server/sonar-web/src/main/js/components/tutorials/manual/__tests__/TokenStep-test.tsx index 20bbf75cd1a..3ecf8bb1eb7 100644 --- a/server/sonar-web/src/main/js/components/tutorials/manual/__tests__/TokenStep-test.tsx +++ b/server/sonar-web/src/main/js/components/tutorials/manual/__tests__/TokenStep-test.tsx @@ -20,7 +20,7 @@ import { shallow } from 'enzyme'; import * as React from 'react'; import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils'; -import { LoggedInUser } from '../../../../types/types'; +import { LoggedInUser } from '../../../../types/users'; import TokenStep from '../TokenStep'; jest.mock('../../../../api/user-tokens', () => ({ diff --git a/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts new file mode 100644 index 00000000000..69575d5b216 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/users-test.ts @@ -0,0 +1,83 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { isSameHomePage } from '../users'; + +describe('isSameHomePage', () => { + it('should homepage equality properly', () => { + expect( + isSameHomePage( + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component' + }, + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component' + } + ) + ).toBe(true); + + expect( + isSameHomePage( + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component' + }, + { + type: 'ISSUES' + } + ) + ).toBe(false); + + expect( + isSameHomePage( + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component' + }, + { + type: 'APPLICATION', + branch: 'test-branch-1', + component: 'test-component' + } + ) + ).toBe(false); + + expect( + isSameHomePage( + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component' + }, + { + type: 'APPLICATION', + branch: 'test-branch', + component: 'test-component-1' + } + ) + ).toBe(false); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/issues.ts b/server/sonar-web/src/main/js/helpers/issues.ts index 322de67f388..8cbf77dfcaa 100644 --- a/server/sonar-web/src/main/js/helpers/issues.ts +++ b/server/sonar-web/src/main/js/helpers/issues.ts @@ -24,7 +24,8 @@ import SecurityHotspotIcon from '../components/icons/SecurityHotspotIcon'; import VulnerabilityIcon from '../components/icons/VulnerabilityIcon'; import { IssueType, RawIssue } from '../types/issues'; import { MetricKey } from '../types/metrics'; -import { Dict, FlowLocation, Issue, TextRange, UserBase } from '../types/types'; +import { Dict, FlowLocation, Issue, TextRange } from '../types/types'; +import { UserBase } from '../types/users'; import { ISSUE_TYPES } from './constants'; interface Rule {} diff --git a/server/sonar-web/src/main/js/helpers/mocks/users.ts b/server/sonar-web/src/main/js/helpers/mocks/users.ts index 75e09d1c406..d184c0ffb8c 100644 --- a/server/sonar-web/src/main/js/helpers/mocks/users.ts +++ b/server/sonar-web/src/main/js/helpers/mocks/users.ts @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { UserBase } from '../../types/types'; +import { UserBase } from '../../types/users'; export function mockUserBase(overrides: Partial<UserBase> = {}): UserBase { return { diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts index d94d804787a..3c4c452ddd7 100644 --- a/server/sonar-web/src/main/js/helpers/testMocks.ts +++ b/server/sonar-web/src/main/js/helpers/testMocks.ts @@ -32,13 +32,11 @@ import { Analysis, AnalysisEvent, Condition, - CurrentUser, FlowLocation, Group, HealthType, IdentityProvider, Issue, - LoggedInUser, Measure, MeasureEnhanced, Metric, @@ -55,9 +53,9 @@ import { SourceViewerFile, SysInfoBase, SysInfoCluster, - SysInfoStandalone, - User + SysInfoStandalone } from '../types/types'; +import { CurrentUser, LoggedInUser, User } from '../types/users'; export function mockAlmApplication(overrides: Partial<AlmApplication> = {}): AlmApplication { return { diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts index e7aaa61ddbb..cfcf6564696 100644 --- a/server/sonar-web/src/main/js/helpers/urls.ts +++ b/server/sonar-web/src/main/js/helpers/urls.ts @@ -24,7 +24,8 @@ import { ComponentQualifier, isApplication, isPortfolioLike } from '../types/com import { MeasurePageView } from '../types/measures'; import { GraphType } from '../types/project-activity'; import { SecurityStandard } from '../types/security'; -import { Dict, HomePage } from '../types/types'; +import { Dict } from '../types/types'; +import { HomePage } from '../types/users'; import { getBranchLikeQuery, isBranch, isMainBranch, isPullRequest } from './branch-like'; import { IS_SSR } from './browser'; import { serializeOptionalBoolean } from './query'; diff --git a/server/sonar-web/src/main/js/helpers/users.ts b/server/sonar-web/src/main/js/helpers/users.ts index a12c632704a..1b91344d3ec 100644 --- a/server/sonar-web/src/main/js/helpers/users.ts +++ b/server/sonar-web/src/main/js/helpers/users.ts @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { CurrentUser, LoggedInUser, UserActive, UserBase } from '../types/types'; +import { CurrentUser, HomePage } from '../types/users'; export function hasGlobalPermission(user: CurrentUser, permission: string): boolean { if (!user.permissions) { @@ -26,10 +26,10 @@ export function hasGlobalPermission(user: CurrentUser, permission: string): bool return user.permissions.global.includes(permission); } -export function isLoggedIn(user: CurrentUser): user is LoggedInUser { - return user.isLoggedIn; -} - -export function isUserActive(user: UserBase): user is UserActive { - return user.active !== false && Boolean(user.name); +export function isSameHomePage(a: HomePage, b: HomePage) { + return ( + a.type === b.type && + (a as any).branch === (b as any).branch && + (a as any).component === (b as any).component + ); } diff --git a/server/sonar-web/src/main/js/store/__tests__/users-test.tsx b/server/sonar-web/src/main/js/store/__tests__/users-test.tsx deleted file mode 100644 index fcb49ed5eed..00000000000 --- a/server/sonar-web/src/main/js/store/__tests__/users-test.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { mockCurrentUser, mockLoggedInUser, mockUser } from '../../helpers/testMocks'; -import { isLoggedIn } from '../../helpers/users'; -import { CurrentUserSetting, HomePage, LoggedInUser } from '../../types/types'; -import reducer, { - getCurrentUser, - getCurrentUserSetting, - getUserByLogin, - getUsersByLogins, - receiveCurrentUser, - setCurrentUserSettingAction, - setHomePageAction, - setSonarlintAd, - State -} from '../users'; - -describe('reducer and actions', () => { - it('should allow to receive the current user', () => { - const initialState: State = createState(); - - const currentUser = mockCurrentUser(); - const newState = reducer(initialState, receiveCurrentUser(currentUser)); - expect(newState).toEqual(createState({ currentUser })); - }); - - it('should allow to set the homepage', () => { - const homepage: HomePage = { type: 'PROJECTS' }; - const currentUser = mockLoggedInUser({ homepage: undefined }); - const initialState: State = createState({ currentUser }); - - const newState = reducer(initialState, setHomePageAction(homepage)); - expect(newState).toEqual( - createState({ currentUser: { ...currentUser, homepage } as LoggedInUser }) - ); - }); - - it('should allow to set a user setting', () => { - const setting1: CurrentUserSetting = { key: 'notifications.optOut', value: '1' }; - const setting2: CurrentUserSetting = { key: 'notifications.readDate', value: '2' }; - const setting3: CurrentUserSetting = { key: 'notifications.optOut', value: '2' }; - const currentUser = mockLoggedInUser(); - const initialState: State = createState({ currentUser }); - - const newState = reducer(initialState, setCurrentUserSettingAction(setting1)); - expect(newState).toEqual( - createState({ currentUser: { ...currentUser, settings: [setting1] } as LoggedInUser }) - ); - - const newerState = reducer(newState, setCurrentUserSettingAction(setting2)); - expect(newerState).toEqual( - createState({ - currentUser: { ...currentUser, settings: [setting1, setting2] } as LoggedInUser - }) - ); - - const newestState = reducer(newerState, setCurrentUserSettingAction(setting3)); - expect(newestState).toEqual( - createState({ - currentUser: { ...currentUser, settings: [setting3, setting2] } as LoggedInUser - }) - ); - }); - - it('should allow to set the sonarLintAdSeen flag', () => { - const currentUser = mockLoggedInUser(); - const initialState: State = createState({ currentUser }); - - const newState = reducer(initialState, setSonarlintAd()); - expect(isLoggedIn(newState.currentUser) && newState.currentUser.sonarLintAdSeen).toBe(true); - }); -}); - -describe('getters', () => { - const currentUser = mockLoggedInUser({ settings: [{ key: 'notifications.optOut', value: '1' }] }); - const jane = mockUser({ login: 'jane', name: 'Jane Doe' }); - const john = mockUser({ login: 'john' }); - const state = createState({ currentUser, usersByLogin: { jane, john } }); - - it('getCurrentUser', () => { - expect(getCurrentUser(state)).toBe(currentUser); - }); - - it('getCurrentUserSetting', () => { - expect(getCurrentUserSetting(state, 'notifications.optOut')).toBe('1'); - expect(getCurrentUserSetting(state, 'notifications.readDate')).toBeUndefined(); - }); - - it('getUserByLogin', () => { - expect(getUserByLogin(state, 'jane')).toBe(jane); - expect(getUserByLogin(state, 'steve')).toBeUndefined(); - }); - - it('getUsersByLogins', () => { - expect(getUsersByLogins(state, ['jane', 'john'])).toEqual([jane, john]); - }); -}); - -function createState(overrides: Partial<State> = {}): State { - return { usersByLogin: {}, userLogins: [], currentUser: mockCurrentUser(), ...overrides }; -} diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts index 074d20e2a59..885d7b25cdc 100644 --- a/server/sonar-web/src/main/js/store/rootReducer.ts +++ b/server/sonar-web/src/main/js/store/rootReducer.ts @@ -19,35 +19,23 @@ */ import { combineReducers } from 'redux'; import { BranchLike } from '../types/branch-like'; -import { CurrentUserSettingNames } from '../types/types'; import branches, * as fromBranches from './branches'; import globalMessages, * as fromGlobalMessages from './globalMessages'; -import users, * as fromUsers from './users'; export type Store = { branches: fromBranches.State; globalMessages: fromGlobalMessages.State; - users: fromUsers.State; }; export default combineReducers<Store>({ branches, - globalMessages, - users + globalMessages }); export function getGlobalMessages(state: Store) { return fromGlobalMessages.getGlobalMessages(state.globalMessages); } -export function getCurrentUserSetting(state: Store, key: CurrentUserSettingNames) { - return fromUsers.getCurrentUserSetting(state.users, key); -} - -export function getCurrentUser(state: Store) { - return fromUsers.getCurrentUser(state.users); -} - export function getBranchStatusByBranchLike( state: Store, component: string, diff --git a/server/sonar-web/src/main/js/store/users.ts b/server/sonar-web/src/main/js/store/users.ts deleted file mode 100644 index ebcdc85b256..00000000000 --- a/server/sonar-web/src/main/js/store/users.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { uniq } from 'lodash'; -import { combineReducers, Dispatch } from 'redux'; -import * as api from '../api/users'; -import { isLoggedIn } from '../helpers/users'; -import { - CurrentUser, - CurrentUserSetting, - CurrentUserSettingNames, - Dict, - HomePage, - LoggedInUser -} from '../types/types'; -import { ActionType } from './utils/actions'; - -const enum Actions { - ReceiveCurrentUser = 'RECEIVE_CURRENT_USER', - SetCurrentUserSetting = 'SET_CURRENT_USER_SETTING', - SetHomePageAction = 'SET_HOMEPAGE', - SetSonarlintAd = 'SET_SONARLINT_AD' -} - -type Action = - | ActionType<typeof receiveCurrentUser, Actions.ReceiveCurrentUser> - | ActionType<typeof setCurrentUserSettingAction, Actions.SetCurrentUserSetting> - | ActionType<typeof setHomePageAction, Actions.SetHomePageAction> - | ActionType<typeof setSonarlintAd, Actions.SetSonarlintAd>; - -export interface State { - usersByLogin: Dict<any>; - userLogins: string[]; - currentUser: CurrentUser; -} - -export function receiveCurrentUser(user: CurrentUser) { - return { type: Actions.ReceiveCurrentUser, user }; -} - -export function setHomePageAction(homepage: HomePage) { - return { type: Actions.SetHomePageAction, homepage }; -} - -export function setCurrentUserSettingAction(setting: CurrentUserSetting) { - return { type: Actions.SetCurrentUserSetting, setting }; -} - -export function setSonarlintAd() { - return { type: Actions.SetSonarlintAd }; -} - -export function setHomePage(homepage: HomePage) { - return (dispatch: Dispatch) => { - api.setHomePage(homepage).then( - () => { - dispatch(setHomePageAction(homepage)); - }, - () => {} - ); - }; -} - -export function setCurrentUserSetting(setting: CurrentUserSetting) { - return (dispatch: Dispatch, getState: () => { users: State }) => { - const oldSetting = getCurrentUserSetting(getState().users, setting.key); - dispatch(setCurrentUserSettingAction(setting)); - api.setUserSetting(setting).then( - () => {}, - () => { - dispatch(setCurrentUserSettingAction({ ...setting, value: oldSetting || '' })); - } - ); - }; -} - -function usersByLogin(state: State['usersByLogin'] = {}, action: Action): State['usersByLogin'] { - if (action.type === Actions.ReceiveCurrentUser && isLoggedIn(action.user)) { - return { ...state, [action.user.login]: action.user }; - } else { - return state; - } -} - -function userLogins(state: State['userLogins'] = [], action: Action): State['userLogins'] { - if (action.type === Actions.ReceiveCurrentUser && isLoggedIn(action.user)) { - return uniq([...state, action.user.login]); - } else { - return state; - } -} - -function currentUser( - state: State['currentUser'] = { isLoggedIn: false }, - action: Action -): State['currentUser'] { - if (action.type === Actions.ReceiveCurrentUser) { - return action.user; - } - if (action.type === Actions.SetHomePageAction && isLoggedIn(state)) { - return { ...state, homepage: action.homepage } as LoggedInUser; - } - if (action.type === Actions.SetCurrentUserSetting && isLoggedIn(state)) { - let settings: CurrentUserSetting[]; - if (state.settings) { - settings = [...state.settings]; - const index = settings.findIndex(setting => setting.key === action.setting.key); - if (index === -1) { - settings.push(action.setting); - } else { - settings[index] = action.setting; - } - } else { - settings = [action.setting]; - } - return { ...state, settings } as LoggedInUser; - } - if (action.type === Actions.SetSonarlintAd && isLoggedIn(state)) { - return { ...state, sonarLintAdSeen: true } as LoggedInUser; - } - return state; -} - -export default combineReducers({ usersByLogin, userLogins, currentUser }); - -export function getCurrentUser(state: State) { - return state.currentUser; -} - -export function getCurrentUserSetting(state: State, key: CurrentUserSettingNames) { - let setting; - if (isLoggedIn(state.currentUser) && state.currentUser.settings) { - setting = state.currentUser.settings.find(setting => setting.key === key); - } - return setting && setting.value; -} - -export function getUserByLogin(state: State, login: string) { - return state.usersByLogin[login]; -} - -export function getUsersByLogins(state: State, logins: string[]) { - return logins.map(login => getUserByLogin(state, login)); -} diff --git a/server/sonar-web/src/main/js/types/extension.ts b/server/sonar-web/src/main/js/types/extension.ts index b444b100e69..5ec01bd71f0 100644 --- a/server/sonar-web/src/main/js/types/extension.ts +++ b/server/sonar-web/src/main/js/types/extension.ts @@ -23,7 +23,8 @@ import { Location, Router } from '../components/hoc/withRouter'; import { Store } from '../store/rootReducer'; import { AppState } from './appstate'; import { L10nBundle } from './l10n'; -import { CurrentUser, Dict } from './types'; +import { Dict } from './types'; +import { CurrentUser } from './users'; export enum AdminPageExtension { GovernanceConsole = 'governance/views_console' diff --git a/server/sonar-web/src/main/js/types/issues.ts b/server/sonar-web/src/main/js/types/issues.ts index 960f8bd67ab..18f6e322f19 100644 --- a/server/sonar-web/src/main/js/types/issues.ts +++ b/server/sonar-web/src/main/js/types/issues.ts @@ -17,7 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { FlowLocation, Issue, Paging, TextRange, UserBase } from './types'; +import { FlowLocation, Issue, Paging, TextRange } from './types'; +import { UserBase } from './users'; export enum IssueType { CodeSmell = 'CODE_SMELL', diff --git a/server/sonar-web/src/main/js/types/quality-gates.ts b/server/sonar-web/src/main/js/types/quality-gates.ts index 9d0faaeea42..87e3532e080 100644 --- a/server/sonar-web/src/main/js/types/quality-gates.ts +++ b/server/sonar-web/src/main/js/types/quality-gates.ts @@ -18,7 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { BranchLike } from './branch-like'; -import { MeasureEnhanced, Metric, Status, UserBase } from './types'; +import { MeasureEnhanced, Metric, Status } from './types'; +import { UserBase } from './users'; export interface QualityGateProjectStatus { conditions?: QualityGateProjectStatusCondition[]; diff --git a/server/sonar-web/src/main/js/types/security-hotspots.ts b/server/sonar-web/src/main/js/types/security-hotspots.ts index 6dfa65c923b..96553ddc991 100644 --- a/server/sonar-web/src/main/js/types/security-hotspots.ts +++ b/server/sonar-web/src/main/js/types/security-hotspots.ts @@ -18,14 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { ComponentQualifier } from './component'; -import { - FlowLocation, - IssueChangelog, - IssueChangelogDiff, - Paging, - TextRange, - UserBase -} from './types'; +import { FlowLocation, IssueChangelog, IssueChangelogDiff, Paging, TextRange } from './types'; +import { UserBase } from './users'; export enum RiskExposure { LOW = 'LOW', diff --git a/server/sonar-web/src/main/js/types/types.ts b/server/sonar-web/src/main/js/types/types.ts index 2c6342be3dd..f84971c149a 100644 --- a/server/sonar-web/src/main/js/types/types.ts +++ b/server/sonar-web/src/main/js/types/types.ts @@ -17,6 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +import { UserActive, UserBase } from './users'; + export type Dict<T> = { [key: string]: T }; export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; @@ -178,40 +181,6 @@ export interface Condition { op?: string; } -export interface CoveredFile { - key: string; - longName: string; - coveredLines: number; -} - -export interface Coupon { - billing?: { - address?: string; - country?: string; - email?: string; - name?: string; - use?: string; - }; - maxNcloc: number; - planActiveUntil: string; -} - -export interface CurrentUser { - isLoggedIn: boolean; - permissions?: { global: string[] }; - usingSonarLintConnectedMode?: boolean; -} - -export interface CurrentUserSetting { - key: CurrentUserSettingNames; - value: string; -} - -export type CurrentUserSettingNames = - | 'notifications.optOut' - | 'notifications.readDate' - | 'tutorials.jenkins.skipBitbucketPreReqs'; - export interface CustomMeasure { createdAt?: string; description?: string; @@ -278,26 +247,6 @@ export interface Group { export type HealthType = 'RED' | 'YELLOW' | 'GREEN'; -export type HomePage = - | { type: 'APPLICATION'; branch: string | undefined; component: string } - | { type: 'ISSUES' } - | { type: 'MY_ISSUES' } - | { type: 'MY_PROJECTS' } - | { type: 'PORTFOLIO'; component: string } - | { type: 'PORTFOLIOS' } - | { type: 'PROJECT'; branch: string | undefined; component: string } - | { type: 'PROJECTS' }; - -export type HomePageType = - | 'APPLICATION' - | 'ISSUES' - | 'MY_ISSUES' - | 'MY_PROJECTS' - | 'PORTFOLIO' - | 'PORTFOLIOS' - | 'PROJECT' - | 'PROJECTS'; - export interface IdentityProvider { backgroundColor: string; helpMessage?: string; @@ -415,18 +364,6 @@ export interface LinePopup { open?: boolean; } -export interface LoggedInUser extends CurrentUser, UserActive { - externalIdentity?: string; - externalProvider?: string; - groups: string[]; - homepage?: HomePage; - isLoggedIn: true; - local?: boolean; - scmAccounts: string[]; - settings?: CurrentUserSetting[]; - sonarLintAdSeen?: boolean; -} - export interface Measure extends MeasureIntern { metric: string; } @@ -838,29 +775,6 @@ export interface TextRange { endOffset: number; } -export interface User extends UserBase { - externalIdentity?: string; - externalProvider?: string; - groups?: string[]; - lastConnectionDate?: string; - local: boolean; - scmAccounts?: string[]; - tokensCount?: number; -} - -export interface UserActive extends UserBase { - active?: true; - name: string; -} - -export interface UserBase { - active?: boolean; - avatar?: string; - email?: string; - login: string; - name?: string; -} - export interface UserSelected extends UserActive { selected: boolean; } diff --git a/server/sonar-web/src/main/js/types/users.ts b/server/sonar-web/src/main/js/types/users.ts new file mode 100644 index 00000000000..5c01dc64b52 --- /dev/null +++ b/server/sonar-web/src/main/js/types/users.ts @@ -0,0 +1,88 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +export interface CurrentUser { + isLoggedIn: boolean; + permissions?: { global: string[] }; + usingSonarLintConnectedMode?: boolean; +} + +export interface LoggedInUser extends CurrentUser, UserActive { + externalIdentity?: string; + externalProvider?: string; + groups: string[]; + homepage?: HomePage; + isLoggedIn: true; + local?: boolean; + scmAccounts: string[]; + settings?: CurrentUserSetting[]; + sonarLintAdSeen?: boolean; +} + +export type HomePage = + | { type: 'APPLICATION'; branch: string | undefined; component: string } + | { type: 'ISSUES' } + | { type: 'MY_ISSUES' } + | { type: 'MY_PROJECTS' } + | { type: 'PORTFOLIO'; component: string } + | { type: 'PORTFOLIOS' } + | { type: 'PROJECT'; branch: string | undefined; component: string } + | { type: 'PROJECTS' }; + +export interface CurrentUserSetting { + key: CurrentUserSettingNames; + value: string; +} + +export type CurrentUserSettingNames = + | 'notifications.optOut' + | 'notifications.readDate' + | 'tutorials.jenkins.skipBitbucketPreReqs'; + +export interface UserActive extends UserBase { + active?: true; + name: string; +} + +export interface User extends UserBase { + externalIdentity?: string; + externalProvider?: string; + groups?: string[]; + lastConnectionDate?: string; + local: boolean; + scmAccounts?: string[]; + tokensCount?: number; +} + +export interface UserBase { + active?: boolean; + avatar?: string; + email?: string; + login: string; + name?: string; +} + +export function isUserActive(user: UserBase): user is UserActive { + return user.active !== false && Boolean(user.name); +} + +export function isLoggedIn(user: CurrentUser): user is LoggedInUser { + return user.isLoggedIn; +} diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 43c6cbcfcb2..67ebbdbbadb 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3625,7 +3625,6 @@ onboarding.tutorial.with.jenkins.prereqs.plugins.sonar_scanner=SonarQube Scanner onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide=For a step by step guide on installing and configuring those plugins in Jenkins, visit the {link} documentation page. onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link=Analysis Prerequisites onboarding.tutorial.with.jenkins.prereqs.following_are_recommendations=We recommend using the configuration in the following steps for the best results, but you can customize it as needed. -onboarding.tutorial.with.jenkins.prereqs.skip_next_time=Don't show me the prerequisites next time onboarding.tutorial.with.jenkins.prereqs.done=Configure Analysis onboarding.tutorial.with.jenkins.multi_branch_pipeline.title=Create a Multibranch Pipeline Job onboarding.tutorial.with.jenkins.multi_branch_pipeline.intro=Create a Multibranch Pipeline in order to automatically analyze all your branches and pull requests. |