aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2017-03-28 16:42:37 +0200
committerStas Vilchik <stas-vilchik@users.noreply.github.com>2017-04-03 10:38:52 +0200
commitadb4265900d35345f8d900dca47cc6c2f490cb21 (patch)
tree1a3e27f58ff84c51cccd3f36d6a13ce2eec26c24 /server/sonar-web
parent32a73efa05cb12056a93f08b9124e647213f1f02 (diff)
downloadsonarqube-adb4265900d35345f8d900dca47cc6c2f490cb21.tar.gz
sonarqube-adb4265900d35345f8d900dca47cc6c2f490cb21.zip
SONAR-9005 support rules for organizations
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutApp.js10
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js8
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js31
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutStandards.js26
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js16
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/init.js18
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js3
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/rule-description-view.js6
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js22
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js8
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/rule-parameters-view.js10
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js19
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rule.hbs2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rules.hbs2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-description.hbs6
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-issues.hbs4
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-meta.hbs4
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-profile.hbs4
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationRules.js (renamed from server/sonar-web/src/main/js/helpers/handlebars/profileUrl.js)12
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js5
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap27
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/routes.js5
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js5
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js1
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js5
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js62
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js19
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js26
-rw-r--r--server/sonar-web/src/main/js/components/issue/issue-view.js2
-rw-r--r--server/sonar-web/src/main/js/components/workspace/main.js3
-rw-r--r--server/sonar-web/src/main/js/components/workspace/templates/workspace-rule.hbs2
-rw-r--r--server/sonar-web/src/main/js/components/workspace/views/rule-view.js10
-rw-r--r--server/sonar-web/src/main/js/helpers/handlebars/rulePermalink.js22
-rw-r--r--server/sonar-web/src/main/js/helpers/urls.js12
40 files changed, 288 insertions, 156 deletions
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
index a0f80af5dca..d76e6e3b4ba 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js
@@ -33,7 +33,7 @@ import AboutStandards from './AboutStandards';
import AboutScanners from './AboutScanners';
import { searchProjects } from '../../../api/components';
import { getFacet } from '../../../api/issues';
-import { getCurrentUser, getSettingValue } from '../../../store/rootReducer';
+import { getAppState, getCurrentUser, getSettingValue } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
import { fetchAboutPageSettings } from '../actions';
import AboutAppForSonarQubeDotCom from './AboutAppForSonarQubeDotCom';
@@ -53,6 +53,10 @@ class AboutApp extends React.Component {
mounted: boolean;
props: {
+ appState: {
+ defaultOrganization: string,
+ organizationsEnabled: boolean
+ },
currentUser: { isLoggedIn: boolean },
customText?: string,
fetchAboutPageSettings: () => Promise<*>,
@@ -115,6 +119,7 @@ class AboutApp extends React.Component {
if (sonarqubeDotCom && sonarqubeDotCom.value === 'true') {
return (
<AboutAppForSonarQubeDotCom
+ appState={this.props.appState}
bugs={bugs}
codeSmells={codeSmells}
currentUser={this.props.currentUser}
@@ -180,7 +185,7 @@ class AboutApp extends React.Component {
<AboutQualityGates />
</div>
<div className="flex-column flex-column-half about-page-group-boxes">
- <AboutStandards />
+ <AboutStandards appState={this.props.appState} />
</div>
</div>
@@ -192,6 +197,7 @@ class AboutApp extends React.Component {
}
const mapStateToProps = state => ({
+ appState: getAppState(state),
currentUser: getCurrentUser(state),
customText: getSettingValue(state, 'sonar.lf.aboutText'),
sonarqubeDotCom: getSettingValue(state, 'sonar.lf.sonarqube.com.enabled')
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js b/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js
index 6d43c38a8f7..addce0a2496 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutAppForSonarQubeDotCom.js
@@ -34,6 +34,10 @@ import '../sonarqube-dot-com-styles.css';
export default class AboutAppForSonarQubeDotCom extends React.Component {
props: {
+ appState: {
+ defaultOrganization: string,
+ organizationsEnabled: boolean
+ },
bugs: number,
codeSmells: number,
currentUser: { isLoggedIn: boolean },
@@ -76,7 +80,7 @@ export default class AboutAppForSonarQubeDotCom extends React.Component {
</div>
</div>
- <AboutRulesForSonarQubeDotCom />
+ <AboutRulesForSonarQubeDotCom appState={this.props.appState} />
<div className="about-page-container">
{customText != null &&
@@ -102,7 +106,7 @@ export default class AboutAppForSonarQubeDotCom extends React.Component {
<AboutQualityGates />
</div>
<div className="flex-column flex-column-half about-page-group-boxes">
- <AboutStandards />
+ <AboutStandards appState={this.props.appState} />
</div>
</div>
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js b/server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js
index 140ab0444d0..59fef3421c9 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutRulesForSonarQubeDotCom.js
@@ -23,11 +23,20 @@ import { Link } from 'react-router';
import { getRulesUrl } from '../../../helpers/urls';
export default class AboutRulesForSonarQubeDotCom extends React.Component {
+ props: {
+ appState: {
+ defaultOrganization: string,
+ organizationsEnabled: boolean
+ }
+ };
+
render() {
+ const organization = this.props.appState.defaultOrganization;
+
return (
<div className="sqcom-about-rules">
<div className="about-page-container">
- <Link to={getRulesUrl()} className="sqcom-about-rules-link">
+ <Link to={getRulesUrl(null, organization)} className="sqcom-about-rules-link">
+3,000 rules
<span className="spacer-left">
<svg width="15" height="36" viewBox="0 0 15 36">
@@ -40,17 +49,27 @@ export default class AboutRulesForSonarQubeDotCom extends React.Component {
</svg>
</span>
</Link>
- <Link to={getRulesUrl({ languages: 'js' })} className="sqcom-about-rules-link">
+ <Link
+ to={getRulesUrl({ languages: 'js' }, organization)}
+ className="sqcom-about-rules-link">
JavaScript
</Link>
- <Link to={getRulesUrl({ languages: 'java' })} className="sqcom-about-rules-link">
+ <Link
+ to={getRulesUrl({ languages: 'java' }, organization)}
+ className="sqcom-about-rules-link">
Java
</Link>
- <Link to={getRulesUrl({ languages: 'c,cpp' })} className="sqcom-about-rules-link">
+ <Link
+ to={getRulesUrl({ languages: 'c,cpp' }, organization)}
+ className="sqcom-about-rules-link">
C/C++
</Link>
- <Link to={getRulesUrl({ languages: 'cs' })} className="sqcom-about-rules-link">C#</Link>
- <Link to={getRulesUrl()} className="button">And More</Link>
+ <Link
+ to={getRulesUrl({ languages: 'cs' }, organization)}
+ className="sqcom-about-rules-link">
+ C#
+ </Link>
+ <Link to={getRulesUrl(null, organization)} className="button">And More</Link>
</div>
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutStandards.js b/server/sonar-web/src/main/js/apps/about/components/AboutStandards.js
index 295fabe38df..a2991500f31 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutStandards.js
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutStandards.js
@@ -27,9 +27,21 @@ const link = 'https://redirect.sonarsource.com/doc/rules.html';
const owaspTags = 'owasp-a1,owasp-a2,owasp-a3,owasp-a4,owasp-a5,' +
'owasp-a6,owasp-a7,owasp-a8,owasp-a9,owasp-a10';
+const sans25Tags = 'sans-top25-porous,sans-top25-risky,sans-top25-insecure';
export default class AboutStandards extends React.Component {
+ props: {
+ appState: {
+ defaultOrganization: string,
+ organizationsEnabled: boolean
+ }
+ };
+
render() {
+ const organization = this.props.appState.organizationsEnabled
+ ? this.props.appState.defaultOrganization
+ : null;
+
return (
<div className="boxed-group">
<h2>{translate('about_page.standards')}</h2>
@@ -39,34 +51,34 @@ export default class AboutStandards extends React.Component {
<div className="spacer-top">
<ul className="list-inline">
<li>
- <Link to={getRulesUrl({ tags: 'misra' })} className="link-with-icon">
+ <Link to={getRulesUrl({ tags: 'misra' }, organization)} className="link-with-icon">
<i className="icon-tags" />
<span className="little-spacer-left">MISRA</span>
</Link>
</li>
<li>
- <Link to={getRulesUrl({ tags: 'cert' })} className="link-with-icon">
+ <Link to={getRulesUrl({ tags: 'cert' }, organization)} className="link-with-icon">
<i className="icon-tags" />
<span className="little-spacer-left">CERT</span>
</Link>
</li>
<li>
- <Link to={getRulesUrl({ tags: 'cwe' })} className="link-with-icon">
+ <Link to={getRulesUrl({ tags: 'cwe' }, organization)} className="link-with-icon">
<i className="icon-tags" />
<span className="little-spacer-left">CWE</span>
</Link>
</li>
<li>
- <Link to={getRulesUrl({ tags: owaspTags })} className="link-with-icon">
+ <Link
+ to={getRulesUrl({ tags: owaspTags }, organization)}
+ className="link-with-icon">
<i className="icon-tags" />
<span className="little-spacer-left">OWASP Top 10</span>
</Link>
</li>
<li>
<Link
- to={getRulesUrl({
- tags: 'sans-top25-porous,sans-top25-risky,sans-top25-insecure'
- })}
+ to={getRulesUrl({ tags: sans25Tags }, organization)}
className="link-with-icon">
<i className="icon-tags" />
<span className="little-spacer-left">SANS Top 25</span>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
index 91b561597b9..c7bb6c70ed3 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesAppContainer.js
@@ -17,16 +17,26 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+// @flow
import React from 'react';
import init from '../init';
-export default class CodingRulesAppContainer extends React.Component {
+export default class CodingRulesAppContainer extends React.PureComponent {
+ stop: ?() => void;
+ props: {
+ params: {
+ organizationKey?: string
+ }
+ };
+
componentDidMount() {
- this.stop = init(this.refs.container);
+ this.stop = init(this.refs.container, this.props.params.organizationKey);
}
componentWillUnmount() {
- this.stop();
+ if (this.stop) {
+ this.stop();
+ }
}
render() {
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/init.js b/server/sonar-web/src/main/js/apps/coding-rules/init.js
index f25d2ad0c10..1a92814b70c 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/init.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/init.js
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+// @flow
import $ from 'jquery';
import { sortBy } from 'lodash';
import Backbone from 'backbone';
@@ -34,10 +35,14 @@ import FiltersView from './filters-view';
const App = new Marionette.Application();
-App.on('start', function(el) {
- $.get(window.baseUrl + '/api/rules/app')
+App.on('start', function(options: { el: HTMLElement, organization: ?string }) {
+ const data = options.organization ? { organization: options.organization } : {};
+ $.get(window.baseUrl + '/api/rules/app', data)
.done(r => {
+ App.canCreateCustomRule = r.canCreateCustomRule;
+ App.canCustomizeRule = r.canCustomizeRule;
App.canWrite = r.canWrite;
+ App.organization = options.organization;
App.qualityProfiles = sortBy(r.qualityprofiles, ['name', 'lang']);
App.languages = { ...r.languages, none: 'None' };
App.qualityProfiles.forEach(profile => {
@@ -47,7 +52,7 @@ App.on('start', function(el) {
App.statuses = r.statuses;
})
.done(() => {
- this.layout = new Layout({ el });
+ this.layout = new Layout({ el: options.el });
this.layout.render();
$('#footer').addClass('search-navigator-footer');
@@ -81,7 +86,7 @@ App.on('start', function(el) {
});
this.layout.filtersRegion.show(this.filtersView);
- key.setScope('list');
+ window.key.setScope('list');
this.router = new Router({
app: this
});
@@ -89,10 +94,11 @@ App.on('start', function(el) {
});
});
-export default function(el) {
- App.start(el);
+export default function(el: HTMLElement, organization: ?string) {
+ App.start({ el, organization });
return () => {
+ // $FlowFixMe
Backbone.history.stop();
App.layout.destroy();
$('#footer').removeClass('search-navigator-footer');
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js
index 2fa5eb3f2f4..11ed2ef6b74 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule-details-view.js
@@ -171,7 +171,7 @@ export default Marionette.LayoutView.extend({
serializeData() {
const isCustom = this.model.has('templateKey');
- const isEditable = this.options.app.canWrite && isCustom;
+ const isEditable = this.options.app.canCustomizeRule && isCustom;
let qualityProfilesVisible = true;
if (this.model.get('isTemplate')) {
@@ -182,7 +182,6 @@ export default Marionette.LayoutView.extend({
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
isEditable,
qualityProfilesVisible,
- canWrite: this.options.app.canWrite,
allTags: union(this.model.get('sysTags'), this.model.get('tags'))
};
}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js
index 1a5ff0ccdfe..295590a3bcb 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rule-view.js
@@ -47,7 +47,7 @@ export default Marionette.ItemView.extend({
serializeData() {
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- canWrite: this.options.app.canWrite,
+ canDeleteCustomRule: this.options.app.canCreateCustomRule,
templateRule: this.options.templateRule,
permalink: window.baseUrl + '/coding_rules/#rule_key=' + encodeURIComponent(this.model.id)
};
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js
index e8f9c0752c1..d6ec8a461cd 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/custom-rules-view.js
@@ -56,7 +56,7 @@ export default Marionette.CompositeView.extend({
serializeData() {
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- canWrite: this.options.app.canWrite
+ canCreateCustomRule: this.options.app.canCreateCustomRule
};
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-description-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-description-view.js
index 62d516c543d..0e942ef4bfb 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-description-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-description-view.js
@@ -94,12 +94,10 @@ export default Marionette.ItemView.extend({
},
serializeData() {
- const isEditable = this.options.app.canWrite && this.model.get('isCustom');
-
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- isEditable,
- canWrite: this.options.app.canWrite
+ isCustom: this.model.get('isCustom'),
+ canCustomizeRule: this.options.app.canCustomizeRule
};
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js
index d13deae57e0..384270c2919 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-issues-view.js
@@ -20,6 +20,7 @@
import $ from 'jquery';
import Marionette from 'backbone.marionette';
import Template from '../templates/rule/coding-rules-rule-issues.hbs';
+import { getComponentIssuesUrl } from '../../../helpers/urls';
export default Marionette.ItemView.extend({
template: Template,
@@ -34,7 +35,6 @@ export default Marionette.ItemView.extend({
},
requestIssues() {
- const that = this;
const url = window.baseUrl + '/api/issues/search';
const options = {
rules: this.model.id,
@@ -42,6 +42,10 @@ export default Marionette.ItemView.extend({
ps: 1,
facets: 'projectUuids'
};
+ const { organization } = this.options.app;
+ if (organization) {
+ Object.assign(options, { organization });
+ }
return $.get(url, options).done(r => {
const projectsFacet = r.facets.find(facet => facet.property === 'projectUuids');
let projects = projectsFacet != null ? projectsFacet.values : [];
@@ -49,11 +53,16 @@ export default Marionette.ItemView.extend({
const projectBase = r.components.find(component => component.uuid === project.val);
return {
...project,
- name: projectBase != null ? projectBase.longName : ''
+ name: projectBase != null ? projectBase.longName : '',
+ issuesUrl: projectBase != null &&
+ getComponentIssuesUrl(projectBase.key, {
+ resolved: 'false',
+ rules: this.model.id
+ })
};
});
- that.projects = projects;
- that.total = r.total;
+ this.projects = projects;
+ this.total = r.total;
});
},
@@ -61,10 +70,7 @@ export default Marionette.ItemView.extend({
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
total: this.total,
- projects: this.projects,
- baseSearchUrl: window.baseUrl +
- '/issues/search#resolved=false|rules=' +
- encodeURIComponent(this.model.id)
+ projects: this.projects
};
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js
index ba8ed5311ba..0a0b22ade85 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-meta-view.js
@@ -106,11 +106,15 @@ export default Marionette.ItemView.extend(RuleFilterMixin).extend({
},
serializeData() {
+ const permalinkPath = this.options.app.organization
+ ? `/organizations/${this.options.app.organization}/rules`
+ : '/coding_rules';
+
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- canWrite: this.options.app.canWrite,
+ canCustomizeRule: this.options.app.canCustomizeRule,
allTags: union(this.model.get('sysTags'), this.model.get('tags')),
- permalink: window.baseUrl + '/coding_rules#rule_key=' + encodeURIComponent(this.model.id)
+ permalink: window.baseUrl + permalinkPath + '#rule_key=' + encodeURIComponent(this.model.id)
};
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-parameters-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-parameters-view.js
index 8923b74d374..209860ab4cd 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-parameters-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-parameters-view.js
@@ -30,15 +30,5 @@ export default Marionette.ItemView.extend({
onRender() {
const params = this.model.get('params');
this.$el.toggleClass('hidden', params == null || params.length === 0);
- },
-
- serializeData() {
- const isEditable = this.options.app.canWrite && this.model.get('isCustom');
-
- return {
- ...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
- isEditable,
- canWrite: this.options.app.canWrite
- };
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js
index eab8d1be804..8120484ae41 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js
+++ b/server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js
@@ -123,6 +123,9 @@ export default Marionette.ItemView.extend({
const myProfile = this.options.app.qualityProfiles.find(
p => p.key === this.model.get('qProfile')
);
+ if (!myProfile) {
+ return null;
+ }
const parentKey = myProfile.parentKey;
const parent = { ...this.options.app.qualityProfiles.find(p => p.key === parentKey) };
const parentActiveInfo = this.model.collection.findWhere({ qProfile: parentKey }) ||
@@ -147,14 +150,26 @@ export default Marionette.ItemView.extend({
});
},
+ getProfilePath(profileKey) {
+ const { organization } = this.options.app;
+ const encodedKey = encodeURIComponent(profileKey);
+ return organization
+ ? `${window.baseUrl}/organizations/${organization}/quality_profiles/show?key=${encodedKey}`
+ : `${window.baseUrl}/profiles/show?key=${encodedKey}`;
+ },
+
serializeData() {
+ const parent = this.getParent();
+
return {
...Marionette.ItemView.prototype.serializeData.apply(this, arguments),
+ parent,
canWrite: this.options.app.canWrite,
- parent: this.getParent(),
parameters: this.enhanceParameters(),
templateKey: this.options.rule.get('templateKey'),
- isTemplate: this.options.rule.get('isTemplate')
+ isTemplate: this.options.rule.get('isTemplate'),
+ profilePath: this.getProfilePath(this.model.get('key')),
+ parentProfilePath: parent && this.getProfilePath(parent.key)
};
}
});
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rule.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rule.hbs
index b5371ee37f3..eaff503fc17 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rule.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rule.hbs
@@ -17,7 +17,7 @@
&nbsp;
</td>
-{{#if canWrite}}
+{{#if canDeleteCustomRule}}
<td class="coding-rules-detail-list-actions">
<div class="button-group">
<button class="js-delete-custom-rule button-red">
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rules.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rules.hbs
index 36a79d1951a..bd3899109cf 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rules.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-custom-rules.hbs
@@ -3,7 +3,7 @@
<h3 class="coding-rules-detail-title">{{t 'coding_rules.custom_rules'}}</h3>
- {{#if canWrite}}
+ {{#if canCreateCustomRule}}
<div class="button-group coding-rules-detail-quality-profiles-activation">
<button class="js-create-custom-rule">{{t 'coding_rules.create'}}</button>
</div>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-description.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-description.hbs
index 3b86bc6d54e..d0ab5457eeb 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-description.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-description.hbs
@@ -1,19 +1,19 @@
<div class="coding-rules-detail-description rule-desc markdown">{{{htmlDesc}}}</div>
-{{#unless isEditable}}
+{{#unless isCustom}}
<div class="coding-rules-detail-description coding-rules-detail-description-extra">
<div id="coding-rules-detail-description-extra">
{{#if htmlNote}}
<div class="rule-desc spacer-bottom markdown">{{{htmlNote}}}</div>
{{/if}}
- {{#if canWrite}}
+ {{#if canCustomizeRule}}
<div class="button-group">
<button id="coding-rules-detail-extend-description">{{t 'coding_rules.extend_description'}}</button>
</div>
{{/if}}
</div>
- {{#if canWrite}}
+ {{#if canCustomizeRule}}
<div class="coding-rules-detail-extend-description-form hidden">
<table class="width100">
<tbody>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-issues.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-issues.hbs
index da9a5336d36..f6dc9fe7619 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-issues.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-issues.hbs
@@ -1,7 +1,7 @@
<div class="coding-rule-section-separator"></div>
<h3 class="coding-rules-detail-title">
- {{t 'coding_rules.issues'}} (<a class="js-rule-issues" href="{{baseSearchUrl}}">{{total}}</a>)
+ {{t 'coding_rules.issues'}} ({{total}})
</h3>
{{#notEmpty projects}}
@@ -13,7 +13,7 @@
<tr>
<td class="coding-rules-detail-list-name">{{name}}</td>
<td class="coding-rules-detail-list-parameters">
- <a href="{{../baseSearchUrl}}|projectUuids={{val}}" target="_blank">{{count}}</a>
+ <a href="{{issuesUrl}}" target="_blank">{{count}}</a>
</td>
</tr>
{{/each}}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-meta.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-meta.hbs
index fc38adfff0c..255f97fea08 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-meta.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-meta.hbs
@@ -34,14 +34,14 @@
</li>
{{/notEq}}
- <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canWrite}}coding-rules-detail-tags-change{{/if}}"
+ <li class="coding-rules-detail-property coding-rules-detail-tag-list {{#if canCustomizeRule}}coding-rules-detail-tags-change{{/if}}"
data-toggle="tooltip" data-placement="bottom" title="Rule tags">
<i class="icon-tags"></i>
<span>{{#if allTags}}{{join allTags ', '}}{{else}}{{t 'coding_rules.no_tags'}}{{/if}}</span>
{{#if canWrite}}<i class="icon-dropdown"></i>{{/if}}
</li>
- {{#if canWrite}}
+ {{#if canCustomizeRule}}
<li class="coding-rules-detail-property coding-rules-detail-tag-edit hidden">
{{#if sysTags}}<i class="icon-tags"></i>
<span>{{join sysTags ', '}}</span>{{/if}}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-profile.hbs b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-profile.hbs
index 929a1e6d454..12d1fe950d5 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-profile.hbs
+++ b/server/sonar-web/src/main/js/apps/coding-rules/templates/rule/coding-rules-rule-profile.hbs
@@ -1,5 +1,5 @@
<td class="coding-rules-detail-quality-profile-name">
- <a href="{{profileUrl key}}">
+ <a href="{{profilePath}}">
{{name}}
</a>
{{#if parent}}
@@ -10,7 +10,7 @@
{{#eq inherit 'INHERITED'}}
<i class="icon-inheritance" title="{{tp 'coding_rules.inherits' name parent.name}}"></i>
{{/eq}}
- <a class="link-base-color" href="{{profileUrl parent.key}}">
+ <a class="link-base-color" href="{{parentProfilePath}}">
{{parent.name}}
</a>
</div>
diff --git a/server/sonar-web/src/main/js/helpers/handlebars/profileUrl.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationRules.js
index dab5f850fc2..c70546464a2 100644
--- a/server/sonar-web/src/main/js/helpers/handlebars/profileUrl.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationRules.js
@@ -17,6 +17,12 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-module.exports = function(key) {
- return window.baseUrl + '/profiles/show?key=' + encodeURIComponent(key);
-};
+// @flow
+import React from 'react';
+import CodingRulesAppContainer from '../../coding-rules/components/CodingRulesAppContainer';
+
+export default class OrganizationRules extends React.PureComponent {
+ render() {
+ return <CodingRulesAppContainer {...this.props} />;
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
index fdf72a5009e..0675c1872d8 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.js
@@ -161,6 +161,11 @@ export default class OrganizationNavigation extends React.Component {
{translate('quality_profiles.page')}
</Link>
</li>
+ <li>
+ <Link to={`/organizations/${organization.key}/rules`} activeClassName="active">
+ {translate('coding_rules.page')}
+ </Link>
+ </li>
{organization.canAdmin && this.renderAdministration()}
</ul>
</div>
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
index 46358abc847..0d9b7f5706c 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.js.snap
@@ -53,6 +53,15 @@ exports[`test admin 1`] = `
quality_profiles.page
</Link>
</li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/rules">
+ coding_rules.page
+ </Link>
+ </li>
<li
className="">
<a
@@ -183,6 +192,15 @@ exports[`test regular user 1`] = `
quality_profiles.page
</Link>
</li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/rules">
+ coding_rules.page
+ </Link>
+ </li>
</ul>
</div>
</div>
@@ -244,6 +262,15 @@ exports[`test undeletable org 1`] = `
quality_profiles.page
</Link>
</li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/rules">
+ coding_rules.page
+ </Link>
+ </li>
<li
className="">
<a
diff --git a/server/sonar-web/src/main/js/apps/organizations/routes.js b/server/sonar-web/src/main/js/apps/organizations/routes.js
index 1b7f81eda3d..7f91a2f344d 100644
--- a/server/sonar-web/src/main/js/apps/organizations/routes.js
+++ b/server/sonar-web/src/main/js/apps/organizations/routes.js
@@ -20,6 +20,7 @@
import OrganizationPage from './components/OrganizationPage';
import OrganizationProjects from './components/OrganizationProjects';
import OrganizationFavoriteProjects from './components/OrganizationFavoriteProjects';
+import OrganizationRules from './components/OrganizationRules';
import OrganizationAdmin from './components/OrganizationAdmin';
import OrganizationEdit from './components/OrganizationEdit';
import OrganizationGroups from './components/OrganizationGroups';
@@ -56,6 +57,10 @@ const routes = [
component: OrganizationMembersContainer
},
{
+ path: 'rules',
+ component: OrganizationRules
+ },
+ {
path: 'quality_profiles',
childRoutes: qualityProfilesRoutes
},
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js
index 2e84e64d2a3..0996a1d7ce4 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.js
@@ -33,7 +33,8 @@ type Props = {
params?: {},
ruleKey: string,
ruleName: string
- }>
+ }>,
+ organization: ?string
};
export default class Changelog extends React.PureComponent {
@@ -74,7 +75,7 @@ export default class Changelog extends React.PureComponent {
</td>
<td style={{ lineHeight: '1.5' }}>
- <Link to={getRulesUrl({ rule_key: event.ruleKey })}>
+ <Link to={getRulesUrl({ rule_key: event.ruleKey }, this.props.organization)}>
{event.ruleName}
</Link>
</td>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js
index c7ea2d89572..a1fe68f50af 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js
@@ -170,7 +170,7 @@ export default class ChangelogContainer extends React.PureComponent {
{this.state.events != null &&
this.state.events.length > 0 &&
- <Changelog events={this.state.events} />}
+ <Changelog events={this.state.events} organization={this.props.organization} />}
{shouldDisplayFooter &&
<footer className="text-center spacer-top small">
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js
index cdc70a050ed..6428c060684 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js
@@ -122,6 +122,7 @@ export default class ComparisonContainer extends React.PureComponent {
inLeft={inLeft}
inRight={inRight}
modified={modified}
+ organization={this.props.organization}
/>}
</div>
);
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js
index c6acf738546..ad79758344a 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.js
@@ -32,7 +32,8 @@ type Props = {
right: { name: string },
inLeft: Array<*>,
inRight: Array<*>,
- modified: Array<*>
+ modified: Array<*>,
+ organization: ?string
};
export default class ComparisonResults extends React.PureComponent {
@@ -43,7 +44,7 @@ export default class ComparisonResults extends React.PureComponent {
<div>
<SeverityIcon severity={severity} />
{' '}
- <Link to={getRulesUrl({ rule_key: rule.key })}>
+ <Link to={getRulesUrl({ rule_key: rule.key }, this.props.organization)}>
{rule.name}
</Link>
</div>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js
index 1101c1560ce..d1398b7f90e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js
@@ -84,11 +84,13 @@ export default class ProfileActions extends React.PureComponent {
'/api/qualityprofiles/backup?profileKey=' +
encodeURIComponent(profile.key);
- // FIXME getRulesUrl
- const activateMoreUrl = getRulesUrl({
- qprofile: profile.key,
- activation: 'false'
- });
+ const activateMoreUrl = getRulesUrl(
+ {
+ qprofile: profile.key,
+ activation: 'false'
+ },
+ this.props.organization
+ );
return (
<ul className="dropdown-menu dropdown-menu-right">
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js
index 7a68617ab25..6b726e51e96 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.js
@@ -33,6 +33,7 @@ const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
type Props = {
canAdmin: boolean,
+ organization: ?string,
profile: Profile
};
@@ -133,10 +134,13 @@ export default class ProfileRules extends React.PureComponent {
}
renderActiveCount() {
- const rulesUrl = getRulesUrl({
- qprofile: this.props.profile.key,
- activation: 'true'
- });
+ const rulesUrl = getRulesUrl(
+ {
+ qprofile: this.props.profile.key,
+ activation: 'true'
+ },
+ this.props.organization
+ );
if (this.state.activatedTotal == null) {
return null;
@@ -152,10 +156,13 @@ export default class ProfileRules extends React.PureComponent {
}
renderActiveTotal() {
- const rulesUrl = getRulesUrl({
- qprofile: this.props.profile.key,
- activation: 'false'
- });
+ const rulesUrl = getRulesUrl(
+ {
+ qprofile: this.props.profile.key,
+ activation: 'false'
+ },
+ this.props.organization
+ );
if (this.state.total == null || this.state.activatedTotal == null) {
return null;
@@ -184,11 +191,14 @@ export default class ProfileRules extends React.PureComponent {
}
renderCountForType(type: string) {
- const rulesUrl = getRulesUrl({
- qprofile: this.props.profile.key,
- activation: 'true',
- types: type
- });
+ const rulesUrl = getRulesUrl(
+ {
+ qprofile: this.props.profile.key,
+ activation: 'true',
+ types: type
+ },
+ this.props.organization
+ );
const count = this.state.activatedByType && this.state.activatedByType[type]
? this.state.activatedByType[type].count
@@ -206,11 +216,14 @@ export default class ProfileRules extends React.PureComponent {
}
renderTotalForType(type: string) {
- const rulesUrl = getRulesUrl({
- qprofile: this.props.profile.key,
- activation: 'false',
- types: type
- });
+ const rulesUrl = getRulesUrl(
+ {
+ qprofile: this.props.profile.key,
+ activation: 'false',
+ types: type
+ },
+ this.props.organization
+ );
const count = this.state.activatedByType && this.state.activatedByType[type]
? this.state.activatedByType[type].count
@@ -242,7 +255,7 @@ export default class ProfileRules extends React.PureComponent {
return null;
}
- const url = getDeprecatedActiveRulesUrl({ qprofile: profile.key });
+ const url = getDeprecatedActiveRulesUrl({ qprofile: profile.key }, this.props.organization);
return (
<div className="quality-profile-rules-deprecated clearfix">
@@ -259,10 +272,13 @@ export default class ProfileRules extends React.PureComponent {
}
render() {
- const activateMoreUrl = getRulesUrl({
- qprofile: this.props.profile.key,
- activation: 'false'
- });
+ const activateMoreUrl = getRulesUrl(
+ {
+ qprofile: this.props.profile.key,
+ activation: 'false'
+ },
+ this.props.organization
+ );
return (
<div className="quality-profile-rules">
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js b/server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js
index 23995d62e19..eca194a8209 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/Evolution.js
@@ -39,7 +39,7 @@ export default class Evolution extends React.PureComponent {
<div className="quality-profiles-evolution">
<EvolutionDeprecated organization={organization} profiles={profiles} />
<EvolutionStagnant organization={organization} profiles={profiles} />
- <EvolutionRules />
+ <EvolutionRules organization={organization} />
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js
index ce8f4ddafbc..89d9d87beab 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js
@@ -35,8 +35,6 @@ export default class EvolutionDeprecated extends React.PureComponent {
props: Props;
render() {
- // FIXME getDeprecatedActiveRulesUrl
-
const profilesWithDeprecations = this.props.profiles.filter(
profile => profile.activeDeprecatedRuleCount > 0
);
@@ -73,7 +71,10 @@ export default class EvolutionDeprecated extends React.PureComponent {
{profile.languageName}
{', '}
<Link
- to={getDeprecatedActiveRulesUrl({ qprofile: profile.key })}
+ to={getDeprecatedActiveRulesUrl(
+ { qprofile: profile.key },
+ this.props.organization
+ )}
className="text-muted">
{translateWithParameters(
'quality_profile.x_rules',
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js
index 553e6bdf62c..123b9394b91 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.js
@@ -39,7 +39,9 @@ function parseRules(r) {
});
}
-type Props = {};
+type Props = {
+ organization: ?string
+};
export default class EvolutionRules extends React.PureComponent {
mounted: boolean;
@@ -75,15 +77,16 @@ export default class EvolutionRules extends React.PureComponent {
}
render() {
- // FIXME getRulesUrl
-
if (!this.state.latestRulesTotal) {
return null;
}
- const newRulesUrl = getRulesUrl({
- available_since: PERIOD_START_MOMENT.format('YYYY-MM-DD')
- });
+ const newRulesUrl = getRulesUrl(
+ {
+ available_since: PERIOD_START_MOMENT.format('YYYY-MM-DD')
+ },
+ this.props.organization
+ );
return (
<div className="quality-profile-box quality-profiles-evolution-rules">
@@ -96,7 +99,9 @@ export default class EvolutionRules extends React.PureComponent {
{this.state.latestRules.map(rule => (
<li key={rule.key} className="spacer-top">
<div className="text-ellipsis">
- <Link to={getRulesUrl({ rule_key: rule.key })} className="link-no-underline">
+ <Link
+ to={getRulesUrl({ rule_key: rule.key }, this.props.organization)}
+ className="link-no-underline">
{' '}
{rule.name}
</Link>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js
index 3a53ee66e19..a38a5e9954f 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js
@@ -74,20 +74,24 @@ export default class ProfilesListRow extends React.PureComponent {
}
renderRules() {
- // FIXME getRulesUrl
-
const { profile } = this.props;
- const activeRulesUrl = getRulesUrl({
- qprofile: profile.key,
- activation: 'true'
- });
+ const activeRulesUrl = getRulesUrl(
+ {
+ qprofile: profile.key,
+ activation: 'true'
+ },
+ this.props.organization
+ );
- const deprecatedRulesUrl = getRulesUrl({
- qprofile: profile.key,
- activation: 'true',
- statuses: 'DEPRECATED'
- });
+ const deprecatedRulesUrl = getRulesUrl(
+ {
+ qprofile: profile.key,
+ activation: 'true',
+ statuses: 'DEPRECATED'
+ },
+ this.props.organization
+ );
return (
<div>
diff --git a/server/sonar-web/src/main/js/components/issue/issue-view.js b/server/sonar-web/src/main/js/components/issue/issue-view.js
index eca902adbe9..e9b4c47cfcd 100644
--- a/server/sonar-web/src/main/js/components/issue/issue-view.js
+++ b/server/sonar-web/src/main/js/components/issue/issue-view.js
@@ -245,7 +245,7 @@ export default Marionette.ItemView.extend({
const ruleKey = this.model.get('rule');
// lazy load Workspace
const Workspace = require('../workspace/main').default;
- Workspace.openRule({ key: ruleKey });
+ Workspace.openRule({ key: ruleKey, organization: this.model.get('projectOrganization') });
},
action(action) {
diff --git a/server/sonar-web/src/main/js/components/workspace/main.js b/server/sonar-web/src/main/js/components/workspace/main.js
index 8c8cfd05f44..bb834be5a3a 100644
--- a/server/sonar-web/src/main/js/components/workspace/main.js
+++ b/server/sonar-web/src/main/js/components/workspace/main.js
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+// @flow
import $ from 'jquery';
import Item from './models/item';
import Items from './models/items';
@@ -77,7 +78,7 @@ Workspace.prototype = {
return this.open({ ...options, __type__: 'component' });
},
- openRule(options) {
+ openRule(options: { key: string, organization: string }) {
return this.open({ ...options, __type__: 'rule' });
},
diff --git a/server/sonar-web/src/main/js/components/workspace/templates/workspace-rule.hbs b/server/sonar-web/src/main/js/components/workspace/templates/workspace-rule.hbs
index 9c43694986b..377035a4d2f 100644
--- a/server/sonar-web/src/main/js/components/workspace/templates/workspace-rule.hbs
+++ b/server/sonar-web/src/main/js/components/workspace/templates/workspace-rule.hbs
@@ -42,7 +42,7 @@
{{/if}}
<li class="pull-right spacer-left">
- <a class="icon-link" target="_blank" href="{{rulePermalink key}}"></a>
+ <a class="icon-link" target="_blank" href="{{permalink}}"></a>
</li>
<li class="pull-right">
diff --git a/server/sonar-web/src/main/js/components/workspace/views/rule-view.js b/server/sonar-web/src/main/js/components/workspace/views/rule-view.js
index 1fe6440d64c..be86ab3e38d 100644
--- a/server/sonar-web/src/main/js/components/workspace/views/rule-view.js
+++ b/server/sonar-web/src/main/js/components/workspace/views/rule-view.js
@@ -21,6 +21,8 @@ import { union } from 'lodash';
import Marionette from 'backbone.marionette';
import BaseView from './base-viewer-view';
import Template from '../templates/workspace-rule.hbs';
+import { getRulesUrl } from '../../../helpers/urls';
+import { areThereCustomOrganizations } from '../../../store/organizations/utils';
export default BaseView.extend({
template: Template,
@@ -35,9 +37,15 @@ export default BaseView.extend({
},
serializeData() {
+ const query = { rule_key: this.model.get('key') };
+ const permalink = areThereCustomOrganizations()
+ ? getRulesUrl(query, this.model.get('organization'))
+ : getRulesUrl(query);
+
return {
...Marionette.LayoutView.prototype.serializeData.apply(this, arguments),
- allTags: union(this.model.get('sysTags'), this.model.get('tags'))
+ allTags: union(this.model.get('sysTags'), this.model.get('tags')),
+ permalink
};
}
});
diff --git a/server/sonar-web/src/main/js/helpers/handlebars/rulePermalink.js b/server/sonar-web/src/main/js/helpers/handlebars/rulePermalink.js
deleted file mode 100644
index e338339a804..00000000000
--- a/server/sonar-web/src/main/js/helpers/handlebars/rulePermalink.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-module.exports = function(ruleKey) {
- return window.baseUrl + '/coding_rules#rule_key=' + encodeURIComponent(ruleKey);
-};
diff --git a/server/sonar-web/src/main/js/helpers/urls.js b/server/sonar-web/src/main/js/helpers/urls.js
index de25aa553ee..1464e336fb7 100644
--- a/server/sonar-web/src/main/js/helpers/urls.js
+++ b/server/sonar-web/src/main/js/helpers/urls.js
@@ -114,17 +114,19 @@ export function getQualityGateUrl(key) {
* @param {object} query
* @returns {string}
*/
-export function getRulesUrl(query) {
+export function getRulesUrl(query, organization?: string) {
+ const path = organization ? `/organizations/${organization}/rules` : '/coding_rules';
+
if (query) {
const serializedQuery = Object.keys(query)
.map(criterion => `${encodeURIComponent(criterion)}=${encodeURIComponent(query[criterion])}`)
.join('|');
// return a string (not { pathname }) to help react-router's Link handle this properly
- return '/coding_rules#' + serializedQuery;
+ return path + '#' + serializedQuery;
}
- return '/coding_rules';
+ return path;
}
/**
@@ -132,9 +134,9 @@ export function getRulesUrl(query) {
* @param {object} query
* @returns {string}
*/
-export function getDeprecatedActiveRulesUrl(query = {}) {
+export function getDeprecatedActiveRulesUrl(query = {}, organization?: string) {
const baseQuery = { activation: 'true', statuses: 'DEPRECATED' };
- return getRulesUrl({ ...query, ...baseQuery });
+ return getRulesUrl({ ...query, ...baseQuery }, organization);
}
export const getProjectsUrl = () => {