@@ -18,6 +18,8 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { connect } from 'react-redux'; | |||
import { getGlobalSettingValue, Store } from '../../../store/rootReducer'; | |||
import { Facet, Query, ReferencedComponent, ReferencedLanguage, ReferencedRule } from '../utils'; | |||
import AssigneeFacet from './AssigneeFacet'; | |||
import AuthorFacet from './AuthorFacet'; | |||
@@ -51,9 +53,10 @@ export interface Props { | |||
referencedLanguages: T.Dict<ReferencedLanguage>; | |||
referencedRules: T.Dict<ReferencedRule>; | |||
referencedUsers: T.Dict<T.UserBase>; | |||
disableDeveloperAggregatedInfo: boolean; | |||
} | |||
export default class Sidebar extends React.PureComponent<Props> { | |||
export class Sidebar extends React.PureComponent<Props> { | |||
renderComponentFacets() { | |||
const { component, facets, loadingFacets, openFacets, query } = this.props; | |||
if (!component) { | |||
@@ -223,7 +226,7 @@ export default class Sidebar extends React.PureComponent<Props> { | |||
/> | |||
)} | |||
{this.renderComponentFacets()} | |||
{!this.props.myIssues && ( | |||
{!this.props.myIssues && !this.props.disableDeveloperAggregatedInfo && ( | |||
<AssigneeFacet | |||
assigned={query.assigned} | |||
assignees={query.assignees} | |||
@@ -238,7 +241,7 @@ export default class Sidebar extends React.PureComponent<Props> { | |||
stats={facets.assignees} | |||
/> | |||
)} | |||
{displayAuthorFacet && ( | |||
{displayAuthorFacet && !this.props.disableDeveloperAggregatedInfo && ( | |||
<AuthorFacet | |||
authors={query.authors} | |||
component={component} | |||
@@ -256,3 +259,15 @@ export default class Sidebar extends React.PureComponent<Props> { | |||
); | |||
} | |||
} | |||
export const mapStateToProps = (state: Store) => { | |||
const disableDeveloperAggregatedInfo = getGlobalSettingValue( | |||
state, | |||
'sonar.developerAggregatedInfo.disabled' | |||
); | |||
return { | |||
disableDeveloperAggregatedInfo: disableDeveloperAggregatedInfo?.value === true.toString() | |||
}; | |||
}; | |||
export default connect(mapStateToProps)(Sidebar); |
@@ -20,15 +20,61 @@ | |||
import { shallow, ShallowWrapper } from 'enzyme'; | |||
import { flatten } from 'lodash'; | |||
import * as React from 'react'; | |||
import { mockComponent } from '../../../../helpers/testMocks'; | |||
import { getGlobalSettingValue } from '../../../../store/rootReducer'; | |||
import { ComponentQualifier } from '../../../../types/component'; | |||
import { Query } from '../../utils'; | |||
import Sidebar, { Props } from '../Sidebar'; | |||
import { mapStateToProps, Sidebar } from '../Sidebar'; | |||
jest.mock('../../../../store/rootReducer', () => ({})); | |||
jest.mock('../../../../store/rootReducer', () => ({ getGlobalSettingValue: jest.fn() })); | |||
const renderSidebar = (props?: Partial<Props>) => { | |||
it('should render facets for global page', () => { | |||
expect(renderSidebar()).toMatchSnapshot(); | |||
}); | |||
it('should render facets for project', () => { | |||
expect(renderSidebar({ component: mockComponent() })).toMatchSnapshot(); | |||
}); | |||
it('should render facets for module', () => { | |||
expect( | |||
renderSidebar({ component: mockComponent({ qualifier: ComponentQualifier.SubProject }) }) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render facets for directory', () => { | |||
expect( | |||
renderSidebar({ component: mockComponent({ qualifier: ComponentQualifier.Directory }) }) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render facets for developer', () => { | |||
expect( | |||
renderSidebar({ component: mockComponent({ qualifier: ComponentQualifier.Developper }) }) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render facets when my issues are selected', () => { | |||
expect(renderSidebar({ myIssues: true })).toMatchSnapshot(); | |||
}); | |||
it('should not render developer nominative facets when asked not to', () => { | |||
expect(renderSidebar({ disableDeveloperAggregatedInfo: true })).toMatchSnapshot(); | |||
}); | |||
it('should init the component with the proper store value', () => { | |||
mapStateToProps({} as any); | |||
expect(getGlobalSettingValue).toHaveBeenCalledWith( | |||
expect.any(Object), | |||
'sonar.developerAggregatedInfo.disabled' | |||
); | |||
}); | |||
const renderSidebar = (props?: Partial<Sidebar['props']>) => { | |||
return flatten( | |||
mapChildren( | |||
shallow( | |||
shallow<Sidebar>( | |||
<Sidebar | |||
component={undefined} | |||
facets={{}} | |||
@@ -45,6 +91,7 @@ const renderSidebar = (props?: Partial<Props>) => { | |||
referencedLanguages={{}} | |||
referencedRules={{}} | |||
referencedUsers={{}} | |||
disableDeveloperAggregatedInfo={false} | |||
{...props} | |||
/> | |||
) | |||
@@ -54,40 +101,9 @@ const renderSidebar = (props?: Partial<Props>) => { | |||
function mapChildren(wrapper: ShallowWrapper) { | |||
return wrapper.children().map(node => { | |||
if (typeof node.type() === 'symbol') { | |||
return node.children().map(node => node.name()); | |||
return node.children().map(n => n.name()); | |||
} | |||
return node.name(); | |||
}); | |||
} | |||
}; | |||
const component = { | |||
breadcrumbs: [], | |||
name: 'foo', | |||
key: 'foo', | |||
organization: 'org' | |||
}; | |||
it('should render facets for global page', () => { | |||
expect(renderSidebar()).toMatchSnapshot(); | |||
}); | |||
it('should render facets for project', () => { | |||
expect(renderSidebar({ component: { ...component, qualifier: 'TRK' } })).toMatchSnapshot(); | |||
}); | |||
it('should render facets for module', () => { | |||
expect(renderSidebar({ component: { ...component, qualifier: 'BRC' } })).toMatchSnapshot(); | |||
}); | |||
it('should render facets for directory', () => { | |||
expect(renderSidebar({ component: { ...component, qualifier: 'DIR' } })).toMatchSnapshot(); | |||
}); | |||
it('should render facets for developer', () => { | |||
expect(renderSidebar({ component: { ...component, qualifier: 'DEV' } })).toMatchSnapshot(); | |||
}); | |||
it('should render facets when my issues are selected', () => { | |||
expect(renderSidebar({ myIssues: true })).toMatchSnapshot(); | |||
}); |
@@ -1,5 +1,20 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should not render developer nominative facets when asked not to 1`] = ` | |||
Array [ | |||
"TypeFacet", | |||
"SeverityFacet", | |||
"ResolutionFacet", | |||
"StatusFacet", | |||
"StandardFacet", | |||
"InjectIntl(CreationDateFacet)", | |||
"Connect(LanguageFacet)", | |||
"RuleFacet", | |||
"TagFacet", | |||
"ProjectFacet", | |||
] | |||
`; | |||
exports[`should render facets for developer 1`] = ` | |||
Array [ | |||
"TypeFacet", |
@@ -49,6 +49,7 @@ import org.sonar.server.ui.VersionFormatter; | |||
import org.sonar.server.ui.WebAnalyticsLoader; | |||
import org.sonar.server.user.UserSession; | |||
import static org.sonar.api.CoreProperties.DEVELOPER_AGGREGATED_INFO_DISABLED; | |||
import static org.sonar.api.CoreProperties.RATING_GRID; | |||
import static org.sonar.core.config.WebConstants.SONAR_LF_ENABLE_GRAVATAR; | |||
import static org.sonar.core.config.WebConstants.SONAR_LF_GRAVATAR_SERVER_URL; | |||
@@ -67,7 +68,8 @@ public class GlobalAction implements NavigationWsAction, Startable { | |||
SONAR_LF_LOGO_WIDTH_PX, | |||
SONAR_LF_ENABLE_GRAVATAR, | |||
SONAR_LF_GRAVATAR_SERVER_URL, | |||
RATING_GRID); | |||
RATING_GRID, | |||
DEVELOPER_AGGREGATED_INFO_DISABLED); | |||
private final Map<String, String> systemSettingValuesByKey; | |||
@@ -51,7 +51,6 @@ import org.sonar.updatecenter.common.Version; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.RETURNS_DEEP_STUBS; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
@@ -116,6 +115,7 @@ public class GlobalActionTest { | |||
settings.setProperty("sonar.lf.enableGravatar", true); | |||
settings.setProperty("sonar.updatecenter.activate", false); | |||
settings.setProperty("sonar.technicalDebt.ratingGrid", "0.05,0.1,0.2,0.5"); | |||
settings.setProperty("sonar.developerAggregatedInfo.disabled", false); | |||
// This setting should be ignored as it's not needed | |||
settings.setProperty("sonar.defaultGroup", "sonar-users"); | |||
init(); | |||
@@ -128,6 +128,7 @@ public class GlobalActionTest { | |||
" \"sonar.lf.enableGravatar\": \"true\"," + | |||
" \"sonar.updatecenter.activate\": \"false\"," + | |||
" \"sonar.technicalDebt.ratingGrid\": \"0.05,0.1,0.2,0.5\"" + | |||
" \"sonar.developerAggregatedInfo.disabled\": \"false\"" + | |||
" }" + | |||
"}"); | |||
} | |||
@@ -149,6 +150,18 @@ public class GlobalActionTest { | |||
"}"); | |||
} | |||
@Test | |||
public void return_developer_info_disabled_setting() { | |||
init(); | |||
settings.setProperty("sonar.developerAggregatedInfo.disabled", true); | |||
assertJson(call()).isSimilarTo("{" + | |||
" \"settings\": {" + | |||
" \"sonar.developerAggregatedInfo.disabled\": \"true\"" + | |||
" }" + | |||
"}"); | |||
} | |||
@Test | |||
public void return_deprecated_logo_settings() { | |||
init(); |
@@ -131,6 +131,16 @@ public class CorePropertyDefinitions { | |||
.build(), | |||
// ISSUES | |||
PropertyDefinition.builder(CoreProperties.DEVELOPER_AGGREGATED_INFO_DISABLED) | |||
.name("Disable developer aggregated information") | |||
.description("Don't show issue facets aggregating information per developer") | |||
.category(CoreProperties.CATEGORY_GENERAL) | |||
.subCategory(CoreProperties.SUBCATEGORY_ISSUES) | |||
.onQualifiers(Qualifiers.PROJECT) | |||
.type(BOOLEAN) | |||
.defaultValue(Boolean.toString(false)) | |||
.build(), | |||
PropertyDefinition.builder(CoreProperties.DEFAULT_ISSUE_ASSIGNEE) | |||
.name("Default Assignee") | |||
.description("New issues will be assigned to this user each time it is not possible to determine the user who is the author of the issue.") |
@@ -30,7 +30,7 @@ public class CorePropertyDefinitionsTest { | |||
@Test | |||
public void all() { | |||
List<PropertyDefinition> defs = CorePropertyDefinitions.all(); | |||
assertThat(defs).hasSize(51); | |||
assertThat(defs).hasSize(52); | |||
} | |||
@Test |
@@ -392,6 +392,11 @@ public interface CoreProperties { | |||
*/ | |||
String DEFAULT_ISSUE_ASSIGNEE = "sonar.issues.defaultAssigneeLogin"; | |||
/** | |||
* @since 8.5 | |||
*/ | |||
String DEVELOPER_AGGREGATED_INFO_DISABLED = "sonar.developerAggregatedInfo.disabled"; | |||
/** | |||
* @since 7.6 | |||
*/ |