diff options
Diffstat (limited to 'server/sonar-web/src/main/js/app')
30 files changed, 321 insertions, 217 deletions
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/app/components/current-user/CurrentUserContext.ts b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts new file mode 100644 index 00000000000..efb10534705 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/current-user/CurrentUserContext.ts @@ -0,0 +1,31 @@ +/* + * 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'; + +export interface CurrentUserContextInterface { + currentUser: CurrentUser; + updateCurrentUserHomepage: (homepage: HomePage) => void; + updateCurrentUserSonarLintAdSeen: () => void; +} + +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/app/components/current-user/withCurrentUserContext.tsx b/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx new file mode 100644 index 00000000000..e2621f072ac --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/current-user/withCurrentUserContext.tsx @@ -0,0 +1,42 @@ +/* + * 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 { getWrappedDisplayName } from '../../../components/hoc/utils'; +import { CurrentUserContext, CurrentUserContextInterface } from './CurrentUserContext'; + +export default function withCurrentUserContext<P>( + WrappedComponent: React.ComponentType<P & Pick<CurrentUserContextInterface, 'currentUser'>> +) { + return class WithCurrentUserContext extends React.PureComponent< + Omit<P, keyof CurrentUserContextInterface> + > { + static displayName = getWrappedDisplayName(WrappedComponent, 'withCurrentUserContext'); + + render() { + return ( + <CurrentUserContext.Consumer> + {(currentUserContext: CurrentUserContextInterface) => ( + <WrappedComponent {...currentUserContext} {...(this.props as P)} /> + )} + </CurrentUserContext.Consumer> + ); + } + }; +} 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>, |