]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8927 Change format of quality profile permalinks
authorStas Vilchik <vilchiks@gmail.com>
Thu, 30 Mar 2017 12:09:03 +0000 (14:09 +0200)
committerStas Vilchik <stas-vilchik@users.noreply.github.com>
Mon, 3 Apr 2017 08:38:52 +0000 (10:38 +0200)
21 files changed:
it/it-tests/src/test/java/it/organization/OrganizationQualityProfilesPageTest.java
it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java
server/sonar-web/src/main/js/apps/coding-rules/rule/rule-profile-view.js
server/sonar-web/src/main/js/apps/overview/meta/MetaQualityProfiles.js
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.js
server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonContainer.js
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.js
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileContainer.js
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileLink.js
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileContainer-test.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.js
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritanceBox.js
server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.js
server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.js
server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.js
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListRow.js
server/sonar-web/src/main/js/apps/quality-profiles/routes.js
server/sonar-web/src/main/js/apps/quality-profiles/utils.js
server/sonar-web/src/main/js/apps/quality-profiles/views/RenameProfileView.js
server/sonar-web/src/main/js/helpers/urls.js

index 3cabbe545d0af2e5a686324324a8a11cf8cf830b..f214c76456ffeda79c8d172f7272f847b3d6f801 100644 (file)
@@ -100,7 +100,10 @@ public class OrganizationQualityProfilesPageTest {
   @Test
   public void testNotFound() {
     Navigation nav = Navigation.get(orchestrator);
-    nav.open("/organizations/test-org/quality_profiles/show?key=unknown");
+    nav.open("/organizations/" + ORGANIZATION + "/quality_profiles/show?key=unknown");
+    $(".quality-profile-not-found").should(Condition.visible);
+
+    nav.open("/organizations/" + ORGANIZATION + "/quality_profiles/show?language=xoo&name=unknown");
     $(".quality-profile-not-found").should(Condition.visible);
   }
 
index cd41ebf2e29a959a6499dd63290cbe3e2f343797..73e9902e4b58d010be1a3cd05bb3e222ac0e0185 100644 (file)
@@ -85,8 +85,12 @@ public class QualityProfilesPageTest {
   @Test
   public void testNotFound() {
     Navigation nav = Navigation.get(orchestrator);
+
     nav.open("/profiles/show?key=unknown");
     $(".quality-profile-not-found").should(Condition.visible);
+
+    nav.open("/profiles/show?language=xoo&name=unknown");
+    $(".quality-profile-not-found").should(Condition.visible);
   }
 
   @Test
index 8120484ae41d7f51d817f3891d2a5dd07ba1473f..1f03259a1a880ebae33dbae2eaa9aece3e8f9679 100644 (file)
@@ -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.
  */
+import { stringify } from 'querystring';
 import $ from 'jquery';
 import { sortBy } from 'lodash';
 import Backbone from 'backbone';
@@ -150,12 +151,12 @@ export default Marionette.ItemView.extend({
     });
   },
 
-  getProfilePath(profileKey) {
+  getProfilePath(language, name) {
     const { organization } = this.options.app;
-    const encodedKey = encodeURIComponent(profileKey);
+    const query = stringify({ language, name });
     return organization
-      ? `${window.baseUrl}/organizations/${organization}/quality_profiles/show?key=${encodedKey}`
-      : `${window.baseUrl}/profiles/show?key=${encodedKey}`;
+      ? `${window.baseUrl}/organizations/${organization}/quality_profiles/show?${query}`
+      : `${window.baseUrl}/profiles/show?${query}`;
   },
 
   serializeData() {
@@ -168,7 +169,7 @@ export default Marionette.ItemView.extend({
       parameters: this.enhanceParameters(),
       templateKey: this.options.rule.get('templateKey'),
       isTemplate: this.options.rule.get('isTemplate'),
-      profilePath: this.getProfilePath(this.model.get('key')),
+      profilePath: this.getProfilePath(this.model.get('lang'), this.model.get('name')),
       parentProfilePath: parent && this.getProfilePath(parent.key)
     };
   }
index fb5c176df851faaaecfac9525fb4da11ecb11b71..13484c3ca0a1c14ccd2919f063e53b985429cf90 100644 (file)
@@ -85,8 +85,8 @@ class MetaQualityProfiles extends React.Component {
     const languageName = languageFromStore ? languageFromStore.name : profile.language;
 
     const path = this.props.customOrganizations
-      ? getQualityProfileUrl(profile.key, this.props.component.organization)
-      : getQualityProfileUrl(profile.key);
+      ? getQualityProfileUrl(profile.name, profile.language, this.props.component.organization)
+      : getQualityProfileUrl(profile.name, profile.language);
 
     const inner = (
       <div className="text-ellipsis">
index a1fe68f50afcfdb33bfc90a1c07691c80d8b75cf..119c4bd52be17f805b357730caf8346b7dbec79b 100644 (file)
@@ -125,23 +125,37 @@ export default class ChangelogContainer extends React.PureComponent {
   }
 
   handleFromDateChange = (fromDate?: string) => {
-    const path = getProfileChangelogPath(this.props.profile.key, this.props.organization, {
-      since: fromDate,
-      to: this.props.location.query.to
-    });
+    const path = getProfileChangelogPath(
+      this.props.profile.name,
+      this.props.profile.language,
+      this.props.organization,
+      {
+        since: fromDate,
+        to: this.props.location.query.to
+      }
+    );
     this.context.router.push(path);
   };
 
   handleToDateChange = (toDate?: string) => {
-    const path = getProfileChangelogPath(this.props.profile.key, this.props.organization, {
-      since: this.props.location.query.since,
-      to: toDate
-    });
+    const path = getProfileChangelogPath(
+      this.props.profile.name,
+      this.props.profile.language,
+      this.props.organization,
+      {
+        since: this.props.location.query.since,
+        to: toDate
+      }
+    );
     this.context.router.push(path);
   };
 
   handleReset = () => {
-    const path = getProfileChangelogPath(this.props.profile.key, this.props.organization);
+    const path = getProfileChangelogPath(
+      this.props.profile.name,
+      this.props.profile.language,
+      this.props.organization
+    );
     this.context.router.push(path);
   };
 
index 6428c0606841ded047486b37f2c43f36d056bd50..24fba98b4522d27cbc230ce0cf22394874eff13f 100644 (file)
@@ -93,7 +93,12 @@ export default class ComparisonContainer extends React.PureComponent {
   }
 
   handleCompare = (withKey: string) => {
-    const path = getProfileComparePath(this.props.profile.key, this.props.organization, withKey);
+    const path = getProfileComparePath(
+      this.props.profile.name,
+      this.props.profile.language,
+      this.props.organization,
+      withKey
+    );
     this.context.router.push(path);
   };
 
index d1398b7f90ece1aa333fc655ffe8db8c0636b2c9..aacbe90c4283422c457cf5e79b3a94ac8832f99b 100644 (file)
@@ -31,6 +31,7 @@ import type { Profile } from '../propTypes';
 
 type Props = {
   canAdmin: boolean,
+  fromList: boolean,
   organization: ?string,
   profile: Profile,
   updateProfiles: () => Promise<*>
@@ -39,6 +40,10 @@ type Props = {
 export default class ProfileActions extends React.PureComponent {
   props: Props;
 
+  static defaultProps = {
+    fromList: false
+  };
+
   static contextTypes = {
     router: React.PropTypes.object
   };
@@ -46,7 +51,15 @@ export default class ProfileActions extends React.PureComponent {
   handleRenameClick = (e: SyntheticInputEvent) => {
     e.preventDefault();
     new RenameProfileView({ profile: this.props.profile })
-      .on('done', () => this.props.updateProfiles())
+      .on('done', (newName: string) => {
+        this.props.updateProfiles().then(() => {
+          if (!this.props.fromList) {
+            this.context.router.replace(
+              getProfilePath(newName, this.props.profile.language, this.props.organization)
+            );
+          }
+        });
+      })
       .render();
   };
 
@@ -55,7 +68,9 @@ export default class ProfileActions extends React.PureComponent {
     new CopyProfileView({ profile: this.props.profile })
       .on('done', profile => {
         this.props.updateProfiles().then(() => {
-          this.context.router.push(getProfilePath(profile.key, this.props.organization));
+          this.context.router.push(
+            getProfilePath(profile.name, profile.language, this.props.organization)
+          );
         });
       })
       .render();
@@ -107,7 +122,7 @@ export default class ProfileActions extends React.PureComponent {
         </li>
         <li>
           <Link
-            to={getProfileComparePath(profile.key, this.props.organization)}
+            to={getProfileComparePath(profile.name, profile.language, this.props.organization)}
             id="quality-profile-compare">
             {translate('compare')}
           </Link>
index d55f57dd8fe19d4561208b48064737acdd262106..0ee269b6a25cd40cf4ec4c9ed7e288050d70cd19 100644 (file)
@@ -28,19 +28,51 @@ import type { Profile } from '../propTypes';
 type Props = {
   canAdmin: boolean,
   children: React.Element<*>,
-  location: { query: { key: string } },
+  location: {
+    pathname: string,
+    query: { key?: string, language: string, name: string }
+  },
   organization: ?string,
   profiles: Array<Profile>,
+  router: { replace: () => void },
   updateProfiles: () => Promise<*>
 };
 
 export default class ProfileContainer extends React.PureComponent {
   props: Props;
 
+  componentDidMount() {
+    const { location, profiles, router } = this.props;
+    if (location.query.key) {
+      // try to find a quality profile with the given key
+      // if managed to find one, redirect to a new version
+      // otherwise do nothing, `render` will show not found page
+      const profile = profiles.find(profile => profile.key === location.query.key);
+      if (profile) {
+        router.replace({
+          pathname: location.pathname,
+          query: { language: profile.language, name: profile.name }
+        });
+      }
+    }
+  }
+
   render() {
     const { organization, profiles, location, ...other } = this.props;
-    const { key } = location.query;
-    const profile = profiles.find(profile => profile.key === key);
+    const { key, language, name } = location.query;
+
+    if (key) {
+      // if there is a `key` parameter,
+      // then if we managed to find a quality profile with this key
+      // then we will be redirected in `componentDidMount`
+      // otherwise show `ProfileNotFound`
+      const profile = profiles.find(profile => profile.key === location.query.key);
+      return profile ? null : <ProfileNotFound organization={organization} />;
+    }
+
+    const profile = profiles.find(
+      profile => profile.language === language && profile.name === name
+    );
 
     if (!profile) {
       return <ProfileNotFound organization={organization} />;
index a60c37ab9b1a9a06c7bc067ef31dc22e1a8a443d..0eb92cb01056fff3219046018b74c2c9b354dfcb 100644 (file)
@@ -24,18 +24,19 @@ import { getProfilePath } from '../utils';
 
 type Props = {
   children?: React.Element<*>,
-  organization: ?string,
-  profileKey: string
+  language: string,
+  name: string,
+  organization: ?string
 };
 
 export default class ProfileLink extends React.PureComponent {
   props: Props;
 
   render() {
-    const { profileKey, organization, children, ...other } = this.props;
+    const { name, language, organization, children, ...other } = this.props;
     return (
       <Link
-        to={getProfilePath(profileKey, organization)}
+        to={getProfilePath(name, language, organization)}
         activeClassName="link-no-underline"
         {...other}>
         {children}
index c4073232a95da859fbd67b625c37aa6e7ab70f27..08aa98c6b326d35f59545a0a1c5b625be68e82aa 100644 (file)
@@ -26,12 +26,12 @@ import ProfileHeader from '../../details/ProfileHeader';
 import { createFakeProfile } from '../../utils';
 
 it('should render ProfileHeader', () => {
-  const targetProfile = createFakeProfile({ key: 'profile1' });
-  const profiles = [targetProfile, createFakeProfile({ key: 'profile2' })];
+  const targetProfile = createFakeProfile({ language: 'js', name: 'fake' });
+  const profiles = [targetProfile, createFakeProfile({ language: 'js', name: 'another' })];
   const updateProfiles = jest.fn();
   const output = shallow(
     <ProfileContainer
-      location={{ query: { key: 'profile1' } }}
+      location={{ query: { language: 'js', name: 'fake' } }}
       profiles={profiles}
       canAdmin={false}
       updateProfiles={updateProfiles}>
@@ -46,10 +46,13 @@ it('should render ProfileHeader', () => {
 });
 
 it('should render ProfileNotFound', () => {
-  const profiles = [createFakeProfile({ key: 'profile1' }), createFakeProfile({ key: 'profile2' })];
+  const profiles = [
+    createFakeProfile({ language: 'js', name: 'fake' }),
+    createFakeProfile({ language: 'js', name: 'another' })
+  ];
   const output = shallow(
     <ProfileContainer
-      location={{ query: { key: 'random' } }}
+      location={{ query: { language: 'js', name: 'random' } }}
       profiles={profiles}
       canAdmin={false}
       updateProfiles={() => true}>
@@ -60,11 +63,11 @@ it('should render ProfileNotFound', () => {
 });
 
 it('should render Helmet', () => {
-  const profiles = [createFakeProfile({ key: 'profile1', name: 'First Profile' })];
+  const profiles = [createFakeProfile({ language: 'js', name: 'First Profile' })];
   const updateProfiles = jest.fn();
   const output = shallow(
     <ProfileContainer
-      location={{ query: { key: 'profile1' } }}
+      location={{ query: { language: 'js', name: 'First Profile' } }}
       profiles={profiles}
       canAdmin={false}
       updateProfiles={updateProfiles}>
index 3a06c63e47297851363c3548fdadf7214991af7b..5c66dfcfcacb7f750c1acb27da72471eb6723c93 100644 (file)
@@ -108,9 +108,10 @@ export default class ProfileHeader extends React.PureComponent {
 
         <h1 className="page-title">
           <ProfileLink
-            organization={organization}
-            profileKey={profile.key}
-            className="link-base-color">
+            className="link-base-color"
+            language={profile.language}
+            name={profile.name}
+            organization={organization}>
             <span>{profile.name}</span>
           </ProfileLink>
         </h1>
@@ -120,7 +121,9 @@ export default class ProfileHeader extends React.PureComponent {
             {this.renderUpdateDate()}
             {this.renderUsageDate()}
             <li>
-              <Link to={getProfileChangelogPath(profile.key, organization)} className="button">
+              <Link
+                to={getProfileChangelogPath(profile.name, profile.language, organization)}
+                className="button">
                 {translate('changelog')}
               </Link>
             </li>
index f6760f674f52e703c42455cec9b651316b769b8b..ea38598bd65ded7f52382fca1119fb865a2946e7 100644 (file)
@@ -34,26 +34,19 @@ type Props = {
   updateProfiles: () => Promise<*>
 };
 
+type ProfileInheritanceDetails = {
+  activeRuleCount: number,
+  key: string,
+  language: string,
+  name: string,
+  overridingRuleCount?: number
+};
+
 type State = {
-  ancestors?: Array<{
-    activeRuleCount: number,
-    key: string,
-    name: string,
-    overridingRuleCount?: number
-  }>,
-  children?: Array<{
-    activeRuleCount: number,
-    key: string,
-    name: string,
-    overridingRuleCount?: number
-  }>,
+  ancestors?: Array<ProfileInheritanceDetails>,
+  children?: Array<ProfileInheritanceDetails>,
   loading: boolean,
-  profile?: {
-    activeRuleCount: number,
-    key: string,
-    name: string,
-    overridingRuleCount?: number
-  }
+  profile?: ProfileInheritanceDetails
 };
 
 export default class ProfileInheritance extends React.PureComponent {
@@ -129,6 +122,7 @@ export default class ProfileInheritance extends React.PureComponent {
                     className="js-inheritance-ancestor"
                     depth={index}
                     key={ancestor.key}
+                    language={this.props.profile.language}
                     organization={this.props.organization}
                     profile={ancestor}
                   />
@@ -138,6 +132,7 @@ export default class ProfileInheritance extends React.PureComponent {
                 className={currentClassName}
                 depth={this.state.ancestors ? this.state.ancestors.length : 0}
                 displayLink={false}
+                language={this.props.profile.language}
                 organization={this.props.organization}
                 profile={this.state.profile}
               />
@@ -148,6 +143,7 @@ export default class ProfileInheritance extends React.PureComponent {
                     className="js-inheritance-child"
                     depth={this.state.ancestors ? this.state.ancestors.length + 1 : 0}
                     key={child.key}
+                    language={this.props.profile.language}
                     organization={this.props.organization}
                     profile={child}
                   />
index 5af9d91b2075c118fe13b4b21e1f4466584025e9..6ae591d571c26eb429d1582431d2d34594cbf142 100644 (file)
@@ -26,10 +26,12 @@ type Props = {
   className?: string,
   depth: number,
   displayLink?: boolean,
+  language: string,
   organization: ?string,
   profile: {
     activeRuleCount: number,
     key: string,
+    language: string,
     name: string,
     overridingRuleCount?: number
   }
@@ -51,7 +53,10 @@ export default class ProfileInheritanceBox extends React.PureComponent {
         <td>
           <div style={{ paddingLeft: offset }}>
             {this.props.displayLink
-              ? <ProfileLink organization={this.props.organization} profileKey={profile.key}>
+              ? <ProfileLink
+                  language={this.props.language}
+                  name={profile.name}
+                  organization={this.props.organization}>
                   {profile.name}
                 </ProfileLink>
               : profile.name}
index 89d9d87beabd64f3ae21e2e8bcbb1309002aa09b..037c1e9f16f448e8858a716c81f6335acf94227e 100644 (file)
@@ -61,9 +61,10 @@ export default class EvolutionDeprecated extends React.PureComponent {
             <li key={profile.key} className="spacer-top">
               <div className="text-ellipsis">
                 <ProfileLink
-                  organization={this.props.organization}
-                  profileKey={profile.key}
-                  className="link-no-underline">
+                  className="link-no-underline"
+                  language={profile.language}
+                  name={profile.name}
+                  organization={this.props.organization}>
                   {profile.name}
                 </ProfileLink>
               </div>
index 29679aca1aee945bb8b0a6264f3d48912c3f4b14..63f0ff7bdefe6e4be1cc1118cb3f8339dce14463 100644 (file)
@@ -55,9 +55,10 @@ export default class EvolutionStagnant extends React.PureComponent {
             <li key={profile.key} className="spacer-top">
               <div className="text-ellipsis">
                 <ProfileLink
-                  organization={this.props.organization}
-                  profileKey={profile.key}
-                  className="link-no-underline">
+                  className="link-no-underline"
+                  language={profile.language}
+                  name={profile.name}
+                  organization={this.props.organization}>
                   {profile.name}
                 </ProfileLink>
               </div>
index 48ff0383758ae4340c60b1472bee34b5eba56366..df6191a83008881bbf2257cc7698ce438d67023d 100644 (file)
@@ -73,7 +73,9 @@ export default class PageHeader extends React.PureComponent {
       })
         .on('done', profile => {
           this.props.updateProfiles().then(() => {
-            this.context.router.push(getProfilePath(profile.key, this.props.organization));
+            this.context.router.push(
+              getProfilePath(profile.name, profile.language, this.props.organization)
+            );
           });
         })
         .render();
index a38a5e9954f3abfe39919938d9221dfd425473d2..8f3e21c793ed53fb031de6d28e7214e26ec88a9a 100644 (file)
@@ -48,7 +48,10 @@ export default class ProfilesListRow extends React.PureComponent {
     const offset = 25 * (profile.depth - 1);
     return (
       <div style={{ paddingLeft: offset }}>
-        <ProfileLink organization={this.props.organization} profileKey={profile.key}>
+        <ProfileLink
+          language={profile.language}
+          name={profile.name}
+          organization={this.props.organization}>
           {profile.name}
         </ProfileLink>
       </div>
@@ -161,6 +164,7 @@ export default class ProfilesListRow extends React.PureComponent {
               </button>
               <ProfileActions
                 canAdmin={this.props.canAdmin}
+                fromList={true}
                 organization={this.props.organization}
                 profile={this.props.profile}
                 updateProfiles={this.props.updateProfiles}
index 57c5ca1baadcbe4033868edb89b70abb7dbdad4f..4c53b80384fe3e119ecca2742107a5a78339abfb 100644 (file)
@@ -17,6 +17,8 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+import { withRouter } from 'react-router';
+
 const routes = [
   {
     getComponent(state, callback) {
@@ -39,7 +41,7 @@ const routes = [
       {
         getComponent(_, callback) {
           require.ensure([], require => {
-            callback(null, require('./components/ProfileContainer').default);
+            callback(null, withRouter(require('./components/ProfileContainer').default));
           });
         },
         childRoutes: [
index 64bb0ea07d6def6b74e260e6c3e702bc5e16b0cc..97ff96be5241b1976f641660f5c415409a6e5b2a 100644 (file)
@@ -70,36 +70,38 @@ export const getProfilesPath = (organization: ?string) =>
   organization ? `/organizations/${organization}/quality_profiles` : '/profiles';
 
 export const getProfilesForLanguagePath = (language: string, organization: ?string) => ({
-  pathname: organization ? `/organizations/${organization}/quality_profiles` : '/profiles',
+  pathname: getProfilesPath(organization),
   query: { language }
 });
 
-export const getProfilePath = (profile: string, organization: ?string) => ({
-  pathname: organization
-    ? `/organizations/${organization}/quality_profiles/show`
-    : '/profiles/show',
-  query: { key: profile }
+export const getProfilePath = (name: string, language: string, organization: ?string) => ({
+  pathname: getProfilesPath(organization) + '/show',
+  query: { name, language }
 });
 
-export const getProfileComparePath = (profile: string, organization: ?string, withKey?: string) => {
-  const query: Object = { key: profile };
+export const getProfileComparePath = (
+  name: string,
+  language: string,
+  organization: ?string,
+  withKey?: string
+) => {
+  const query: Object = { language, name };
   if (withKey) {
     Object.assign(query, { withKey });
   }
   return {
-    pathname: organization
-      ? `/organizations/${organization}/quality_profiles/compare`
-      : '/profiles/compare',
+    pathname: getProfilesPath(organization) + '/compare',
     query
   };
 };
 
 export const getProfileChangelogPath = (
-  profile: string,
+  name: string,
+  language: string,
   organization: ?string,
   filter?: { since?: string, to?: string }
 ) => {
-  const query: Object = { key: profile };
+  const query: Object = { language, name };
   if (filter) {
     if (filter.since) {
       Object.assign(query, { since: filter.since });
@@ -109,9 +111,7 @@ export const getProfileChangelogPath = (
     }
   }
   return {
-    pathname: organization
-      ? `/organizations/${organization}/quality_profiles/changelog`
-      : '/profiles/changelog',
+    pathname: getProfilesPath(organization) + '/changelog',
     query
   };
 };
index 308efa7c143f5f687825b752a96bb9e4c04f36dc..57e3e5c5e67b478f25527f1a870f2da19efbb6dc 100644 (file)
@@ -33,9 +33,9 @@ export default ModalFormView.extend({
   sendRequest() {
     const name = this.$('#rename-profile-name').val();
     renameProfile(this.options.profile.key, name)
-      .then(profile => {
+      .then(() => {
         this.destroy();
-        this.trigger('done', profile);
+        this.trigger('done', name);
       })
       .catch(e => {
         if (e.response.status === 400) {
index 1464e336fb73cc688c815cccaee605373896ac28..1d4097f95c70050f610516bec692d2f29a6be961 100644 (file)
@@ -91,11 +91,9 @@ export function getComponentPermissionsUrl(componentKey) {
 
 /**
  * Generate URL for a quality profile
- * @param {string} key
- * @returns {Object}
  */
-export function getQualityProfileUrl(key, organization) {
-  return getProfilePath(key, organization);
+export function getQualityProfileUrl(name, language, organization) {
+  return getProfilePath(name, language, organization);
 }
 
 /**