]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9756 enable settings for long-living branches (#2438)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Mon, 28 Aug 2017 12:32:09 +0000 (14:32 +0200)
committerJanos Gyerik <janos.gyerik@sonarsource.com>
Tue, 12 Sep 2017 09:34:54 +0000 (11:34 +0200)
12 files changed:
server/sonar-web/src/main/js/api/settings.ts
server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavMenu-test.tsx
server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap
server/sonar-web/src/main/js/apps/settings/components/App.js
server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js
server/sonar-web/src/main/js/apps/settings/components/Definition.js
server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js
server/sonar-web/src/main/js/apps/settings/components/PageHeader.js
server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js
server/sonar-web/src/main/js/apps/settings/store/actions.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index fb579b166f89bb5a820da5c8c94a43ce0d9f16bc..ecadfadc87f8bb2414b2464b034244aaec1eccdd 100644 (file)
@@ -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<any> {
-  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<any> {
+  return getJSON('/api/settings/list_definitions', { branch, component }).then(r => r.definitions);
 }
 
-export function getValues(keys: string, componentKey: string): Promise<any> {
-  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<any> {
+  return getJSON('/api/settings/values', { keys, component, branch }).then(r => r.settings);
 }
 
-export function setSettingValue(definition: any, value: any, componentKey: string): Promise<void> {
+export function setSettingValue(
+  definition: any,
+  value: any,
+  component?: string,
+  branch?: string
+): Promise<void> {
   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<void> {
-  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<void> {
+  return post('/api/settings/reset', { keys: key, component, branch });
 }
 
 export function sendTestEmail(to: string, subject: string, message: string): Promise<void> {
index 3c1a4f512b790e9016f5954c368ab7a122fba44a..c7ed8058de9aa9a26bbc8218751e7d895201f1b7 100644 (file)
@@ -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<Props> {
   }
 
   renderAdministration() {
-    if (!this.props.branch.isMain) {
+    if (isShortLivingBranch(this.props.branch)) {
       return null;
     }
 
@@ -201,19 +205,21 @@ export default class ComponentNavMenu extends React.PureComponent<Props> {
   }
 
   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<Props> {
     return (
       <li key="settings">
         <Link
-          to={{ pathname: '/project/settings', query: { id: this.props.component.key } }}
+          to={{
+            pathname: '/project/settings',
+            query: { branch: getBranchName(this.props.branch), id: this.props.component.key }
+          }}
           activeClassName="active">
           {translate('project_settings.page')}
         </Link>
index c69eda2ef7a460a0934e1e6cc284d073d86f3db7..0c50f2de673a58114bc49ed14aef73c510fa0632 100644 (file)
@@ -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;
index f406307cd81c681c49236a60a27f66f2fd841b48..a331e992eb68543cc68f0c961e8a1b10aecfa33b 100644 (file)
@@ -93,6 +93,44 @@ exports[`should work for long-living branches 1`] = `
       project_activity.page
     </Link>
   </li>
+  <li
+    className="dropdown"
+  >
+    <a
+      className="dropdown-toggle is-admin"
+      data-toggle="dropdown"
+      href="#"
+      id="component-navigation-admin"
+    >
+      layout.settings
+       
+      <i
+        className="icon-dropdown"
+      />
+    </a>
+    <ul
+      className="dropdown-menu"
+    >
+      <li>
+        <Link
+          activeClassName="active"
+          onlyActiveOnIndex={false}
+          style={Object {}}
+          to={
+            Object {
+              "pathname": "/project/settings",
+              "query": Object {
+                "branch": "release",
+                "id": "foo",
+              },
+            }
+          }
+        >
+          project_settings.page
+        </Link>
+      </li>
+    </ul>
+  </li>
 </NavBarTabs>
 `;
 
@@ -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",
               },
             }
index 704d742b4a2dd8fab8f6ba3a8bf899cd750c7361..793ca7370ebe458088900d7827b96b75304704ac 100644 (file)
@@ -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 (
       <div id="settings-page" className="page page-limited">
         <Helmet title={translate('settings.page')} />
 
-        <PageHeader component={this.props.component} />
+        <PageHeader branch={branchName} component={this.props.component} />
         <div className="side-tabs-layout settings-layout">
           <div className="side-tabs-side">
             <AllCategoriesList
+              branch={branchName}
               component={this.props.component}
               selectedCategory={selectedCategory}
               defaultCategory={this.props.defaultCategory}
             />
           </div>
           <div className="side-tabs-main">
-            <CategoryDefinitionsList component={this.props.component} category={selectedCategory} />
+            <CategoryDefinitionsList
+              branch={branchName}
+              component={this.props.component}
+              category={selectedCategory}
+            />
 
             {selectedCategory === 'exclusions' && <WildcardsHelp />}
           </div>
index 60365bb356297120e1fe55b07affeae6dc93fa83..b9f61bfc68cb25be8891769712de134e87db25da 100644 (file)
@@ -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();
index d064997d3621ffe50c65b129af1a271c7ee674cd..3ae60c1afcc4b276be12bd04bab3257660d94c4d 100644 (file)
@@ -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);
index 3df8d283c7de721335cec47eb536d0f8a90f9baa..2106bb5463988b12f5d841c301c80e5ff7edd87b 100644 (file)
@@ -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 {
       <ul className="settings-definitions-list">
         {this.props.settings.map(setting =>
           <li key={setting.definition.key}>
-            <Definition component={this.props.component} setting={setting} />
+            <Definition
+              branch={this.props.branch}
+              component={this.props.component}
+              setting={setting}
+            />
           </li>
         )}
       </ul>
index 394b607a715ee0eb6fd40daa66544c50bbf59036..4ae3b8fc8587a1f3b1a7c879b0a38ab90e8af29d 100644 (file)
@@ -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 (
index b8299136778d6f1cad5fda859df63a62f9e06c51..ca8443fbfc18159ad6881ae1ba74efd0d32c6fc2 100644 (file)
@@ -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 }}
               />}
             <DefinitionsList
-              settings={bySubCategory[subCategory.key]}
+              branch={this.props.branch}
               component={this.props.component}
+              settings={bySubCategory[subCategory.key]}
             />
             {this.renderEmailForm(subCategory.key)}
           </li>
index cbdd7eb63baf649e1ed78b052b1f26cf15aed885..25e75c2b3c3927a1e1d29ad86aecc7f20ac809e2 100644 (file)
@@ -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));
index 87353b720dd3de4d74881d38581f16d5d4609aa5..8917fc328fad49296d29c2f6c20c404c4a2427ad 100644 (file)
@@ -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