import React from 'react';
import { connect } from 'react-redux';
import Helmet from 'react-helmet';
-import { getSettingValue } from '../../store/rootReducer';
+import { getGlobalSettingValue } from '../../store/rootReducer';
function DefaultHelmetContainer({ children, sonarqubeDotCom }) {
return (
}
const mapStateToProps = state => ({
- sonarqubeDotCom: getSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
+ sonarqubeDotCom: getGlobalSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
});
export default connect(mapStateToProps)(DefaultHelmetContainer);
*/
// @flow
import { connect } from 'react-redux';
-import { getAppState, getSettingValue } from '../../store/rootReducer';
+import { getAppState, getGlobalSettingValue } from '../../store/rootReducer';
import GlobalFooter from './GlobalFooter';
const mapStateToProps = state => ({
sonarqubeVersion: getAppState(state).version,
productionDatabase: getAppState(state).productionDatabase,
- sonarqubeDotCom: getSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
+ sonarqubeDotCom: getGlobalSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
});
export default connect(mapStateToProps)(GlobalFooter);
import Tooltip from '../../../../components/controls/Tooltip';
import HelpIcon from '../../../../components/icons-components/HelpIcon';
import OnboardingModal from '../../../../apps/tutorials/onboarding/OnboardingModal';
-import { getCurrentUser, getAppState, getSettingValue } from '../../../../store/rootReducer';
+import { getCurrentUser, getAppState, getGlobalSettingValue } from '../../../../store/rootReducer';
import { translate } from '../../../../helpers/l10n';
import './GlobalNav.css';
}
const mapStateToProps = state => {
- const sonarCloudSetting = getSettingValue(state, 'sonar.lf.sonarqube.com.enabled');
+ const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.lf.sonarqube.com.enabled');
return {
currentUser: getCurrentUser(state),
import PropTypes from 'prop-types';
import { Link } from 'react-router';
import { connect } from 'react-redux';
-import { getSettingValue, getCurrentUser } from '../../../../store/rootReducer';
+import { getGlobalSettingValue, getCurrentUser } from '../../../../store/rootReducer';
import { translate } from '../../../../helpers/l10n';
class GlobalNavBranding extends React.PureComponent {
const mapStateToProps = state => ({
currentUser: getCurrentUser(state),
- customLogoUrl: (getSettingValue(state, 'sonar.lf.logoUrl') || {}).value,
- customLogoWidth: (getSettingValue(state, 'sonar.lf.logoWidthPx') || {}).value
+ customLogoUrl: (getGlobalSettingValue(state, 'sonar.lf.logoUrl') || {}).value,
+ customLogoWidth: (getGlobalSettingValue(state, 'sonar.lf.logoWidthPx') || {}).value
});
export default connect(mapStateToProps)(GlobalNavBranding);
import AboutScanners from './AboutScanners';
import { searchProjects } from '../../../api/components';
import { getFacet } from '../../../api/issues';
-import { getAppState, getCurrentUser, getSettingValue } from '../../../store/rootReducer';
+import { getAppState, getCurrentUser, getGlobalSettingValue } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
import { fetchAboutPageSettings } from '../actions';
import AboutAppForSonarQubeDotComLazyLoader from './AboutAppForSonarQubeDotComLazyLoader';
const mapStateToProps = state => ({
appState: getAppState(state),
currentUser: getCurrentUser(state),
- customText: getSettingValue(state, 'sonar.lf.aboutText'),
- sonarqubeDotCom: getSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
+ customText: getGlobalSettingValue(state, 'sonar.lf.aboutText'),
+ sonarqubeDotCom: getGlobalSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
});
const mapDispatchToProps = { fetchAboutPageSettings };
import OrganizationsList from './OrganizationsList';
import { translate } from '../../../helpers/l10n';
import { fetchIfAnyoneCanCreateOrganizations, fetchMyOrganizations } from './actions';
-import { getAppState, getMyOrganizations, getSettingValue } from '../../../store/rootReducer';
+import { getAppState, getMyOrganizations, getGlobalSettingValue } from '../../../store/rootReducer';
/*:: import type { Organization } from '../../../store/organizations/duck'; */
class UserOrganizations extends React.PureComponent {
}
const mapStateToProps = state => ({
- anyoneCanCreate: getSettingValue(state, 'sonar.organizations.anyoneCanCreate'),
+ anyoneCanCreate: getGlobalSettingValue(state, 'sonar.organizations.anyoneCanCreate'),
canAdmin: getAppState(state).canAdmin,
organizations: getMyOrganizations(state)
});
// @flow
import React from 'react';
import Helmet from 'react-helmet';
-import { connect } from 'react-redux';
import PageHeader from './PageHeader';
import CategoryDefinitionsList from './CategoryDefinitionsList';
import AllCategoriesList from './AllCategoriesList';
import WildcardsHelp from './WildcardsHelp';
-import { fetchSettings } from '../store/actions';
-import { getSettingsAppDefaultCategory } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
import '../styles.css';
/*::
type Props = {
- component: { key: string },
+ component?: { key: string },
defaultCategory: ?string,
fetchSettings(componentKey: ?string): Promise<*>,
location: { query: {} }
};
*/
-class App extends React.PureComponent {
+export default class App extends React.PureComponent {
/*:: props: Props; */
state /*: State */ = { loaded: false };
html.classList.add('dashboard-page');
}
const componentKey = this.props.component ? this.props.component.key : null;
- this.props.fetchSettings(componentKey).then(() => {
- this.setState({ loaded: true });
- });
+ this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true }));
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps /*: Props*/) {
if (prevProps.component !== this.props.component) {
const componentKey = this.props.component ? this.props.component.key : null;
this.props.fetchSettings(componentKey);
);
}
}
-
-const mapStateToProps = state => ({
- defaultCategory: getSettingsAppDefaultCategory(state)
-});
-
-export default connect(mapStateToProps, { fetchSettings })(App);
*/
import { connect } from 'react-redux';
import App from './App';
-import { getComponent } from '../../../store/rootReducer';
+import { fetchSettings } from '../store/actions';
+import { getComponent, getSettingsAppDefaultCategory } from '../../../store/rootReducer';
const mapStateToProps = (state, ownProps) => ({
component: ownProps.location.query.id
? getComponent(state, ownProps.location.query.id)
- : undefined
+ : undefined,
+ defaultCategory: getSettingsAppDefaultCategory(state)
});
-export default connect(mapStateToProps)(App);
+const mapdispatchToProps = { fetchSettings };
+
+export default connect(mapStateToProps, mapdispatchToProps)(App);
}
const mapStateToProps = (state, ownProps) => ({
- settings: getSettingsAppSettingsForCategory(state, ownProps.category)
+ settings: getSettingsAppSettingsForCategory(
+ state,
+ ownProps.category,
+ ownProps.component ? ownProps.component.key : null
+ )
});
export default connect(mapStateToProps)(CategoryDefinitionsList);
}
handleCancel() {
- this.props.cancelChange(this.props.setting.definition.key);
+ const componentKey = this.props.component ? this.props.component.key : null;
+ this.props.cancelChange(this.props.setting.definition.key, componentKey);
this.props.passValidation(this.props.setting.definition.key);
}
return getValues(keys, componentKey);
})
.then(settings => {
- dispatch(receiveValues(settings));
+ dispatch(receiveValues(settings, componentKey));
dispatch(closeAllGlobalMessages());
})
.catch(e => parseError(e).then(message => dispatch(addGlobalErrorMessage(message))));
return setSettingValue(definition, value, componentKey)
.then(() => getValues(key, componentKey))
.then(values => {
- dispatch(receiveValues(values));
+ dispatch(receiveValues(values, componentKey));
dispatch(cancelChange(key));
dispatch(passValidation(key));
dispatch(stopLoading(key));
.then(() => getValues(key, componentKey))
.then(values => {
if (values.length > 0) {
- dispatch(receiveValues(values));
+ dispatch(receiveValues(values, componentKey));
} else {
- dispatch(receiveValues([{ key }]));
+ dispatch(receiveValues([{ key }], componentKey));
}
dispatch(passValidation(key));
dispatch(stopLoading(key));
import settingsPage, * as fromSettingsPage from './settingsPage/reducer';
import licenses, * as fromLicenses from './licenses/reducer';
import globalMessages, * as fromGlobalMessages from '../../../store/globalMessages/duck';
-/*:: import type { State as GlobalMessagesState } from '../../../store/globalMessages/duck'; */
import encryptionPage from './encryptionPage/reducer';
+/*:: import type { State as GlobalMessagesState } from '../../../store/globalMessages/duck'; */
+/*:: import type { State as ValuesState } from './values/reducer'; */
/*::
type State = {
globalMessages: GlobalMessagesState,
licenses: {},
settingsPage: {},
- values: {}
+ values: ValuesState
};
*/
export const getDefaultCategory = (state /*: State */) =>
fromDefinitions.getDefaultCategory(state.definitions);
-export const getValue = (state /*: State */, key /*: string */) =>
- fromValues.getValue(state.values, key);
+export const getValue = (state /*: State */, key /*: string */, componentKey /*: ?string */) =>
+ fromValues.getValue(state.values, key, componentKey);
-export const getSettingsForCategory = (state /*: State */, category /*: string */) =>
+export const getSettingsForCategory = (
+ state /*: State */,
+ category /*: string */,
+ componentKey /*: ?string */
+) =>
fromDefinitions.getDefinitionsForCategory(state.definitions, category).map(definition => ({
- ...getValue(state, definition.key),
+ ...getValue(state, definition.key, componentKey),
definition
}));
* @param {Array} settings
* @returns {Object}
*/
-export const receiveValues = (settings /*: SettingValue[] */) => ({
+export const receiveValues = (settings /*: SettingValue[] */, componentKey /*: ?string */) => ({
type: RECEIVE_VALUES,
- settings
+ settings,
+ componentKey
});
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// @flow
+import { combineReducers } from 'redux';
import { keyBy } from 'lodash';
import { RECEIVE_VALUES } from './actions';
/*::
-type State = { [key: string]: {} };
+type SettingsState = { [key: string]: {} };
+type ComponentsState = { [key: string]: SettingsState };
+export type State = { components: ComponentsState, global: SettingsState };
*/
-const reducer = (state /*: State */ = {}, action /*: Object */) => {
+const componentsSettings = (state /*: ComponentsState */ = {}, action /*: Object */) => {
+ if (!action.componentKey) {
+ return state;
+ }
+
+ const key = action.componentKey;
+ if (action.type === RECEIVE_VALUES) {
+ const settingsByKey = keyBy(action.settings, 'key');
+ return { ...state, [key]: { ...(state[key] || {}), ...settingsByKey } };
+ }
+
+ return state;
+};
+
+const globalSettings = (state /*: SettingsState */ = {}, action /*: Object */) => {
+ if (action.componentKey) {
+ return state;
+ }
+
if (action.type === RECEIVE_VALUES) {
const settingsByKey = keyBy(action.settings, 'key');
return { ...state, ...settingsByKey };
return state;
};
-export default reducer;
+export default combineReducers({ components: componentsSettings, global: globalSettings });
-export const getValue = (state /*: State */, key /*: string */) => state[key];
+export const getValue = (state /*: State */, key /*: string */, componentKey /*: ?string */) => {
+ let settings = state.global;
+ if (componentKey) {
+ settings = state.components[componentKey];
+ }
+ return settings && settings[key];
+};
import {
getCurrentUser,
areThereCustomOrganizations,
- getSettingValue
+ getGlobalSettingValue
} from '../../../store/rootReducer';
const mapStateToProps = state => {
- const sonarCloudSetting = getSettingValue(state, 'sonar.lf.sonarqube.com.enabled');
+ const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.lf.sonarqube.com.enabled');
return {
currentUser: getCurrentUser(state),
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import init from '../init';
-import { getSettingValue } from '../../../store/rootReducer';
+import { getGlobalSettingValue } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
class UpdateCenterAppContainer extends React.PureComponent {
}
const mapStateToProps = state => ({
- updateCenterActive: (getSettingValue(state, 'sonar.updatecenter.activate') || {}).value
+ updateCenterActive: (getGlobalSettingValue(state, 'sonar.updatecenter.activate') || {}).value
});
export default connect(mapStateToProps)(UpdateCenterAppContainer);
import { connect } from 'react-redux';
import md5 from 'blueimp-md5';
import classNames from 'classnames';
-import { getSettingValue } from '../../store/rootReducer';
+import { getGlobalSettingValue } from '../../store/rootReducer';
function stringToColor(str) {
let hash = 0;
}
const mapStateToProps = state => ({
- enableGravatar: (getSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true',
- gravatarServerUrl: (getSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value
+ enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true',
+ gravatarServerUrl: (getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value
});
export default connect(mapStateToProps)(Avatar);
function getRatingGrid() {
// workaround cyclic dependencies
const getStore = require('../app/utils/getStore').default;
- const { getSettingValue } = require('../store/rootReducer');
+ const { getGlobalSettingValue } = require('../store/rootReducer');
const store = getStore();
- const settingValue = getSettingValue(store.getState(), 'sonar.technicalDebt.ratingGrid');
+ const settingValue = getGlobalSettingValue(store.getState(), 'sonar.technicalDebt.ratingGrid');
return settingValue ? settingValue.value : '';
}
export const getPermissionsAppError = state => fromPermissionsApp.getError(state.permissionsApp);
-export const getSettingValue = (state, key) => fromSettingsApp.getValue(state.settingsApp, key);
+export const getGlobalSettingValue = (state, key) =>
+ fromSettingsApp.getValue(state.settingsApp, key);
export const getSettingsAppDefinition = (state, key) =>
fromSettingsApp.getDefinition(state.settingsApp, key);
export const getSettingsAppDefaultCategory = state =>
fromSettingsApp.getDefaultCategory(state.settingsApp);
-export const getSettingsAppSettingsForCategory = (state, category) =>
- fromSettingsApp.getSettingsForCategory(state.settingsApp, category);
+export const getSettingsAppSettingsForCategory = (state, category, componentKey) =>
+ fromSettingsApp.getSettingsForCategory(state.settingsApp, category, componentKey);
export const getSettingsAppChangedValue = (state, key) =>
fromSettingsApp.getChangedValue(state.settingsApp, key);
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarScanner;
+import org.openqa.selenium.By;
import org.sonarqube.pageobjects.ProjectsManagementPage;
import org.sonarqube.tests.Category1Suite;
import java.io.UnsupportedEncodingException;
import org.sonarqube.ws.client.permission.CreateTemplateWsRequest;
import org.sonarqube.ws.client.permission.UsersWsRequest;
+import static com.codeborne.selenide.Selenide.$;
import static org.apache.commons.lang.time.DateUtils.addDays;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.getComponent;
.assertStringSettingValue("sonar.dbcleaner.daysBeforeDeletingClosedIssues", "1");
}
+ @Test
+ public void display_correct_global_setting () throws UnsupportedEncodingException {
+ scanSample(null, null);
+ SettingsPage page = nav.logIn().submitCredentials(adminUser).openSettings("sample")
+ .openCategory("Analysis Scope")
+ .assertSettingDisplayed("sonar.coverage.exclusions")
+ .setStringValue("sonar.coverage.exclusions", "foo")
+ .assertStringSettingValue("sonar.coverage.exclusions", "foo");
+
+ $(".global-navbar-menu ").$(By.linkText("Administration")).click();
+ page
+ .openCategory("Analysis Scope")
+ .assertSettingDisplayed("sonar.coverage.exclusions")
+ .assertStringSettingValue("sonar.coverage.exclusions", "");
+ }
+
@Test
public void display_module_settings() throws UnsupportedEncodingException {
orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample")));