diff options
Diffstat (limited to 'server/sonar-web/src/main/js/app/components/nav')
18 files changed, 579 insertions, 528 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js index d0e02dcbae8..ed484f8453f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.js @@ -28,18 +28,18 @@ import { getTasksForComponent } from '../../../../api/ce'; import { STATUSES } from '../../../../apps/background-tasks/constants'; export default React.createClass({ - componentDidMount () { + componentDidMount() { this.mounted = true; this.loadStatus(); this.populateRecentHistory(); }, - componentWillUnmount () { + componentWillUnmount() { this.mounted = false; }, - loadStatus () { + loadStatus() { getTasksForComponent(this.props.component.id).then(r => { if (this.mounted) { this.setState({ @@ -51,7 +51,7 @@ export default React.createClass({ }); }, - populateRecentHistory () { + populateRecentHistory() { const { breadcrumbs } = this.props.component; const { qualifier } = breadcrumbs[breadcrumbs.length - 1]; if (['TRK', 'VW', 'DEV'].indexOf(qualifier) !== -1) { @@ -64,33 +64,34 @@ export default React.createClass({ } }, - render () { + render() { return ( - <nav className="navbar navbar-context page-container" id="context-navigation"> - <div className="navbar-context-inner"> - <div className="container"> - <ComponentNavFavorite - component={this.props.component.key} - favorite={this.props.component.isFavorite}/> + <nav className="navbar navbar-context page-container" id="context-navigation"> + <div className="navbar-context-inner"> + <div className="container"> + <ComponentNavFavorite + component={this.props.component.key} + favorite={this.props.component.isFavorite} + /> - <ComponentNavBreadcrumbs - component={this.props.component} - breadcrumbs={this.props.component.breadcrumbs}/> + <ComponentNavBreadcrumbs + component={this.props.component} + breadcrumbs={this.props.component.breadcrumbs} + /> - <TooltipsContainer options={{ delay: { show: 0, hide: 2000 } }}> - <ComponentNavMeta - {...this.props} - {...this.state} - version={this.props.component.version} - snapshotDate={this.props.component.snapshotDate}/> - </TooltipsContainer> + <TooltipsContainer options={{ delay: { show: 0, hide: 2000 } }}> + <ComponentNavMeta + {...this.props} + {...this.state} + version={this.props.component.version} + snapshotDate={this.props.component.snapshotDate} + /> + </TooltipsContainer> - <ComponentNavMenu - component={this.props.component} - conf={this.props.conf}/> - </div> + <ComponentNavMenu component={this.props.component} conf={this.props.conf} /> </div> - </nav> + </div> + </nav> ); } }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js index 1915257f6c4..05648e1bec5 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.js @@ -29,7 +29,7 @@ class ComponentNavBreadcrumbs extends React.Component { breadcrumbs: React.PropTypes.array }; - render () { + render() { const { breadcrumbs, organization, shouldOrganizationBeDisplayed } = this.props; if (!breadcrumbs) { @@ -42,47 +42,46 @@ class ComponentNavBreadcrumbs extends React.Component { const items = breadcrumbs.map((item, index) => { return ( - <span key={item.key}> - {!displayOrganization && index === 0 && ( - <span className="navbar-context-title-qualifier little-spacer-right"> - <QualifierIcon qualifier={lastItem.qualifier}/> - </span> - )} - <Link to={{ pathname: '/dashboard', query: { id: item.key } }} className="link-base-color"> - {index === breadcrumbs.length - 1 ? ( - <strong>{item.name}</strong> - ) : ( - <span>{item.name}</span> - )} - </Link> - {index < breadcrumbs.length - 1 && ( - <span className="slash-separator"/> - )} - </span> + <span key={item.key}> + {!displayOrganization && + index === 0 && + <span className="navbar-context-title-qualifier little-spacer-right"> + <QualifierIcon qualifier={lastItem.qualifier} /> + </span>} + <Link + to={{ pathname: '/dashboard', query: { id: item.key } }} + className="link-base-color" + > + {index === breadcrumbs.length - 1 + ? <strong>{item.name}</strong> + : <span>{item.name}</span>} + </Link> + {index < breadcrumbs.length - 1 && <span className="slash-separator" />} + </span> ); }); return ( - <h2 className="navbar-context-title"> - {displayOrganization && ( - <span> - <span className="navbar-context-title-qualifier little-spacer-right"> - <QualifierIcon qualifier={lastItem.qualifier}/> - </span> - <OrganizationLink organization={organization} className="link-base-color"> - {organization.name} - </OrganizationLink> - <span className="slash-separator"/> - </span> - )} - {items} - </h2> + <h2 className="navbar-context-title"> + {displayOrganization && + <span> + <span className="navbar-context-title-qualifier little-spacer-right"> + <QualifierIcon qualifier={lastItem.qualifier} /> + </span> + <OrganizationLink organization={organization} className="link-base-color"> + {organization.name} + </OrganizationLink> + <span className="slash-separator" /> + </span>} + {items} + </h2> ); } } const mapStateToProps = (state, ownProps) => ({ - organization: ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization), + organization: ownProps.component.organization && + getOrganizationByKey(state, ownProps.component.organization), shouldOrganizationBeDisplayed: areThereCustomOrganizations(state) }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavFavorite.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavFavorite.js index 20a96f79203..4ae31ef1fb7 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavFavorite.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavFavorite.js @@ -27,17 +27,15 @@ class ComponentNavFavorite extends React.Component { currentUser: React.PropTypes.object.isRequired }; - render () { + render() { if (!this.props.currentUser.isLoggedIn) { return null; } return ( - <div className="navbar-context-favorite"> - <Favorite - component={this.props.component} - favorite={this.props.favorite}/> - </div> + <div className="navbar-context-favorite"> + <Favorite component={this.props.component} favorite={this.props.favorite} /> + </div> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js index c6203fb9017..6d3cc006dc3 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.js @@ -41,241 +41,256 @@ export default class ComponentNavMenu extends React.Component { conf: React.PropTypes.object.isRequired }; - isProject () { + isProject() { return this.props.component.qualifier === 'TRK'; } - isDeveloper () { + isDeveloper() { return this.props.component.qualifier === 'DEV'; } - isView () { + isView() { const { qualifier } = this.props.component; return qualifier === 'VW' || qualifier === 'SVW'; } - shouldShowAdministration () { + shouldShowAdministration() { return Object.keys(this.props.conf).some(key => this.props.conf[key]); } - renderDashboardLink () { + renderDashboardLink() { const pathname = this.isView() ? '/view' : '/dashboard'; return ( - <li> - <Link - to={{ pathname, query: { id: this.props.component.key } }} - activeClassName="active"> - <i className="icon-home"/> - </Link> - </li> + <li> + <Link to={{ pathname, query: { id: this.props.component.key } }} activeClassName="active"> + <i className="icon-home" /> + </Link> + </li> ); } - renderCodeLink () { + renderCodeLink() { if (this.isDeveloper()) { return null; } return ( - <li> - <Link - to={{ pathname: '/code', query: { id: this.props.component.key } }} - activeClassName="active"> - {this.isView() ? translate('view_projects.page') : translate('code.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/code', query: { id: this.props.component.key } }} + activeClassName="active" + > + {this.isView() ? translate('view_projects.page') : translate('code.page')} + </Link> + </li> ); } - renderActivityLink () { + renderActivityLink() { if (!this.isProject()) { return null; } return ( - <li> - <Link to={{ pathname: '/project/activity', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('project_activity.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/activity', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('project_activity.page')} + </Link> + </li> ); } - renderComponentIssuesLink () { + renderComponentIssuesLink() { return ( - <li> - <Link - to={{ pathname: '/component_issues', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('issues.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/component_issues', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('issues.page')} + </Link> + </li> ); } - renderComponentMeasuresLink () { + renderComponentMeasuresLink() { return ( - <li> - <Link - to={{ pathname: '/component_measures', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('layout.measures')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/component_measures', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('layout.measures')} + </Link> + </li> ); } - renderAdministration () { + renderAdministration() { if (!this.shouldShowAdministration()) { return null; } const isSettingsActive = SETTINGS_URLS.some(url => window.location.href.indexOf(url) !== -1); const className = 'dropdown' + (isSettingsActive ? ' active' : ''); return ( - <li className={className}> - <a className="dropdown-toggle navbar-admin-link" - id="component-navigation-admin" data-toggle="dropdown" href="#"> - {translate('layout.settings')} - <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - {this.renderSettingsLink()} - {this.renderProfilesLink()} - {this.renderQualityGateLink()} - {this.renderCustomMeasuresLink()} - {this.renderLinksLink()} - {this.renderPermissionsLink()} - {this.renderBackgroundTasksLink()} - {this.renderUpdateKeyLink()} - {this.renderAdminExtensions()} - {this.renderDeletionLink()} - </ul> - </li> + <li className={className}> + <a + className="dropdown-toggle navbar-admin-link" + id="component-navigation-admin" + data-toggle="dropdown" + href="#" + > + {translate('layout.settings')} + <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + {this.renderSettingsLink()} + {this.renderProfilesLink()} + {this.renderQualityGateLink()} + {this.renderCustomMeasuresLink()} + {this.renderLinksLink()} + {this.renderPermissionsLink()} + {this.renderBackgroundTasksLink()} + {this.renderUpdateKeyLink()} + {this.renderAdminExtensions()} + {this.renderDeletionLink()} + </ul> + </li> ); } - renderSettingsLink () { + renderSettingsLink() { if (!this.props.conf.showSettings) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/settings', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('project_settings.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/settings', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('project_settings.page')} + </Link> + </li> ); } - renderProfilesLink () { + renderProfilesLink() { if (!this.props.conf.showQualityProfiles) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/quality_profiles', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('project_quality_profiles.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/quality_profiles', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('project_quality_profiles.page')} + </Link> + </li> ); } - renderQualityGateLink () { + renderQualityGateLink() { if (!this.props.conf.showQualityGates) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/quality_gate', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('project_quality_gate.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/quality_gate', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('project_quality_gate.page')} + </Link> + </li> ); } - renderCustomMeasuresLink () { + renderCustomMeasuresLink() { if (!this.props.conf.showManualMeasures) { return null; } return ( - <li> - <Link - to={{ pathname: '/custom_measures', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('custom_measures.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/custom_measures', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('custom_measures.page')} + </Link> + </li> ); } - renderLinksLink () { + renderLinksLink() { if (!this.props.conf.showLinks) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/links', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('project_links.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/links', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('project_links.page')} + </Link> + </li> ); } - renderPermissionsLink () { + renderPermissionsLink() { if (!this.props.conf.showPermissions) { return null; } return ( - <li> - <Link - to={{ pathname: '/project_roles', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('permissions.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project_roles', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('permissions.page')} + </Link> + </li> ); } - renderBackgroundTasksLink () { + renderBackgroundTasksLink() { if (!this.props.conf.showBackgroundTasks) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/background_tasks', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('background_tasks.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/background_tasks', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('background_tasks.page')} + </Link> + </li> ); } - renderUpdateKeyLink () { + renderUpdateKeyLink() { if (!this.props.conf.showUpdateKey) { return null; } return ( - <li> - <Link - to={{ pathname: '/project/key', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('update_key.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/key', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('update_key.page')} + </Link> + </li> ); } - renderDeletionLink () { + renderDeletionLink() { const { qualifier } = this.props.component; if (!this.props.conf.showSettings) { @@ -287,33 +302,34 @@ export default class ComponentNavMenu extends React.Component { } return ( - <li> - <Link - to={{ pathname: '/project/deletion', query: { id: this.props.component.key } }} - activeClassName="active"> - {translate('deletion.page')} - </Link> - </li> + <li> + <Link + to={{ pathname: '/project/deletion', query: { id: this.props.component.key } }} + activeClassName="active" + > + {translate('deletion.page')} + </Link> + </li> ); } renderExtension = ({ key, name }, isAdmin = false) => { const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`; return ( - <li key={key}> - <Link to={{ pathname, query: { id: this.props.component.key } }} activeClassName="active"> - {name} - </Link> - </li> + <li key={key}> + <Link to={{ pathname, query: { id: this.props.component.key } }} activeClassName="active"> + {name} + </Link> + </li> ); }; - renderAdminExtensions () { + renderAdminExtensions() { const extensions = this.props.conf.extensions || []; return extensions.map(e => this.renderExtension(e, true)); } - renderExtensions () { + renderExtensions() { const extensions = this.props.component.extensions || []; const withoutGovernance = extensions.filter(ext => ext.name !== 'Governance'); if (!withoutGovernance.length) { @@ -321,29 +337,34 @@ export default class ComponentNavMenu extends React.Component { } return ( - <li className="dropdown"> - <a className="dropdown-toggle" id="component-navigation-more" data-toggle="dropdown" href="#"> - {translate('more')} - <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - {withoutGovernance.map(this.renderExtension)} - </ul> - </li> + <li className="dropdown"> + <a + className="dropdown-toggle" + id="component-navigation-more" + data-toggle="dropdown" + href="#" + > + {translate('more')} + <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + {withoutGovernance.map(this.renderExtension)} + </ul> + </li> ); } - render () { + render() { return ( - <ul className="nav navbar-nav nav-tabs"> - {this.renderDashboardLink()} - {this.renderComponentIssuesLink()} - {this.renderComponentMeasuresLink()} - {this.renderCodeLink()} - {this.renderActivityLink()} - {this.renderAdministration()} - {this.renderExtensions()} - </ul> + <ul className="nav navbar-nav nav-tabs"> + {this.renderDashboardLink()} + {this.renderComponentIssuesLink()} + {this.renderComponentMeasuresLink()} + {this.renderCodeLink()} + {this.renderActivityLink()} + {this.renderAdministration()} + {this.renderExtensions()} + </ul> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.js b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.js index bd2273f9662..21fc78a5de4 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.js @@ -23,40 +23,43 @@ import PendingIcon from '../../../../components/shared/pending-icon'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; export default React.createClass({ - render () { + render() { const metaList = []; const canSeeBackgroundTasks = this.props.conf.showBackgroundTasks; - const backgroundTasksUrl = - `${window.baseUrl}/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; + const backgroundTasksUrl = window.baseUrl + + `/project/background_tasks?id=${encodeURIComponent(this.props.component.key)}`; if (this.props.isInProgress) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.in_progress.admin', backgroundTasksUrl) : - translate('component_navigation.status.in_progress'); + const tooltip = canSeeBackgroundTasks + ? translateWithParameters( + 'component_navigation.status.in_progress.admin', + backgroundTasksUrl + ) + : translate('component_navigation.status.in_progress'); metaList.push( <li key="isInProgress" data-toggle="tooltip" title={tooltip}> - <i className="spinner" style={{ marginTop: '-1px' }}/> - {' '} - <span className="text-info">{translate('background_task.status.IN_PROGRESS')}</span> - </li> + <i className="spinner" style={{ marginTop: '-1px' }} /> + {' '} + <span className="text-info">{translate('background_task.status.IN_PROGRESS')}</span> + </li> ); } else if (this.props.isPending) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.pending.admin', backgroundTasksUrl) : - translate('component_navigation.status.pending'); + const tooltip = canSeeBackgroundTasks + ? translateWithParameters('component_navigation.status.pending.admin', backgroundTasksUrl) + : translate('component_navigation.status.pending'); metaList.push( <li key="isPending" data-toggle="tooltip" title={tooltip}> - <PendingIcon/> <span>{translate('background_task.status.PENDING')}</span> - </li> + <PendingIcon /> <span>{translate('background_task.status.PENDING')}</span> + </li> ); } else if (this.props.isFailed) { - const tooltip = canSeeBackgroundTasks ? - translateWithParameters('component_navigation.status.failed.admin', backgroundTasksUrl) : - translate('component_navigation.status.failed'); + const tooltip = canSeeBackgroundTasks + ? translateWithParameters('component_navigation.status.failed.admin', backgroundTasksUrl) + : translate('component_navigation.status.failed'); metaList.push( <li key="isFailed" data-toggle="tooltip" title={tooltip}> - <span className="badge badge-danger">{translate('background_task.status.FAILED')}</span> - </li> + <span className="badge badge-danger">{translate('background_task.status.FAILED')}</span> + </li> ); } @@ -69,9 +72,9 @@ export default React.createClass({ } return ( - <div className="navbar-context-meta"> - <ul className="list-inline">{metaList}</ul> - </div> + <div className="navbar-context-meta"> + <ul className="list-inline">{metaList}</ul> + </div> ); } }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js b/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js index a783c0344ff..6cd25ac4072 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/RecentHistory.js @@ -29,7 +29,7 @@ type History = Array<{ }>; export default class RecentHistory { - static get (): History { + static get(): History { let history = localStorage.getItem(STORAGE_KEY); if (history == null) { history = []; @@ -44,15 +44,20 @@ export default class RecentHistory { return history; } - static set (newHistory: History): void { + static set(newHistory: History): void { localStorage.setItem(STORAGE_KEY, JSON.stringify(newHistory)); } - static clear (): void { + static clear(): void { localStorage.removeItem(STORAGE_KEY); } - static add (componentKey: string, componentName: string, icon: string, organization?: string): void { + static add( + componentKey: string, + componentName: string, + icon: string, + organization?: string + ): void { const sonarHistory = RecentHistory.get(); const newEntry = { key: componentKey, name: componentName, icon, organization }; let newHistory = sonarHistory.filter(entry => entry.key !== newEntry.key); @@ -61,7 +66,7 @@ export default class RecentHistory { RecentHistory.set(newHistory); } - static remove (componentKey: string): void { + static remove(componentKey: string): void { const history = RecentHistory.get(); const newHistory = history.filter(entry => entry.key !== componentKey); RecentHistory.set(newHistory); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.js b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.js index e8c6e930bd0..6fce85f2d97 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.js @@ -23,7 +23,7 @@ import { Unconnected } from '../ComponentNavBreadcrumbs'; it('should not render breadcrumbs with one element', () => { const breadcrumbs = [{ key: 'my-project', name: 'My Project', qualifier: 'TRK' }]; - const result = shallow(<Unconnected breadcrumbs={breadcrumbs}/>); + const result = shallow(<Unconnected breadcrumbs={breadcrumbs} />); expect(result).toMatchSnapshot(); }); @@ -32,8 +32,10 @@ it('should render organization', () => { const organization = { key: 'foo', name: 'The Foo Organization' }; const result = shallow( <Unconnected - breadcrumbs={breadcrumbs} - organization={organization} - shouldOrganizationBeDisplayed={true}/>); + breadcrumbs={breadcrumbs} + organization={organization} + shouldOrganizationBeDisplayed={true} + /> + ); expect(result).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.js b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.js index 257d3c9f02e..024f2a4a7a0 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.js +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.js @@ -30,6 +30,6 @@ it('should work with extensions', () => { showSettings: true, extensions: [{ key: 'foo', name: 'Foo' }] }; - const wrapper = shallow(<ComponentNavMenu component={component} conf={conf}/>); + const wrapper = shallow(<ComponentNavMenu component={component} conf={conf} />); expect(wrapper).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js index d4a04a25860..ef83aed3921 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.js @@ -27,11 +27,11 @@ import ShortcutsHelpView from './ShortcutsHelpView'; import { getCurrentUser, getAppState } from '../../../../store/rootReducer'; class GlobalNav extends React.Component { - componentDidMount () { + componentDidMount() { window.addEventListener('keypress', this.onKeyPress); } - componentWillUnmount () { + componentWillUnmount() { window.removeEventListener('keypress', this.onKeyPress); } @@ -53,25 +53,25 @@ class GlobalNav extends React.Component { new ShortcutsHelpView().render(); }; - render () { + render() { return ( - <nav className="navbar navbar-global page-container" id="global-navigation"> - <div className="container"> - <GlobalNavBranding/> + <nav className="navbar navbar-global page-container" id="global-navigation"> + <div className="container"> + <GlobalNavBranding /> - <GlobalNavMenu {...this.props}/> + <GlobalNavMenu {...this.props} /> - <ul className="nav navbar-nav navbar-right"> - <GlobalNavUser {...this.props}/> - <GlobalNavSearch {...this.props}/> - <li> - <a onClick={this.openHelp} href="#"> - <i className="icon-help navbar-icon"/> - </a> - </li> - </ul> - </div> - </nav> + <ul className="nav navbar-nav navbar-right"> + <GlobalNavUser {...this.props} /> + <GlobalNavSearch {...this.props} /> + <li> + <a onClick={this.openHelp} href="#"> + <i className="icon-help navbar-icon" /> + </a> + </li> + </ul> + </div> + </nav> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js index a1f73443ea2..8e6dd891305 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.js @@ -29,23 +29,22 @@ class GlobalNavBranding extends React.Component { customLogoWidth: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]) }; - renderLogo () { + renderLogo() { const url = this.props.customLogoUrl || `${window.baseUrl}/images/logo.svg`; const width = this.props.customLogoWidth || 100; const height = 30; const title = translate('layout.sonar.slogan'); - return ( - <img src={url} width={width} height={height} alt={title} title={title}/> - ); + return <img src={url} width={width} height={height} alt={title} title={title} />; } - render () { + render() { const homeController = this.props.currentUser.isLoggedIn ? '/projects' : '/about'; - const homeLinkClassName = 'navbar-brand' + (this.props.customLogoUrl ? ' navbar-brand-custom' : ''); + const homeLinkClassName = 'navbar-brand' + + (this.props.customLogoUrl ? ' navbar-brand-custom' : ''); return ( - <div className="navbar-header"> - <Link to={homeController} className={homeLinkClassName}>{this.renderLogo()}</Link> - </div> + <div className="navbar-header"> + <Link to={homeController} className={homeLinkClassName}>{this.renderLogo()}</Link> + </div> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js index 3693e493fcf..b1e556af9d0 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.js @@ -33,112 +33,114 @@ export default class GlobalNavMenu extends React.Component { globalPages: [] }; - activeLink (url) { + activeLink(url) { return window.location.pathname.indexOf(window.baseUrl + url) === 0 ? 'active' : null; } - renderProjects () { + renderProjects() { return ( - <li> - <Link to="/projects" activeClassName="active"> - {translate('projects.page')} - </Link> - </li> + <li> + <Link to="/projects" activeClassName="active"> + {translate('projects.page')} + </Link> + </li> ); } - renderIssuesLink () { - const query = this.props.currentUser.isLoggedIn ? '#resolved=false|assigned_to_me=true' : '#resolved=false'; + renderIssuesLink() { + const query = this.props.currentUser.isLoggedIn + ? '#resolved=false|assigned_to_me=true' + : '#resolved=false'; const url = '/issues' + query; return ( - <li> - <Link to={url} className={this.activeLink('/issues')}> - {translate('issues.page')} - </Link> - </li> + <li> + <Link to={url} className={this.activeLink('/issues')}> + {translate('issues.page')} + </Link> + </li> ); } - renderRulesLink () { + renderRulesLink() { return ( - <li> - <Link to="/coding_rules" className={this.activeLink('/coding_rules')}> - {translate('coding_rules.page')} - </Link> - </li> + <li> + <Link to="/coding_rules" className={this.activeLink('/coding_rules')}> + {translate('coding_rules.page')} + </Link> + </li> ); } - renderProfilesLink () { + renderProfilesLink() { return ( - <li> - <Link to="/profiles" activeClassName="active"> - {translate('quality_profiles.page')} - </Link> - </li> + <li> + <Link to="/profiles" activeClassName="active"> + {translate('quality_profiles.page')} + </Link> + </li> ); } - renderQualityGatesLink () { + renderQualityGatesLink() { return ( - <li> - <Link to="/quality_gates" activeClassName="active"> - {translate('quality_gates.page')} - </Link> - </li> + <li> + <Link to="/quality_gates" activeClassName="active"> + {translate('quality_gates.page')} + </Link> + </li> ); } - renderAdministrationLink () { + renderAdministrationLink() { if (!isUserAdmin(this.props.currentUser)) { return null; } return ( - <li> - <Link to="/settings" className="navbar-admin-link" activeClassName="active"> - {translate('layout.settings')} - </Link> - </li> + <li> + <Link to="/settings" className="navbar-admin-link" activeClassName="active"> + {translate('layout.settings')} + </Link> + </li> ); } renderGlobalPageLink = ({ key, name }) => { return ( - <li key={key}> - <Link to={`/extension/${key}`}>{name}</Link> - </li> + <li key={key}> + <Link to={`/extension/${key}`}>{name}</Link> + </li> ); }; - renderMore () { + renderMore() { const { globalPages } = this.props.appState; if (globalPages.length === 0) { return null; } return ( - <li className="dropdown"> - <a className="dropdown-toggle" id="global-navigation-more" data-toggle="dropdown" href="#"> - {translate('more')} - <span className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - {globalPages.map(this.renderGlobalPageLink)} - </ul> - </li> + <li className="dropdown"> + <a className="dropdown-toggle" id="global-navigation-more" data-toggle="dropdown" href="#"> + {translate('more')} + <span className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + {globalPages.map(this.renderGlobalPageLink)} + </ul> + </li> ); } - render () { + render() { return ( - <ul className="nav navbar-nav"> - {this.renderProjects()} - {this.renderIssuesLink()} - {this.renderRulesLink()} - {this.renderProfilesLink()} - {this.renderQualityGatesLink()} - {this.renderAdministrationLink()} - {this.renderMore()} - </ul> + <ul className="nav navbar-nav"> + {this.renderProjects()} + {this.renderIssuesLink()} + {this.renderRulesLink()} + {this.renderProfilesLink()} + {this.renderQualityGatesLink()} + {this.renderAdministrationLink()} + {this.renderMore()} + </ul> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavSearch.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavSearch.js index fdcb24c2881..2b5aa6ccf63 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavSearch.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavSearch.js @@ -23,7 +23,7 @@ import { connect } from 'react-redux'; import SearchView from './SearchView'; import { getCurrentUser } from '../../../../store/rootReducer'; -function contains (root, node) { +function contains(root, node) { while (node) { if (node === root) { return true; @@ -36,7 +36,7 @@ function contains (root, node) { class GlobalNavSearch extends React.Component { state = { open: false }; - componentDidMount () { + componentDidMount() { key('s', () => { const isModalOpen = document.querySelector('html').classList.contains('modal-open'); if (!isModalOpen) { @@ -46,7 +46,7 @@ class GlobalNavSearch extends React.Component { }); } - componentWillUnmount () { + componentWillUnmount() { this.closeSearch(); key.unbind('s'); } @@ -92,15 +92,18 @@ class GlobalNavSearch extends React.Component { } }; - render () { + render() { const dropdownClassName = 'dropdown' + (this.state.open ? ' open' : ''); return ( - <li ref="dropdown" className={dropdownClassName}> - <a className="navbar-search-dropdown" href="#" onClick={this.onClick}> - <i className="icon-search navbar-icon"/> <i className="icon-dropdown"/> - </a> - <div ref="container" className="dropdown-menu dropdown-menu-right global-navbar-search-dropdown"/> - </li> + <li ref="dropdown" className={dropdownClassName}> + <a className="navbar-search-dropdown" href="#" onClick={this.onClick}> + <i className="icon-search navbar-icon" /> <i className="icon-dropdown" /> + </a> + <div + ref="container" + className="dropdown-menu dropdown-menu-right global-navbar-search-dropdown" + /> + </li> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js index b8a5fe7c1df..57fda1a1492 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js @@ -49,35 +49,35 @@ class GlobalNavUser extends React.Component { this.props.router.push('/sessions/logout'); }; - renderAuthenticated () { + renderAuthenticated() { const { currentUser } = this.props; return ( - <li className="dropdown js-user-authenticated"> - <a className="dropdown-toggle" data-toggle="dropdown" href="#"> - <Avatar email={currentUser.email} size={20}/> - {currentUser.name} <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu dropdown-menu-right"> - <li> - <Link to="/account">{translate('my_account.page')}</Link> - </li> - <li> - <a onClick={this.handleLogout} href="#">{translate('layout.logout')}</a> - </li> - </ul> - </li> + <li className="dropdown js-user-authenticated"> + <a className="dropdown-toggle" data-toggle="dropdown" href="#"> + <Avatar email={currentUser.email} size={20} /> + {currentUser.name} <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu dropdown-menu-right"> + <li> + <Link to="/account">{translate('my_account.page')}</Link> + </li> + <li> + <a onClick={this.handleLogout} href="#">{translate('layout.logout')}</a> + </li> + </ul> + </li> ); } - renderAnonymous () { + renderAnonymous() { return ( - <li> - <a onClick={this.handleLogin} href="#">{translate('layout.login')}</a> - </li> + <li> + <a onClick={this.handleLogin} href="#">{translate('layout.login')}</a> + </li> ); } - render () { + render() { return this.props.currentUser.isLoggedIn ? this.renderAuthenticated() : this.renderAnonymous(); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js index cf711c889e8..e98a0397a3a 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js @@ -31,7 +31,10 @@ import { translate } from '../../../../helpers/l10n'; import { isUserAdmin } from '../../../../helpers/users'; import { getFavorites } from '../../../../api/favorites'; import { getSuggestions } from '../../../../api/components'; -import { getOrganization, areThereCustomOrganizations } from '../../../../store/organizations/utils'; +import { + getOrganization, + areThereCustomOrganizations +} from '../../../../store/organizations/utils'; type Finding = { name: string, @@ -45,19 +48,19 @@ const SearchItemView = Marionette.ItemView.extend({ tagName: 'li', template: SearchItemTemplate, - select () { + select() { this.$el.addClass('active'); }, - deselect () { + deselect() { this.$el.removeClass('active'); }, - submit () { + submit() { this.$('a')[0].click(); }, - onRender () { + onRender() { this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', html: true, @@ -66,11 +69,11 @@ const SearchItemView = Marionette.ItemView.extend({ }); }, - onDestroy () { + onDestroy() { this.$('[data-toggle="tooltip"]').tooltip('destroy'); }, - serializeData () { + serializeData() { return { ...Marionette.ItemView.prototype.serializeData.apply(this, arguments), index: this.options.index @@ -105,7 +108,7 @@ export default Marionette.LayoutView.extend({ 'keyup .js-search-input': 'onKeyUp' }, - initialize () { + initialize() { this.results = new Backbone.Collection(); this.favorite = []; if (this.model.get('currentUser').isLoggedIn) { @@ -121,15 +124,18 @@ export default Marionette.LayoutView.extend({ this._bufferedValue = ''; }, - onRender () { + onRender() { const that = this; this.resultsRegion.show(this.resultsView); - setTimeout(() => { - that.$('.js-search-input').focus(); - }, 0); + setTimeout( + () => { + that.$('.js-search-input').focus(); + }, + 0 + ); }, - onKeyDown (e) { + onKeyDown(e) { if (e.keyCode === 38) { this.resultsView.selectPrev(); return false; @@ -149,7 +155,7 @@ export default Marionette.LayoutView.extend({ } }, - onKeyUp () { + onKeyUp() { const value = this.$('.js-search-input').val(); if (value === this._bufferedValue) { return; @@ -158,18 +164,21 @@ export default Marionette.LayoutView.extend({ this.searchRequest = this.debouncedSearch(value); }, - onSubmit () { + onSubmit() { return false; }, - fetchFavorite (): Promise<*> { + fetchFavorite(): Promise<*> { const customOrganizations = areThereCustomOrganizations(); return getFavorites().then(r => { this.favorite = r.favorites.map(f => { const showOrganization = customOrganizations && f.organization != null; const organization = showOrganization ? getOrganization(f.organization) : null; return { - url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(f.key) + window.dashboardParameters(true), + url: window.baseUrl + + '/dashboard/index?id=' + + encodeURIComponent(f.key) + + window.dashboardParameters(true), name: f.name, icon: 'favorite', organization @@ -179,12 +188,14 @@ export default Marionette.LayoutView.extend({ }); }, - resetResultsToDefault () { + resetResultsToDefault() { const recentHistory = RecentHistory.get(); const customOrganizations = areThereCustomOrganizations(); const history = recentHistory.map((historyItem, index) => { - const url = window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(historyItem.key) + - window.dashboardParameters(true); + const url = window.baseUrl + + '/dashboard/index?id=' + + encodeURIComponent(historyItem.key) + + window.dashboardParameters(true); const showOrganization = customOrganizations && historyItem.organization != null; // $FlowFixMe flow doesn't check the above condition on `historyItem.organization != null` const organization = showOrganization ? getOrganization(historyItem.organization) : null; @@ -202,7 +213,7 @@ export default Marionette.LayoutView.extend({ this.results.reset([].concat(history, favorite)); }, - search (q) { + search(q) { if (q.length < 2) { this.resetResultsToDefault(); return; @@ -219,8 +230,9 @@ export default Marionette.LayoutView.extend({ const collection = []; r.results.forEach(({ items, q }) => { items.forEach((item, index) => { - const showOrganization = customOrganizations && item.organization != null && - SHOW_ORGANIZATION_FOR_QUALIFIERS.includes(q); + const showOrganization = customOrganizations && + item.organization != null && + SHOW_ORGANIZATION_FOR_QUALIFIERS.includes(q); const organization = showOrganization ? getOrganization(item.organization) : null; collection.push({ ...item, @@ -240,10 +252,13 @@ export default Marionette.LayoutView.extend({ }); }, - getNavigationFindings (q) { + getNavigationFindings(q) { const DEFAULT_ITEMS = [ { name: translate('issues.page'), url: window.baseUrl + '/issues/search' }, - { name: translate('layout.measures'), url: window.baseUrl + '/measures/search?qualifiers[]=TRK' }, + { + name: translate('layout.measures'), + url: window.baseUrl + '/measures/search?qualifiers[]=TRK' + }, { name: translate('coding_rules.page'), url: window.baseUrl + '/coding_rules' }, { name: translate('quality_profiles.page'), url: window.baseUrl + '/profiles' }, { name: translate('quality_gates.page'), url: window.baseUrl + '/quality_gates' } @@ -261,10 +276,13 @@ export default Marionette.LayoutView.extend({ return findings.slice(0, 6); }, - getGlobalDashboardFindings (q) { + getGlobalDashboardFindings(q) { const dashboards = this.model.get('globalDashboards') || []; const items = dashboards.map(d => { - return { name: d.name, url: window.baseUrl + '/dashboard/index?did=' + encodeURIComponent(d.key) }; + return { + name: d.name, + url: window.baseUrl + '/dashboard/index?did=' + encodeURIComponent(d.key) + }; }); const findings = items.filter(f => { return f.name.match(new RegExp(q, 'i')); @@ -275,7 +293,7 @@ export default Marionette.LayoutView.extend({ return findings.slice(0, 6); }, - getFavoriteFindings (q) { + getFavoriteFindings(q) { const findings = this.favorite.filter(f => { return f.name.match(new RegExp(q, 'i')); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js b/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js index 6c9f8cbc4b1..893e4930ad6 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/ShortcutsHelpView.js @@ -24,4 +24,3 @@ export default ModalView.extend({ className: 'modal modal-large', template: ShortcutsHelpTemplate }); - diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.js b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.js index 43e5359b962..8631913e07f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavMenu-test.js @@ -29,6 +29,6 @@ it('should work with extensions', () => { isLoggedIn: false, permissions: { global: [] } }; - const wrapper = shallow(<GlobalNavMenu appState={appState} currentUser={currentUser}/>); + const wrapper = shallow(<GlobalNavMenu appState={appState} currentUser={currentUser} />); expect(wrapper).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js index 38ee2cef480..b82a5e22a60 100644 --- a/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js +++ b/server/sonar-web/src/main/js/app/components/nav/settings/SettingsNav.js @@ -29,35 +29,35 @@ class SettingsNav extends React.Component { extensions: [] }; - isSomethingActive (urls) { + isSomethingActive(urls) { const path = window.location.pathname; return urls.some(url => path.indexOf(window.baseUrl + url) === 0); } - isSecurityActive () { + isSecurityActive() { const urls = ['/users', '/groups', '/roles/global', '/permission_templates']; return this.isSomethingActive(urls); } - isProjectsActive () { + isProjectsActive() { const urls = ['/projects_admin', '/background_tasks']; return this.isSomethingActive(urls); } - isSystemActive () { + isSystemActive() { const urls = ['/updatecenter', '/system']; return this.isSomethingActive(urls); } renderExtension = ({ key, name }) => { return ( - <li key={key}> - <Link to={`/admin/extension/${key}`} activeClassName="active">{name}</Link> - </li> + <li key={key}> + <Link to={`/admin/extension/${key}`} activeClassName="active">{name}</Link> + </li> ); }; - render () { + render() { const isSecurity = this.isSecurityActive(); const isProjects = this.isProjectsActive(); const isSystem = this.isSystemActive(); @@ -70,127 +70,128 @@ class SettingsNav extends React.Component { }); return ( - <nav className="navbar navbar-context page-container" id="context-navigation"> - <div className="navbar-context-inner"> - <div className="container"> - <ul className="nav navbar-nav nav-crumbs"> - <li> - <IndexLink to="/settings"> - {translate('layout.settings')} - </IndexLink> - </li> - </ul> - - <ul className="nav navbar-nav nav-tabs"> - <li className={configurationClassNames}> - <a className="dropdown-toggle" data-toggle="dropdown" id="settings-navigation-configuration" href="#"> - {translate('sidebar.project_settings')} <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> + <nav className="navbar navbar-context page-container" id="context-navigation"> + <div className="navbar-context-inner"> + <div className="container"> + <ul className="nav navbar-nav nav-crumbs"> + <li> + <IndexLink to="/settings"> + {translate('layout.settings')} + </IndexLink> + </li> + </ul> + + <ul className="nav navbar-nav nav-tabs"> + <li className={configurationClassNames}> + <a + className="dropdown-toggle" + data-toggle="dropdown" + id="settings-navigation-configuration" + href="#" + > + {translate('sidebar.project_settings')} <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + <li> + <IndexLink to="/settings" activeClassName="active"> + {translate('settings.page')} + </IndexLink> + </li> + <li> + <IndexLink to="/settings/licenses" activeClassName="active"> + {translate('property.category.licenses')} + </IndexLink> + </li> + <li> + <IndexLink to="/settings/encryption" activeClassName="active"> + {translate('property.category.security.encryption')} + </IndexLink> + </li> + <li> + <IndexLink to="/settings/server_id" activeClassName="active"> + {translate('property.category.server_id')} + </IndexLink> + </li> + <li> + <IndexLink to="/metrics" activeClassName="active"> + Custom Metrics + </IndexLink> + </li> + {this.props.extensions.map(this.renderExtension)} + </ul> + </li> + + <li className={securityClassName}> + <a className="dropdown-toggle" data-toggle="dropdown" href="#"> + {translate('sidebar.security')} <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + <li> + <IndexLink to="/users" activeClassName="active"> + {translate('users.page')} + </IndexLink> + </li> + {!this.props.customOrganizations && <li> - <IndexLink to="/settings" activeClassName="active"> - {translate('settings.page')} + <IndexLink to="/groups" activeClassName="active"> + {translate('user_groups.page')} </IndexLink> - </li> + </li>} + {!this.props.customOrganizations && <li> - <IndexLink to="/settings/licenses" activeClassName="active"> - {translate('property.category.licenses')} + <IndexLink to="/roles/global" activeClassName="active"> + {translate('global_permissions.page')} </IndexLink> - </li> + </li>} + {!this.props.customOrganizations && <li> - <IndexLink to="/settings/encryption" activeClassName="active"> - {translate('property.category.security.encryption')} + <IndexLink to="/permission_templates" activeClassName="active"> + {translate('permission_templates')} </IndexLink> - </li> + </li>} + </ul> + </li> + + <li className={projectsClassName}> + <a className="dropdown-toggle" data-toggle="dropdown" href="#"> + {translate('sidebar.projects')} <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + {!this.props.customOrganizations && <li> - <IndexLink to="/settings/server_id" activeClassName="active"> - {translate('property.category.server_id')} + <IndexLink to="/projects_admin" activeClassName="active"> + Management </IndexLink> - </li> - <li> - <IndexLink to="/metrics" activeClassName="active"> - Custom Metrics - </IndexLink> - </li> - {this.props.extensions.map(this.renderExtension)} - </ul> - </li> - - <li className={securityClassName}> - <a className="dropdown-toggle" data-toggle="dropdown" href="#"> - {translate('sidebar.security')} <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - <li> - <IndexLink to="/users" activeClassName="active"> - {translate('users.page')} - </IndexLink> - </li> - {!this.props.customOrganizations && ( - <li> - <IndexLink to="/groups" activeClassName="active"> - {translate('user_groups.page')} - </IndexLink> - </li> - )} - {!this.props.customOrganizations && ( - <li> - <IndexLink to="/roles/global" activeClassName="active"> - {translate('global_permissions.page')} - </IndexLink> - </li> - )} - {!this.props.customOrganizations && ( - <li> - <IndexLink to="/permission_templates" activeClassName="active"> - {translate('permission_templates')} - </IndexLink> - </li> - )} - </ul> - </li> - - <li className={projectsClassName}> - <a className="dropdown-toggle" data-toggle="dropdown" href="#"> - {translate('sidebar.projects')} <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - {!this.props.customOrganizations && ( - <li> - <IndexLink to="/projects_admin" activeClassName="active"> - Management - </IndexLink> - </li> - )} - <li> - <IndexLink to="/background_tasks" activeClassName="active"> - {translate('background_tasks.page')} - </IndexLink> - </li> - </ul> - </li> - - <li className={systemClassName}> - <a className="dropdown-toggle" data-toggle="dropdown" href="#"> - {translate('sidebar.system')} <i className="icon-dropdown"/> - </a> - <ul className="dropdown-menu"> - <li> - <IndexLink to="/updatecenter" activeClassName="active"> - {translate('update_center.page')} - </IndexLink> - </li> - <li> - <IndexLink to="/system" activeClassName="active"> - {translate('system_info.page')} - </IndexLink> - </li> - </ul> - </li> - </ul> - </div> + </li>} + <li> + <IndexLink to="/background_tasks" activeClassName="active"> + {translate('background_tasks.page')} + </IndexLink> + </li> + </ul> + </li> + + <li className={systemClassName}> + <a className="dropdown-toggle" data-toggle="dropdown" href="#"> + {translate('sidebar.system')} <i className="icon-dropdown" /> + </a> + <ul className="dropdown-menu"> + <li> + <IndexLink to="/updatecenter" activeClassName="active"> + {translate('update_center.page')} + </IndexLink> + </li> + <li> + <IndexLink to="/system" activeClassName="active"> + {translate('system_info.page')} + </IndexLink> + </li> + </ul> + </li> + </ul> </div> - </nav> + </div> + </nav> ); } } diff --git a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/SettingsNav-test.js b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/SettingsNav-test.js index 2477ccb58a4..48f8539f415 100644 --- a/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/SettingsNav-test.js +++ b/server/sonar-web/src/main/js/app/components/nav/settings/__tests__/SettingsNav-test.js @@ -23,6 +23,6 @@ import { UnconnectedSettingsNav } from '../SettingsNav'; it('should work with extensions', () => { const extensions = [{ key: 'foo', name: 'Foo' }]; - const wrapper = shallow(<UnconnectedSettingsNav extensions={extensions}/>); + const wrapper = shallow(<UnconnectedSettingsNav extensions={extensions} />); expect(wrapper).toMatchSnapshot(); }); |