diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-12-11 17:58:18 +0100 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-01-02 10:38:10 +0100 |
commit | d04588cdf547d0e8f9290ad1cf1fa3fb0ecf6371 (patch) | |
tree | e3621c0f0cc43fa2269027a3cb0ec56ec4c68320 /server/sonar-web/src/main | |
parent | 7260d343ea6a7289695a8c509860cbcf726e433c (diff) | |
download | sonarqube-d04588cdf547d0e8f9290ad1cf1fa3fb0ecf6371.tar.gz sonarqube-d04588cdf547d0e8f9290ad1cf1fa3fb0ecf6371.zip |
SONAR-10186 fetch user organizations when app starts
Diffstat (limited to 'server/sonar-web/src/main')
7 files changed, 37 insertions, 191 deletions
diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx index 44528fc0b4d..9dd53d13369 100644 --- a/server/sonar-web/src/main/js/app/components/App.tsx +++ b/server/sonar-web/src/main/js/app/components/App.tsx @@ -23,12 +23,14 @@ import * as PropTypes from 'prop-types'; import GlobalLoading from './GlobalLoading'; import { fetchCurrentUser } from '../../store/users/actions'; import { fetchLanguages, fetchAppState } from '../../store/rootActions'; +import { fetchMyOrganizations } from '../../apps/account/organizations/actions'; interface Props { children: JSX.Element; fetchAppState: () => Promise<any>; fetchCurrentUser: () => Promise<void>; fetchLanguages: () => Promise<void>; + fetchMyOrganizations: () => Promise<void>; } interface State { @@ -66,7 +68,17 @@ class App extends React.PureComponent<Props, State> { this.props .fetchCurrentUser() .then(() => Promise.all([this.fetchAppState(), this.props.fetchLanguages()])) - .then(this.finishLoading, () => {}); + .then( + ([appState]) => { + if (this.mounted) { + if (appState.organizationsEnabled) { + this.props.fetchMyOrganizations(); + } + this.setState({ loading: false }); + } + }, + () => {} + ); } componentWillUnmount() { @@ -76,24 +88,18 @@ class App extends React.PureComponent<Props, State> { fetchAppState = () => { return this.props.fetchAppState().then(appState => { if (this.mounted) { - const onSonarCloud = - appState.settings !== undefined && - appState.settings['sonar.sonarcloud.enabled'] === 'true'; this.setState({ branchesEnabled: appState.branchesEnabled, canAdmin: appState.canAdmin, - onSonarCloud + onSonarCloud: + appState.settings !== undefined && + appState.settings['sonar.sonarcloud.enabled'] === 'true' }); } + return appState; }); }; - finishLoading = () => { - if (this.mounted) { - this.setState({ loading: false }); - } - }; - render() { if (this.state.loading) { return <GlobalLoading />; @@ -102,4 +108,9 @@ class App extends React.PureComponent<Props, State> { } } -export default connect(null, { fetchAppState, fetchCurrentUser, fetchLanguages })(App as any); +export default connect(null, { + fetchAppState, + fetchCurrentUser, + fetchLanguages, + fetchMyOrganizations +})(App as any); 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 3a5a143f963..1649a5e370e 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 @@ -33,7 +33,6 @@ import OrganizationAvatar from '../../../../components/common/OrganizationAvatar interface Props { appState: { organizationsEnabled: boolean }; currentUser: CurrentUser; - fetchMyOrganizations: () => Promise<void>; organizations: Organization[]; } @@ -91,10 +90,8 @@ export default class GlobalNavUser extends React.PureComponent<Props, State> { }; openDropdown = () => { - this.fetchMyOrganizations().then(() => { - window.addEventListener('click', this.handleClickOutside, true); - this.setState({ open: true }); - }); + window.addEventListener('click', this.handleClickOutside, true); + this.setState({ open: true }); }; closeDropdown = () => { @@ -102,13 +99,6 @@ export default class GlobalNavUser extends React.PureComponent<Props, State> { this.setState({ open: false }); }; - fetchMyOrganizations = () => { - if (this.props.appState.organizationsEnabled) { - return this.props.fetchMyOrganizations(); - } - return Promise.resolve(); - }; - renderAuthenticated() { const { organizations } = this.props; const currentUser = this.props.currentUser as LoggedInUser; @@ -163,7 +153,7 @@ export default class GlobalNavUser extends React.PureComponent<Props, State> { <OrganizationAvatar organization={organization} small={true} /> <span className="spacer-left">{organization.name}</span> </div> - {organization.canAdmin && ( + {organization.isAdmin && ( <span className="outline-badge spacer-left">{translate('admin')}</span> )} </OrganizationLink> diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx index f73200791a0..eaff69f9a86 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUserContainer.tsx @@ -20,7 +20,6 @@ import { connect } from 'react-redux'; import GlobalNavUser from './GlobalNavUser'; import { Organization } from '../../../types'; -import { fetchMyOrganizations } from '../../../../apps/account/organizations/actions'; import { getMyOrganizations } from '../../../../store/rootReducer'; interface StateProps { @@ -31,12 +30,4 @@ const mapStateToProps = (state: any): StateProps => ({ organizations: getMyOrganizations(state) }); -interface DispatchProps { - fetchMyOrganizations: () => Promise<void>; -} - -const mapDispatchToProps = { - fetchMyOrganizations: fetchMyOrganizations as any -} as DispatchProps; - -export default connect(mapStateToProps, mapDispatchToProps)(GlobalNavUser); +export default connect(mapStateToProps)(GlobalNavUser); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx index 90cf0393293..659fe6def16 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.tsx @@ -33,104 +33,35 @@ const appState = { organizationsEnabled: true }; it('should render the right interface for anonymous user', () => { const currentUser = { isLoggedIn: false }; const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={jest.fn()} - organizations={[]} - /> + <GlobalNavUser appState={appState} currentUser={currentUser} organizations={[]} /> ); expect(wrapper).toMatchSnapshot(); }); it('should render the right interface for logged in user', () => { const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={jest.fn()} - organizations={[]} - /> + <GlobalNavUser appState={appState} currentUser={currentUser} organizations={[]} /> ); wrapper.setState({ open: true }); expect(wrapper).toMatchSnapshot(); }); -it('should render the users organizations', () => { +it('should render user organizations', () => { const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={jest.fn()} - organizations={organizations} - /> + <GlobalNavUser appState={appState} currentUser={currentUser} organizations={organizations} /> ); wrapper.setState({ open: true }); expect(wrapper).toMatchSnapshot(); }); -it('should not render the users organizations when they are not activated', () => { +it('should not render user organizations when they are not activated', () => { const wrapper = shallow( <GlobalNavUser appState={{ organizationsEnabled: false }} currentUser={currentUser} - fetchMyOrganizations={jest.fn()} organizations={organizations} /> ); wrapper.setState({ open: true }); expect(wrapper).toMatchSnapshot(); }); - -it('should update the component correctly when the user changes to anonymous', () => { - const fetchMyOrganizations = jest.fn(); - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={fetchMyOrganizations} - organizations={[]} - /> - ); - wrapper.setState({ open: true }); - expect(wrapper).toMatchSnapshot(); - wrapper.setProps({ currentUser: { isLoggedIn: false } }); - expect(fetchMyOrganizations.mock.calls.length).toBe(0); - expect(wrapper).toMatchSnapshot(); -}); - -it('should lazyload the organizations when opening the dropdown', () => { - const fetchMyOrganizations = jest.fn(() => Promise.resolve()); - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={fetchMyOrganizations} - organizations={organizations} - /> - ); - expect(fetchMyOrganizations.mock.calls.length).toBe(0); - (wrapper.instance() as GlobalNavUser).openDropdown(); - expect(fetchMyOrganizations.mock.calls.length).toBe(1); - (wrapper.instance() as GlobalNavUser).openDropdown(); - expect(fetchMyOrganizations.mock.calls.length).toBe(2); -}); - -it('should update the organizations when the user changes', () => { - const fetchMyOrganizations = jest.fn(() => Promise.resolve()); - const wrapper = shallow( - <GlobalNavUser - appState={appState} - currentUser={currentUser} - fetchMyOrganizations={fetchMyOrganizations} - organizations={organizations} - /> - ); - (wrapper.instance() as GlobalNavUser).openDropdown(); - expect(fetchMyOrganizations.mock.calls.length).toBe(1); - wrapper.setProps({ - currentUser: { isLoggedIn: true, name: 'test', email: 'test@sonarsource.com' } - }); - (wrapper.instance() as GlobalNavUser).openDropdown(); - expect(fetchMyOrganizations.mock.calls.length).toBe(2); -}); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap index 3bb56aac675..23fef6f2d99 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should not render the users organizations when they are not activated 1`] = ` +exports[`should not render user organizations when they are not activated 1`] = ` <li className="dropdown js-user-authenticated open" > @@ -134,7 +134,7 @@ exports[`should render the right interface for logged in user 1`] = ` </li> `; -exports[`should render the users organizations 1`] = ` +exports[`should render user organizations 1`] = ` <li className="dropdown js-user-authenticated open" > @@ -311,76 +311,3 @@ exports[`should render the users organizations 1`] = ` </ul> </li> `; - -exports[`should update the component correctly when the user changes to anonymous 1`] = ` -<li - className="dropdown js-user-authenticated open" -> - <a - className="dropdown-toggle navbar-avatar" - href="#" - onClick={[Function]} - > - <Connect(Avatar) - hash="abcd1234" - name="foo" - size={32} - /> - </a> - <ul - className="dropdown-menu dropdown-menu-right" - > - <li - className="dropdown-item" - > - <div - className="text-ellipsis text-muted" - title="foo" - > - <strong> - foo - </strong> - </div> - <div - className="little-spacer-top text-ellipsis text-muted" - title="foo@bar.baz" - > - foo@bar.baz - </div> - </li> - <li - className="divider" - /> - <li> - <Link - onClick={[Function]} - onlyActiveOnIndex={false} - style={Object {}} - to="/account" - > - my_account.page - </Link> - </li> - <li> - <a - href="#" - onClick={[Function]} - > - layout.logout - </a> - </li> - </ul> -</li> -`; - -exports[`should update the component correctly when the user changes to anonymous 2`] = ` -<li> - <a - className="navbar-login" - href="#" - onClick={[Function]} - > - layout.login - </a> -</li> -`; diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index a180856c47a..af3c21a26db 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -115,6 +115,7 @@ export interface Organization { canProvisionProjects?: boolean; canUpdateProjectsVisibilityToPrivate?: boolean; description?: string; + isAdmin?: boolean; isDefault?: boolean; key: string; name: string; diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx index c33f2be07eb..e6f34fbd8e2 100644 --- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx +++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx @@ -23,7 +23,7 @@ import { connect } from 'react-redux'; import OrganizationsList from './OrganizationsList'; import CreateOrganizationForm from './CreateOrganizationForm'; import { translate } from '../../../helpers/l10n'; -import { fetchIfAnyoneCanCreateOrganizations, fetchMyOrganizations } from './actions'; +import { fetchIfAnyoneCanCreateOrganizations } from './actions'; import { getAppState, getMyOrganizations, getGlobalSettingValue } from '../../../store/rootReducer'; import { Organization } from '../../../app/types'; @@ -35,7 +35,6 @@ interface StateProps { interface DispatchProps { fetchIfAnyoneCanCreateOrganizations: () => Promise<void>; - fetchMyOrganizations: () => Promise<void>; } interface Props extends StateProps, DispatchProps {} @@ -51,10 +50,7 @@ class UserOrganizations extends React.PureComponent<Props, State> { componentDidMount() { this.mounted = true; - Promise.all([ - this.props.fetchMyOrganizations(), - this.props.fetchIfAnyoneCanCreateOrganizations() - ]).then(this.stopLoading, this.stopLoading); + this.props.fetchIfAnyoneCanCreateOrganizations().then(this.stopLoading, this.stopLoading); } componentWillUnmount() { @@ -133,7 +129,6 @@ const mapStateToProps = (state: any): StateProps => ({ }); const mapDispatchToProps = { - fetchMyOrganizations: fetchMyOrganizations as any, fetchIfAnyoneCanCreateOrganizations: fetchIfAnyoneCanCreateOrganizations as any } as DispatchProps; |