From f85b19f4aaefbb3e4a24ac1ae758da718f4f572b Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 28 Aug 2017 14:32:09 +0200 Subject: [PATCH] SONAR-9756 enable settings for long-living branches (#2438) --- server/sonar-web/src/main/js/api/settings.ts | 37 ++++++----------- .../nav/component/ComponentNavMenu.tsx | 41 +++++++++++-------- .../__tests__/ComponentNavMenu-test.tsx | 1 - .../ComponentNavMenu-test.tsx.snap | 40 ++++++++++++++++++ .../main/js/apps/settings/components/App.js | 21 +++++++--- .../settings/components/CategoriesList.js | 3 +- .../js/apps/settings/components/Definition.js | 5 ++- .../settings/components/DefinitionsList.js | 7 +++- .../js/apps/settings/components/PageHeader.js | 5 ++- .../components/SubCategoryDefinitionsList.js | 4 +- .../main/js/apps/settings/store/actions.js | 18 ++++---- .../resources/org/sonar/l10n/core.properties | 1 + 12 files changed, 122 insertions(+), 61 deletions(-) diff --git a/server/sonar-web/src/main/js/api/settings.ts b/server/sonar-web/src/main/js/api/settings.ts index fb579b166f8..ecadfadc87f 100644 --- a/server/sonar-web/src/main/js/api/settings.ts +++ b/server/sonar-web/src/main/js/api/settings.ts @@ -21,25 +21,22 @@ import { omitBy } from 'lodash'; import { getJSON, RequestData, post, postJSON } from '../helpers/request'; import { TYPE_PROPERTY_SET } from '../apps/settings/constants'; -export function getDefinitions(componentKey: string): Promise { - const data: RequestData = {}; - if (componentKey) { - data.component = componentKey; - } - return getJSON('/api/settings/list_definitions', data).then(r => r.definitions); +export function getDefinitions(component: string | null, branch?: string): Promise { + return getJSON('/api/settings/list_definitions', { branch, component }).then(r => r.definitions); } -export function getValues(keys: string, componentKey: string): Promise { - const data: RequestData = { keys }; - if (componentKey) { - data.component = componentKey; - } - return getJSON('/api/settings/values', data).then(r => r.settings); +export function getValues(keys: string, component?: string, branch?: string): Promise { + return getJSON('/api/settings/values', { keys, component, branch }).then(r => r.settings); } -export function setSettingValue(definition: any, value: any, componentKey: string): Promise { +export function setSettingValue( + definition: any, + value: any, + component?: string, + branch?: string +): Promise { const { key } = definition; - const data: RequestData = { key }; + const data: RequestData = { key, component, branch }; if (definition.multiValues) { data.values = value; @@ -51,19 +48,11 @@ export function setSettingValue(definition: any, value: any, componentKey: strin data.value = value; } - if (componentKey) { - data.component = componentKey; - } - return post('/api/settings/set', data); } -export function resetSettingValue(key: string, componentKey: string): Promise { - const data: RequestData = { keys: key }; - if (componentKey) { - data.component = componentKey; - } - return post('/api/settings/reset', data); +export function resetSettingValue(key: string, component?: string, branch?: string): Promise { + return post('/api/settings/reset', { keys: key, component, branch }); } export function sendTestEmail(to: string, subject: string, message: string): Promise { diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx index 3c1a4f512b7..c7ed8058de9 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx @@ -23,7 +23,11 @@ import * as classNames from 'classnames'; import * as PropTypes from 'prop-types'; import { Branch, Component, ComponentExtension, ComponentConfiguration } from '../../../types'; import NavBarTabs from '../../../../components/nav/NavBarTabs'; -import { isShortLivingBranch, getBranchName } from '../../../../helpers/branches'; +import { + isShortLivingBranch, + getBranchName, + isLongLivingBranch +} from '../../../../helpers/branches'; import { translate } from '../../../../helpers/l10n'; const SETTINGS_URLS = [ @@ -173,7 +177,7 @@ export default class ComponentNavMenu extends React.PureComponent { } renderAdministration() { - if (!this.props.branch.isMain) { + if (isShortLivingBranch(this.props.branch)) { return null; } @@ -201,19 +205,21 @@ export default class ComponentNavMenu extends React.PureComponent { } renderAdministrationLinks() { - return [ - this.renderSettingsLink(), - this.renderBranchesLink(), - this.renderProfilesLink(), - this.renderQualityGateLink(), - this.renderCustomMeasuresLink(), - this.renderLinksLink(), - this.renderPermissionsLink(), - this.renderBackgroundTasksLink(), - this.renderUpdateKeyLink(), - ...this.renderAdminExtensions(), - this.renderDeletionLink() - ]; + return isLongLivingBranch(this.props.branch) + ? [this.renderSettingsLink()] + : [ + this.renderSettingsLink(), + this.renderBranchesLink(), + this.renderProfilesLink(), + this.renderQualityGateLink(), + this.renderCustomMeasuresLink(), + this.renderLinksLink(), + this.renderPermissionsLink(), + this.renderBackgroundTasksLink(), + this.renderUpdateKeyLink(), + ...this.renderAdminExtensions(), + this.renderDeletionLink() + ]; } renderSettingsLink() { @@ -223,7 +229,10 @@ export default class ComponentNavMenu extends React.PureComponent { return (
  • {translate('project_settings.page')} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx index c69eda2ef7a..0c50f2de673 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx @@ -77,7 +77,6 @@ it('should work for short-living branches', () => { isMain: false, mergeBranch: 'master', name: 'feature', - status: { bugs: 0, codeSmells: 2, vulnerabilities: 3 }, type: BranchType.SHORT }; const component = { key: 'foo', qualifier: 'TRK' } as Component; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap index f406307cd81..a331e992eb6 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap @@ -93,6 +93,44 @@ exports[`should work for long-living branches 1`] = ` project_activity.page
  • +
  • + + layout.settings +   + + +
      +
    • + + project_settings.page + +
    • +
    +
  • `; @@ -258,6 +296,7 @@ exports[`should work with extensions 1`] = ` Object { "pathname": "/project/settings", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -479,6 +518,7 @@ exports[`should work with multiple extensions 1`] = ` Object { "pathname": "/project/settings", "query": Object { + "branch": undefined, "id": "foo", }, } diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js index 704d742b4a2..793ca7370eb 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/App.js +++ b/server/sonar-web/src/main/js/apps/settings/components/App.js @@ -24,14 +24,16 @@ import PageHeader from './PageHeader'; import CategoryDefinitionsList from './CategoryDefinitionsList'; import AllCategoriesList from './AllCategoriesList'; import WildcardsHelp from './WildcardsHelp'; +import { getBranchName } from '../../../helpers/branches'; import { translate } from '../../../helpers/l10n'; import '../styles.css'; /*:: type Props = { + branch?: {}, component?: { key: string }, defaultCategory: ?string, - fetchSettings(componentKey: ?string): Promise<*>, + fetchSettings(componentKey: ?string, branch?: string): Promise<*>, location: { query: {} } }; */ @@ -52,13 +54,15 @@ export default class App extends React.PureComponent { html.classList.add('dashboard-page'); } const componentKey = this.props.component ? this.props.component.key : null; - this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true })); + const branch = this.props.branch && getBranchName(this.props.branch); + this.props.fetchSettings(componentKey, branch).then(() => this.setState({ loaded: true })); } componentDidUpdate(prevProps /*: Props*/) { if (prevProps.component !== this.props.component) { const componentKey = this.props.component ? this.props.component.key : null; - this.props.fetchSettings(componentKey); + const branch = this.props.branch && getBranchName(this.props.branch); + this.props.fetchSettings(componentKey, branch); } } @@ -77,21 +81,28 @@ export default class App extends React.PureComponent { const { query } = this.props.location; const selectedCategory = query.category || this.props.defaultCategory; + const branchName = this.props.branch && getBranchName(this.props.branch); + return (
    - +
    - + {selectedCategory === 'exclusions' && }
    diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js index 60365bb3562..b9f61bfc68c 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js @@ -32,6 +32,7 @@ type Category = { /*:: type Props = { + branch?: string, categories: Category[], component?: { key: string }, defaultCategory: string, @@ -43,7 +44,7 @@ export default class CategoriesList extends React.PureComponent { /*:: rops: Props; */ renderLink(category /*: Category */) { - const query = {}; + const query /*: Object */ = { branch: this.props.branch }; if (category.key !== this.props.defaultCategory) { query.category = category.key.toLowerCase(); diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.js b/server/sonar-web/src/main/js/apps/settings/components/Definition.js index d064997d362..3ae60c1afcc 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/Definition.js +++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.js @@ -47,6 +47,7 @@ class Definition extends React.PureComponent { /*:: timeout: number; */ static propTypes = { + branch: PropTypes.string, component: PropTypes.object, setting: PropTypes.object.isRequired, changedValue: PropTypes.any, @@ -90,7 +91,7 @@ class Definition extends React.PureComponent { const componentKey = this.props.component ? this.props.component.key : null; const { definition } = this.props.setting; return this.props - .resetValue(definition.key, componentKey) + .resetValue(definition.key, componentKey, this.props.branch) .then(() => { this.safeSetState({ success: true }); this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000); @@ -110,7 +111,7 @@ class Definition extends React.PureComponent { this.safeSetState({ success: false }); const componentKey = this.props.component ? this.props.component.key : null; this.props - .saveValue(this.props.setting.definition.key, componentKey) + .saveValue(this.props.setting.definition.key, componentKey, this.props.branch) .then(() => { this.safeSetState({ success: true }); this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000); diff --git a/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js index 3df8d283c7d..2106bb54639 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js @@ -24,6 +24,7 @@ import Definition from './Definition'; export default class DefinitionsList extends React.PureComponent { static propTypes = { + branch: PropTypes.object, component: PropTypes.object, settings: PropTypes.array.isRequired }; @@ -33,7 +34,11 @@ export default class DefinitionsList extends React.PureComponent {
      {this.props.settings.map(setting =>
    • - +
    • )}
    diff --git a/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js b/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js index 394b607a715..4ae3b8fc858 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js +++ b/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js @@ -24,6 +24,7 @@ import { translate } from '../../../helpers/l10n'; export default class PageHeader extends React.PureComponent { static propTypes = { + branch: PropTypes.string, component: PropTypes.object }; @@ -35,7 +36,9 @@ export default class PageHeader extends React.PureComponent { const description = this.props.component != null - ? translate('project_settings.page.description') + ? this.props.branch + ? translate('branch_settings.page.description') + : translate('project_settings.page.') : translate('settings.page.description'); return ( diff --git a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js index b8299136778..ca8443fbfc1 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js @@ -27,6 +27,7 @@ import { getSubCategoryName, getSubCategoryDescription } from '../utils'; export default class SubCategoryDefinitionsList extends React.PureComponent { static propTypes = { + branch: PropTypes.string, component: PropTypes.object, settings: PropTypes.array.isRequired }; @@ -63,8 +64,9 @@ export default class SubCategoryDefinitionsList extends React.PureComponent { dangerouslySetInnerHTML={{ __html: subCategory.description }} />} {this.renderEmailForm(subCategory.key)} diff --git a/server/sonar-web/src/main/js/apps/settings/store/actions.js b/server/sonar-web/src/main/js/apps/settings/store/actions.js index cbdd7eb63ba..25e75c2b3c3 100644 --- a/server/sonar-web/src/main/js/apps/settings/store/actions.js +++ b/server/sonar-web/src/main/js/apps/settings/store/actions.js @@ -34,13 +34,13 @@ import { isEmptyValue } from '../utils'; import { translate } from '../../../helpers/l10n'; import { getSettingsAppDefinition, getSettingsAppChangedValue } from '../../../store/rootReducer'; -export const fetchSettings = componentKey => dispatch => { - return getDefinitions(componentKey) +export const fetchSettings = (componentKey, branch) => dispatch => { + return getDefinitions(componentKey, branch) .then(definitions => { const withoutLicenses = definitions.filter(definition => definition.type !== 'LICENSE'); dispatch(receiveDefinitions(withoutLicenses)); const keys = withoutLicenses.map(definition => definition.key).join(); - return getValues(keys, componentKey); + return getValues(keys, componentKey, branch); }) .then(settings => { dispatch(receiveValues(settings, componentKey)); @@ -49,7 +49,7 @@ export const fetchSettings = componentKey => dispatch => { .catch(e => parseError(e).then(message => dispatch(addGlobalErrorMessage(message)))); }; -export const saveValue = (key, componentKey) => (dispatch, getState) => { +export const saveValue = (key, componentKey, branch) => (dispatch, getState) => { dispatch(startLoading(key)); const state = getState(); @@ -62,8 +62,8 @@ export const saveValue = (key, componentKey) => (dispatch, getState) => { return Promise.reject(); } - return setSettingValue(definition, value, componentKey) - .then(() => getValues(key, componentKey)) + return setSettingValue(definition, value, componentKey, branch) + .then(() => getValues(key, componentKey, branch)) .then(values => { dispatch(receiveValues(values, componentKey)); dispatch(cancelChange(key)); @@ -77,11 +77,11 @@ export const saveValue = (key, componentKey) => (dispatch, getState) => { }); }; -export const resetValue = (key, componentKey) => dispatch => { +export const resetValue = (key, componentKey, branch) => dispatch => { dispatch(startLoading(key)); - return resetSettingValue(key, componentKey) - .then(() => getValues(key, componentKey)) + return resetSettingValue(key, componentKey, branch) + .then(() => getValues(key, componentKey, branch)) .then(values => { if (values.length > 0) { dispatch(receiveValues(values, componentKey)); diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 87353b720dd..8917fc328fa 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -556,6 +556,7 @@ roles.page.description2=Grant and revoke project-level permissions. Permissions roles.page.description_portfolio=Grant and revoke portfolio-level permissions. Permissions can be granted to groups or individual users. project_settings.page=General Settings project_settings.page.description=Edit project settings. +branch_settings.page.description=Edit branch settings. project_links.page=Links project_links.page.description=Edit some links associated with this project. project_history.page=History -- 2.39.5