@@ -91,9 +91,9 @@ class App extends React.PureComponent<Props, State> { | |||
this.setState({ | |||
branchesEnabled: appState.branchesEnabled, | |||
canAdmin: appState.canAdmin, | |||
onSonarCloud: | |||
appState.settings !== undefined && | |||
appState.settings['sonar.sonarcloud.enabled'] === 'true' | |||
onSonarCloud: Boolean( | |||
appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true' | |||
) | |||
}); | |||
} | |||
return appState; |
@@ -18,6 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import * as PropTypes from 'prop-types'; | |||
import { Link } from 'react-router'; | |||
import GlobalFooterSonarCloud from './GlobalFooterSonarCloud'; | |||
import GlobalFooterBranding from './GlobalFooterBranding'; | |||
@@ -26,72 +27,73 @@ import { translate, translateWithParameters } from '../../helpers/l10n'; | |||
interface Props { | |||
hideLoggedInInfo?: boolean; | |||
productionDatabase: boolean; | |||
onSonarCloud?: { value: string }; | |||
sonarqubeVersion?: string; | |||
} | |||
export default function GlobalFooter({ | |||
hideLoggedInInfo, | |||
productionDatabase, | |||
onSonarCloud, | |||
sonarqubeVersion | |||
}: Props) { | |||
if (onSonarCloud && onSonarCloud.value === 'true') { | |||
return <GlobalFooterSonarCloud />; | |||
} | |||
export default class GlobalFooter extends React.PureComponent<Props> { | |||
static contextTypes = { | |||
onSonarCloud: PropTypes.bool | |||
}; | |||
return ( | |||
<div id="footer" className="page-footer page-container"> | |||
{productionDatabase === false && ( | |||
<div className="alert alert-danger"> | |||
<p className="big" id="evaluation_warning"> | |||
{translate('footer.production_database_warning')} | |||
</p> | |||
<p>{translate('footer.production_database_explanation')}</p> | |||
</div> | |||
)} | |||
render() { | |||
const { hideLoggedInInfo, productionDatabase, sonarqubeVersion } = this.props; | |||
if (this.context.onSonarCloud) { | |||
return <GlobalFooterSonarCloud />; | |||
} | |||
<GlobalFooterBranding /> | |||
return ( | |||
<div id="footer" className="page-footer page-container"> | |||
{productionDatabase === false && ( | |||
<div className="alert alert-danger"> | |||
<p className="big" id="evaluation_warning"> | |||
{translate('footer.production_database_warning')} | |||
</p> | |||
<p>{translate('footer.production_database_explanation')}</p> | |||
</div> | |||
)} | |||
<ul className="page-footer-menu"> | |||
{!hideLoggedInInfo && | |||
sonarqubeVersion && ( | |||
<li className="page-footer-menu-item"> | |||
{translateWithParameters('footer.version_x', sonarqubeVersion)} | |||
</li> | |||
)} | |||
<li className="page-footer-menu-item"> | |||
<a href="http://www.gnu.org/licenses/lgpl-3.0.txt">{translate('footer.license')}</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="http://www.sonarqube.org">{translate('footer.community')}</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/home.html"> | |||
{translate('footer.documentation')} | |||
</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/community.html"> | |||
{translate('footer.support')} | |||
</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/plugin-library.html"> | |||
{translate('footer.plugins')} | |||
</a> | |||
</li> | |||
{!hideLoggedInInfo && ( | |||
<GlobalFooterBranding /> | |||
<ul className="page-footer-menu"> | |||
{!hideLoggedInInfo && | |||
sonarqubeVersion && ( | |||
<li className="page-footer-menu-item"> | |||
{translateWithParameters('footer.version_x', sonarqubeVersion)} | |||
</li> | |||
)} | |||
<li className="page-footer-menu-item"> | |||
<Link to="/web_api">{translate('footer.web_api')}</Link> | |||
<a href="http://www.gnu.org/licenses/lgpl-3.0.txt">{translate('footer.license')}</a> | |||
</li> | |||
)} | |||
{!hideLoggedInInfo && ( | |||
<li className="page-footer-menu-item"> | |||
<Link to="/about">{translate('footer.about')}</Link> | |||
<a href="http://www.sonarqube.org">{translate('footer.community')}</a> | |||
</li> | |||
)} | |||
</ul> | |||
</div> | |||
); | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/home.html"> | |||
{translate('footer.documentation')} | |||
</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/community.html"> | |||
{translate('footer.support')} | |||
</a> | |||
</li> | |||
<li className="page-footer-menu-item"> | |||
<a href="https://redirect.sonarsource.com/doc/plugin-library.html"> | |||
{translate('footer.plugins')} | |||
</a> | |||
</li> | |||
{!hideLoggedInInfo && ( | |||
<li className="page-footer-menu-item"> | |||
<Link to="/web_api">{translate('footer.web_api')}</Link> | |||
</li> | |||
)} | |||
{!hideLoggedInInfo && ( | |||
<li className="page-footer-menu-item"> | |||
<Link to="/about">{translate('footer.about')}</Link> | |||
</li> | |||
)} | |||
</ul> | |||
</div> | |||
); | |||
} | |||
} |
@@ -18,19 +18,21 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { connect } from 'react-redux'; | |||
import { getAppState, getGlobalSettingValue } from '../../store/rootReducer'; | |||
import { getAppState } from '../../store/rootReducer'; | |||
import GlobalFooter from './GlobalFooter'; | |||
interface StateProps { | |||
onSonarCloud?: { value: string }; | |||
productionDatabase: boolean; | |||
sonarqubeVersion?: string; | |||
} | |||
interface OwnProps { | |||
hideLoggedInInfo?: boolean; | |||
} | |||
const mapStateToProps = (state: any): StateProps => ({ | |||
sonarqubeVersion: getAppState(state).version, | |||
productionDatabase: getAppState(state).productionDatabase, | |||
onSonarCloud: getGlobalSettingValue(state, 'sonar.sonarcloud.enabled') | |||
productionDatabase: getAppState(state).productionDatabase | |||
}); | |||
export default connect(mapStateToProps)(GlobalFooter); | |||
export default connect<StateProps, {}, OwnProps>(mapStateToProps)(GlobalFooter); |
@@ -24,7 +24,7 @@ export default function GlobalFooterSonarCloud() { | |||
return ( | |||
<div id="footer" className="page-footer page-container"> | |||
<div> | |||
© 2008-2018, SonarCloud.io by{' '} | |||
© 2008-2018, SonarCloud by{' '} | |||
<a href="http://www.sonarsource.com" title="SonarSource SA"> | |||
SonarSource SA | |||
</a> |
@@ -18,8 +18,11 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import GlobalFooterContainer from './GlobalFooterContainer'; | |||
import * as PropTypes from 'prop-types'; | |||
import * as theme from '../theme'; | |||
import GlobalLoading from './GlobalLoading'; | |||
import GlobalFooterContainer from './GlobalFooterContainer'; | |||
import { tryGetGlobalNavigation } from '../../api/nav'; | |||
import NavBar from '../../components/nav/NavBar'; | |||
interface Props { | |||
@@ -27,19 +30,62 @@ interface Props { | |||
hideLoggedInInfo?: boolean; | |||
} | |||
export default function SimpleContainer(props: Props) { | |||
return ( | |||
<div className="global-container"> | |||
<div className="page-wrapper" id="container"> | |||
<NavBar className="navbar-global" height={theme.globalNavHeightRaw} /> | |||
interface State { | |||
loading: boolean; | |||
onSonarCloud: boolean; | |||
} | |||
export default class SimpleContainer extends React.PureComponent<Props, State> { | |||
mounted: boolean; | |||
static childContextTypes = { | |||
onSonarCloud: PropTypes.bool | |||
}; | |||
state: State = { loading: true, onSonarCloud: false }; | |||
getChildContext() { | |||
return { onSonarCloud: this.state.onSonarCloud }; | |||
} | |||
componentDidMount() { | |||
this.mounted = true; | |||
tryGetGlobalNavigation().then( | |||
appState => { | |||
if (this.mounted) { | |||
this.setState({ | |||
loading: false, | |||
onSonarCloud: Boolean( | |||
appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true' | |||
) | |||
}); | |||
} | |||
}, | |||
() => {} | |||
); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
render() { | |||
if (this.state.loading) { | |||
return <GlobalLoading />; | |||
} | |||
return ( | |||
<div className="global-container"> | |||
<div className="page-wrapper" id="container"> | |||
<NavBar className="navbar-global" height={theme.globalNavHeightRaw} /> | |||
<div id="bd" className="page-wrapper-simple"> | |||
<div id="nonav" className="page-simple"> | |||
{props.children} | |||
<div id="bd" className="page-wrapper-simple"> | |||
<div id="nonav" className="page-simple"> | |||
{this.props.children} | |||
</div> | |||
</div> | |||
</div> | |||
<GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} /> | |||
</div> | |||
<GlobalFooterContainer hideLoggedInInfo={props.hideLoggedInInfo} /> | |||
</div> | |||
); | |||
); | |||
} | |||
} |
@@ -22,34 +22,29 @@ import { shallow } from 'enzyme'; | |||
import GlobalFooter from '../GlobalFooter'; | |||
it('should render the only logged in information', () => { | |||
expect(shallow(<GlobalFooter productionDatabase={true} />)).toMatchSnapshot(); | |||
expect(getWrapper()).toMatchSnapshot(); | |||
}); | |||
it('should not render the only logged in information', () => { | |||
expect( | |||
shallow( | |||
<GlobalFooter | |||
hideLoggedInInfo={true} | |||
productionDatabase={true} | |||
onSonarCloud={{ value: 'false' }} | |||
sonarqubeVersion="6.4-SNAPSHOT" | |||
/> | |||
) | |||
getWrapper({ hideLoggedInInfo: true, sonarqubeVersion: '6.4-SNAPSHOT' }) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should show the db warning message', () => { | |||
expect(shallow(<GlobalFooter productionDatabase={false} />).find('.alert')).toMatchSnapshot(); | |||
expect(getWrapper({ productionDatabase: false }).find('.alert')).toMatchSnapshot(); | |||
}); | |||
it('should display the sq version', () => { | |||
expect( | |||
shallow(<GlobalFooter productionDatabase={true} sonarqubeVersion="6.4-SNAPSHOT" />) | |||
).toMatchSnapshot(); | |||
expect(getWrapper({ sonarqubeVersion: '6.4-SNAPSHOT' })).toMatchSnapshot(); | |||
}); | |||
it('should render SonarCloud footer', () => { | |||
expect( | |||
shallow(<GlobalFooter productionDatabase={true} onSonarCloud={{ value: 'true' }} />) | |||
).toMatchSnapshot(); | |||
expect(getWrapper({}, true)).toMatchSnapshot(); | |||
}); | |||
function getWrapper(props = {}, onSonarCloud = false) { | |||
return shallow(<GlobalFooter productionDatabase={true} {...props} />, { | |||
context: { onSonarCloud } | |||
}); | |||
} |
@@ -6,7 +6,7 @@ exports[`should render correctly 1`] = ` | |||
id="footer" | |||
> | |||
<div> | |||
© 2008-2018, SonarCloud.io by | |||
© 2008-2018, SonarCloud by | |||
<a | |||
href="http://www.sonarsource.com" |
@@ -18,10 +18,10 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import * as PropTypes from 'prop-types'; | |||
import { connect } from 'react-redux'; | |||
import LoginForm from './LoginForm'; | |||
import { doLogin } from '../../../store/rootActions'; | |||
import { tryGetGlobalNavigation } from '../../../api/nav'; | |||
import { IdentityProvider, getIdentityProviders } from '../../../api/users'; | |||
import { getBaseUrl } from '../../../helpers/urls'; | |||
@@ -32,25 +32,28 @@ interface Props { | |||
interface State { | |||
identityProviders?: IdentityProvider[]; | |||
onSonarCloud: boolean; | |||
} | |||
class LoginFormContainer extends React.PureComponent<Props, State> { | |||
mounted: boolean; | |||
state: State = { onSonarCloud: false }; | |||
static contextTypes = { | |||
onSonarCloud: PropTypes.bool | |||
}; | |||
state: State = {}; | |||
componentDidMount() { | |||
this.mounted = true; | |||
Promise.all([getIdentityProviders(), tryGetGlobalNavigation()]).then( | |||
([identityProvidersResponse, appState]) => { | |||
getIdentityProviders().then( | |||
identityProvidersResponse => { | |||
if (this.mounted) { | |||
this.setState({ | |||
onSonarCloud: | |||
appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true', | |||
identityProviders: identityProvidersResponse.identityProviders | |||
}); | |||
} | |||
} | |||
}, | |||
() => {} | |||
); | |||
} | |||
@@ -73,7 +76,7 @@ class LoginFormContainer extends React.PureComponent<Props, State> { | |||
}; | |||
render() { | |||
const { identityProviders, onSonarCloud } = this.state; | |||
const { identityProviders } = this.state; | |||
if (!identityProviders) { | |||
return null; | |||
} | |||
@@ -81,7 +84,7 @@ class LoginFormContainer extends React.PureComponent<Props, State> { | |||
return ( | |||
<LoginForm | |||
identityProviders={identityProviders} | |||
onSonarCloud={onSonarCloud} | |||
onSonarCloud={this.context.onSonarCloud} | |||
onSubmit={this.handleSubmit} | |||
returnTo={this.getReturnUrl()} | |||
/> |