]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13999 Drop orgs from rules
authorJeremy Davis <jeremy.davis@sonarsource.com>
Mon, 14 Dec 2020 17:21:03 +0000 (18:21 +0100)
committersonartech <sonartech@sonarsource.com>
Tue, 22 Dec 2020 20:09:36 +0000 (20:09 +0000)
25 files changed:
server/sonar-web/src/main/js/api/quality-profiles.ts
server/sonar-web/src/main/js/api/rules.ts
server/sonar-web/src/main/js/apps/coding-rules/components/App.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/BulkChangeModal.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/TagFacet.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/App-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/BulkChange-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/BulkChangeModal-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/FacetsList-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleListItem-test.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/TagFacet-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/App-test.tsx.snap
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/FacetsList-test.tsx.snap
server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/TagFacet-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/components/workspace/__tests__/WorkspaceNav-test.tsx
server/sonar-web/src/main/js/components/workspace/__tests__/WorkspaceNavRule-test.tsx
server/sonar-web/src/main/js/components/workspace/__tests__/WorkspaceRuleTitle-test.tsx
server/sonar-web/src/main/js/components/workspace/__tests__/WorkspaceRuleViewer-test.tsx
server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceNav-test.tsx.snap
server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceNavRule-test.tsx.snap
server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/WorkspaceRuleViewer-test.tsx.snap
server/sonar-web/src/main/js/types/coding-rules.ts [new file with mode: 0644]

index 66f9292c6551e9e139eb8ac22c47f61c12a69745..fcd82b61b5ac9940e27503f03dc5f8c3a937bf57 100644 (file)
@@ -293,7 +293,6 @@ export interface BulkActivateParameters {
   inheritance?: string;
   is_template?: string;
   languages?: string;
-  organization: string | undefined;
   q?: string;
   qprofile?: string;
   repositories?: string;
index 97f244e2728f67d34baaff7bba0384f74ef76f07..7a02fbe6885242c0e8191faf6c188b19f50827b2 100644 (file)
  */
 import { getJSON, post, postJSON } from 'sonar-ui-common/helpers/request';
 import throwGlobalError from '../app/utils/throwGlobalError';
+import { GetRulesAppResponse, SearchRulesResponse } from '../types/coding-rules';
 
-export interface GetRulesAppResponse {
-  canWrite?: boolean;
-  repositories: { key: string; language: string; name: string }[];
-}
-
-export function getRulesApp(organization?: string): Promise<GetRulesAppResponse> {
-  return getJSON('/api/rules/app', { organization }).catch(throwGlobalError);
-}
-
-export interface SearchRulesResponse {
-  actives?: T.Dict<T.RuleActivation[]>;
-  facets?: { property: string; values: { count: number; val: string }[] }[];
-  p: number;
-  ps: number;
-  rules: T.Rule[];
-  total: number;
+export function getRulesApp(): Promise<GetRulesAppResponse> {
+  return getJSON('/api/rules/app').catch(throwGlobalError);
 }
 
 export function searchRules(data: {
@@ -53,16 +40,11 @@ export function takeFacet(response: any, property: string) {
 export function getRuleDetails(parameters: {
   actives?: boolean;
   key: string;
-  organization?: string;
 }): Promise<{ actives?: T.RuleActivation[]; rule: T.RuleDetails }> {
   return getJSON('/api/rules/show', parameters).catch(throwGlobalError);
 }
 
-export function getRuleTags(parameters: {
-  organization?: string;
-  ps?: number;
-  q: string;
-}): Promise<string[]> {
+export function getRuleTags(parameters: { ps?: number; q: string }): Promise<string[]> {
   return getJSON('/api/rules/tags', parameters).then(r => r.tags, throwGlobalError);
 }
 
@@ -70,7 +52,6 @@ export function createRule(data: {
   custom_key: string;
   markdown_description: string;
   name: string;
-  organization?: string;
   params?: string;
   prevent_reactivation?: boolean;
   severity?: string;
@@ -101,7 +82,6 @@ export function updateRule(data: {
   markdown_description?: string;
   markdown_note?: string;
   name?: string;
-  organization?: string;
   params?: string;
   remediation_fn_base_effort?: string;
   remediation_fn_type?: string;
index fe7e71086935d562bfe7049badaa15bf12062f8b..f3f3774c87aea33e8b0872b92ee9150cb345a805 100644 (file)
@@ -41,15 +41,8 @@ import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
 import FiltersHeader from '../../../components/common/FiltersHeader';
 import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
 import '../../../components/search-navigator.css';
-import { hasPrivateAccess } from '../../../helpers/organizations';
 import { isLoggedIn } from '../../../helpers/users';
-import {
-  getAppState,
-  getCurrentUser,
-  getLanguages,
-  getMyOrganizations,
-  Store
-} from '../../../store/rootReducer';
+import { getCurrentUser, getLanguages, Store } from '../../../store/rootReducer';
 import { SecurityStandard } from '../../../types/security';
 import {
   shouldOpenSonarSourceSecurityFacet,
@@ -84,19 +77,11 @@ const PAGE_SIZE = 100;
 const MAX_SEARCH_LENGTH = 200;
 const LIMIT_BEFORE_LOAD_MORE = 5;
 
-interface StateToProps {
-  appState: T.AppState;
+interface Props extends WithRouterProps {
   currentUser: T.CurrentUser;
   languages: T.Languages;
-  userOrganizations: T.Organization[];
-}
-
-interface OwnProps extends WithRouterProps {
-  organization: T.Organization | undefined;
 }
 
-type Props = OwnProps & StateToProps;
-
 interface State {
   actives?: Actives;
   canWrite?: boolean;
@@ -233,7 +218,6 @@ export class App extends React.PureComponent<Props, State> {
   getSearchParameters = () => ({
     f: this.getFieldsToFetch().join(),
     facets: this.getFacetsToFetch().join(),
-    organization: this.props.organization && this.props.organization.key,
     ps: PAGE_SIZE,
     s: 'name',
     ...serializeQuery(this.state.query)
@@ -247,8 +231,7 @@ export class App extends React.PureComponent<Props, State> {
 
   fetchInitialData = () => {
     this.setState({ loading: true });
-    const organization = this.props.organization && this.props.organization.key;
-    Promise.all([getRulesApp(organization), this.fetchQualityProfiles()]).then(
+    Promise.all([getRulesApp(), searchQualityProfiles()]).then(
       ([{ canWrite, repositories }, { profiles }]) => {
         this.setState({
           canWrite,
@@ -321,14 +304,6 @@ export class App extends React.PureComponent<Props, State> {
     }, this.stopLoading);
   };
 
-  fetchQualityProfiles = () => {
-    const { currentUser, organization, userOrganizations } = this.props;
-    if (hasPrivateAccess(currentUser, organization, userOrganizations)) {
-      return searchQualityProfiles();
-    }
-    return { profiles: [] };
-  };
-
   getSelectedIndex = ({ selected, rules } = this.state) => {
     const index = rules.findIndex(rule => rule.key === selected);
     return index !== -1 ? index : undefined;
@@ -551,7 +526,6 @@ export class App extends React.PureComponent<Props, State> {
   renderBulkButton = () => {
     const { currentUser, languages } = this.props;
     const { canWrite, paging, query, referencedProfiles } = this.state;
-    const organization = this.props.organization && this.props.organization.key;
 
     if (!isLoggedIn(currentUser) || !canWrite) {
       return null;
@@ -561,7 +535,6 @@ export class App extends React.PureComponent<Props, State> {
       paging && (
         <BulkChange
           languages={languages}
-          organization={organization}
           query={query}
           referencedProfiles={referencedProfiles}
           total={paging.total}
@@ -573,12 +546,6 @@ export class App extends React.PureComponent<Props, State> {
   render() {
     const { paging, rules } = this.state;
     const selectedIndex = this.getSelectedIndex();
-    const organization = this.props.organization && this.props.organization.key;
-    const hideQualityProfiles = !hasPrivateAccess(
-      this.props.currentUser,
-      this.props.organization,
-      this.props.userOrganizations
-    );
 
     return (
       <>
@@ -609,12 +576,9 @@ export class App extends React.PureComponent<Props, State> {
                     />
                     <FacetsList
                       facets={this.state.facets}
-                      hideProfileFacet={hideQualityProfiles}
                       onFacetToggle={this.handleFacetToggle}
                       onFilterChange={this.handleFilterChange}
                       openFacets={this.state.openFacets}
-                      organization={organization}
-                      organizationsEnabled={this.props.appState.organizationsEnabled}
                       query={this.state.query}
                       referencedProfiles={this.state.referencedProfiles}
                       referencedRepositories={this.state.referencedRepositories}
@@ -659,9 +623,8 @@ export class App extends React.PureComponent<Props, State> {
             <div className="layout-page-main-inner">
               {this.state.openRule ? (
                 <RuleDetails
-                  allowCustomRules={!this.props.appState.organizationsEnabled}
+                  allowCustomRules={true}
                   canWrite={this.state.canWrite}
-                  hideQualityProfiles={hideQualityProfiles}
                   onActivate={this.handleRuleActivate}
                   onDeactivate={this.handleRuleDeactivate}
                   onDelete={this.handleRuleDelete}
@@ -683,7 +646,6 @@ export class App extends React.PureComponent<Props, State> {
                       onDeactivate={this.handleRuleDeactivate}
                       onFilterChange={this.handleFilterChange}
                       onOpen={this.handleRuleOpen}
-                      organization={organization}
                       rule={rule}
                       selected={rule.key === this.state.selected}
                       selectedProfile={this.getSelectedProfile()}
@@ -731,10 +693,8 @@ function parseFacets(rawFacets: { property: string; values: { count: number; val
 }
 
 const mapStateToProps = (state: Store) => ({
-  appState: getAppState(state),
   currentUser: getCurrentUser(state),
-  languages: getLanguages(state),
-  userOrganizations: getMyOrganizations(state)
+  languages: getLanguages(state)
 });
 
 export default withRouter(connect(mapStateToProps)(App));
index dd60587af3d66c1ac555b0ac888b29e79b35d9ac..c6caa9ed0cde05f459019bbfddc0c841fd30224c 100644 (file)
@@ -21,15 +21,14 @@ import * as React from 'react';
 import { Button } from 'sonar-ui-common/components/controls/buttons';
 import Dropdown from 'sonar-ui-common/components/controls/Dropdown';
 import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
+import { PopupPlacement } from 'sonar-ui-common/components/ui/popups';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import { Profile } from '../../../api/quality-profiles';
 import { Query } from '../query';
 import BulkChangeModal from './BulkChangeModal';
-import { PopupPlacement } from 'sonar-ui-common/components/ui/popups';
 
 interface Props {
   languages: T.Languages;
-  organization: string | undefined;
   query: Query;
   referencedProfiles: T.Dict<Profile>;
   total: number;
@@ -138,7 +137,6 @@ export default class BulkChange extends React.PureComponent<Props, State> {
             action={this.state.action}
             languages={this.props.languages}
             onClose={this.closeModal}
-            organization={this.props.organization}
             profile={this.state.profile}
             query={this.props.query}
             referencedProfiles={this.props.referencedProfiles}
index 4531219f1a1452ad1b94d09fec202803e70e823b..246c105537af663384ba6406f97955e75e311b27 100644 (file)
@@ -31,7 +31,6 @@ interface Props {
   action: string;
   languages: T.Languages;
   onClose: () => void;
-  organization: string | undefined;
   profile?: Profile;
   query: Query;
   referencedProfiles: T.Dict<Profile>;
@@ -117,13 +116,14 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
       : this.state.selectedProfiles;
 
     for (const profile of profiles) {
-      looper = looper.then(() =>
-        method({
-          ...data,
-          organization: this.props.organization,
-          targetKey: profile
-        }).then(response => this.processResponse(profile, response))
-      );
+      looper = looper
+        .then(() =>
+          method({
+            ...data,
+            targetKey: profile
+          })
+        )
+        .then(response => this.processResponse(profile, response));
     }
     return looper;
   };
index 6ed4345f97a7ae21d5804b6384733da51e588f95..40316ff89388343ea03ff26c0c59e648a3be5f0b 100644 (file)
@@ -33,21 +33,19 @@ import TagFacet from './TagFacet';
 import TemplateFacet from './TemplateFacet';
 import TypeFacet from './TypeFacet';
 
-interface Props {
+export interface FacetsListProps {
   facets?: Facets;
   hideProfileFacet?: boolean;
   onFacetToggle: (facet: string) => void;
   onFilterChange: (changes: Partial<Query>) => void;
   openFacets: OpenFacets;
-  organization: string | undefined;
-  organizationsEnabled?: boolean;
   query: Query;
   referencedProfiles: T.Dict<Profile>;
   referencedRepositories: T.Dict<{ key: string; language: string; name: string }>;
   selectedProfile?: Profile;
 }
 
-export default function FacetsList(props: Props) {
+export default function FacetsList(props: FacetsListProps) {
   const languageDisabled = !props.hideProfileFacet && props.query.profile !== undefined;
 
   const inheritanceDisabled =
@@ -80,7 +78,6 @@ export default function FacetsList(props: Props) {
         onChange={props.onFilterChange}
         onToggle={props.onFacetToggle}
         open={!!props.openFacets.tags}
-        organization={props.organization}
         stats={props.facets && props.facets.tags}
         values={props.query.tags}
       />
@@ -134,14 +131,12 @@ export default function FacetsList(props: Props) {
         open={!!props.openFacets.availableSince}
         value={props.query.availableSince}
       />
-      {!props.organizationsEnabled && (
-        <TemplateFacet
-          onChange={props.onFilterChange}
-          onToggle={props.onFacetToggle}
-          open={!!props.openFacets.template}
-          value={props.query.template}
-        />
-      )}
+      <TemplateFacet
+        onChange={props.onFilterChange}
+        onToggle={props.onFacetToggle}
+        open={!!props.openFacets.template}
+        value={props.query.template}
+      />
       {!props.hideProfileFacet && (
         <>
           <ProfileFacet
index 790781c5afa1dad0f7d20fb836d07e42043d48f2..4f3ab0f419d7c471480cbd39350fc13674c3fff4 100644 (file)
@@ -42,7 +42,6 @@ interface Props {
   onDeactivate: (profile: string, rule: string) => void;
   onFilterChange: (changes: Partial<Query>) => void;
   onOpen: (ruleKey: string) => void;
-  organization: string | undefined;
   rule: T.Rule;
   selected: boolean;
   selectedProfile?: Profile;
@@ -53,7 +52,6 @@ export default class RuleListItem extends React.PureComponent<Props> {
     if (this.props.selectedProfile) {
       const data = {
         key: this.props.selectedProfile.key,
-        organization: this.props.organization,
         rule: this.props.rule.key
       };
       deactivateRule(data).then(
index 1e4a8e070334d7117dbfaf12ac595c38f4eaa10a..1d539306a487be31d304bfded62968ecff55cf1a 100644 (file)
@@ -27,13 +27,9 @@ import { colors } from '../../../app/theme';
 import ListStyleFacet from '../../../components/facet/ListStyleFacet';
 import { BasicProps } from './Facet';
 
-interface Props extends BasicProps {
-  organization: string | undefined;
-}
-
-export default class TagFacet extends React.PureComponent<Props> {
+export default class TagFacet extends React.PureComponent<BasicProps> {
   handleSearch = (query: string) => {
-    return getRuleTags({ organization: this.props.organization, ps: 50, q: query }).then(tags => ({
+    return getRuleTags({ ps: 50, q: query }).then(tags => ({
       paging: { pageIndex: 1, pageSize: tags.length, total: tags.length },
       results: tags
     }));
index bb659eca8e70caadc20a4baf3a4d1eeaa0c585cc..8eb191aa8ad4d59259297a60db4f20601e7e23e7 100644 (file)
@@ -22,14 +22,7 @@ import * as React from 'react';
 import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
 import { getRulesApp } from '../../../../api/rules';
 import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper';
-import {
-  mockAppState,
-  mockCurrentUser,
-  mockLocation,
-  mockOrganization,
-  mockRouter,
-  mockRule
-} from '../../../../helpers/testMocks';
+import { mockCurrentUser, mockLocation, mockRouter, mockRule } from '../../../../helpers/testMocks';
 import { App } from '../App';
 
 jest.mock('../../../../components/common/ScreenPositionHelper');
@@ -104,20 +97,16 @@ describe('renderBulkButton', () => {
 });
 
 function shallowRender(props: Partial<App['props']> = {}) {
-  const organization = mockOrganization();
   return shallow<App>(
     <App
-      appState={mockAppState()}
       currentUser={mockCurrentUser({
         isLoggedIn: true
       })}
       languages={{ js: { key: 'js', name: 'JavaScript' } }}
       location={mockLocation()}
-      organization={organization}
       params={{}}
       router={mockRouter()}
       routes={[]}
-      userOrganizations={[organization]}
       {...props}
     />
   );
index 835168e0de96f07690bcef1225e197ac06fe3029..8fc15a707c55b24c30198ce90b10c7910ded42c2 100644 (file)
@@ -54,7 +54,6 @@ function shallowRender(props: Partial<BulkChange['props']> = {}) {
   return shallow<BulkChange>(
     <BulkChange
       languages={{ js: { key: 'js', name: 'JavaScript' } }}
-      organization={undefined}
       query={{ activation: false, profile: 'key' } as BulkChange['props']['query']}
       referencedProfiles={{ key: profile }}
       total={2}
index 0856ed585df711fa04b25c9a213e9fa20e546fb0..eac40eb6b1135733804919c8bfe4d2b5c4979f5a 100644 (file)
@@ -105,7 +105,6 @@ function shallowRender(props: Partial<BulkChangeModal['props']> = {}) {
       action="activate"
       languages={{ js: mockLanguage() }}
       onClose={jest.fn()}
-      organization={undefined}
       profile={mockQualityProfile()}
       query={{ languages: ['js'] } as Query}
       referencedProfiles={{
index f0b45fb797803219b9311af8f75a478e66795b4c..239d87824b6025d55cd994647845627a6412a6df 100644 (file)
@@ -20,7 +20,7 @@
 import { shallow } from 'enzyme';
 import * as React from 'react';
 import { Query } from '../../query';
-import FacetsList from '../FacetsList';
+import FacetsList, { FacetsListProps } from '../FacetsList';
 
 it('should render correctly', () => {
   const wrapper = shallowRender();
@@ -34,13 +34,8 @@ it('should correctly hide profile facets', () => {
   expect(wrapper.find('ActivationSeverityFacet').length).toEqual(0);
 });
 
-it('should correctly hide the template facet', () => {
-  const wrapper = shallowRender({ organizationsEnabled: true });
-  expect(wrapper.find('TemplateFacet').length).toEqual(0);
-});
-
 it('should correctly enable/disable the language facet', () => {
-  const wrapper = shallowRender({ query: { profile: 'foo' } });
+  const wrapper = shallowRender({ query: { profile: 'foo' } as Query });
   expect(wrapper.find('Connect(LanguageFacet)').prop('disabled')).toBe(true);
 
   wrapper.setProps({ query: {} }).update();
@@ -63,13 +58,12 @@ it('should correctly enable/disable the inheritcance facet', () => {
   expect(wrapper.find('InheritanceFacet').prop('disabled')).toBe(false);
 });
 
-function shallowRender(props = {}) {
+function shallowRender(props: Partial<FacetsListProps> = {}) {
   return shallow(
     <FacetsList
       onFacetToggle={jest.fn()}
       onFilterChange={jest.fn()}
       openFacets={{}}
-      organization="foo"
       query={{} as Query}
       referencedProfiles={{}}
       referencedRepositories={{}}
index c7fcd701290d807b7086acdd62e3b924f69d4400..7fd16f6d019b146d60c2feea9f3ed04caa3cf94c 100644 (file)
@@ -165,7 +165,6 @@ function shallowRender(props?: Partial<RuleListItem['props']>) {
       onDeactivate={jest.fn()}
       onFilterChange={jest.fn()}
       onOpen={jest.fn()}
-      organization={undefined}
       rule={mockRule({ key: 'javascript:S1067' })}
       selected={false}
       {...props}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/TagFacet-test.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/TagFacet-test.tsx
new file mode 100644 (file)
index 0000000..d7b1c35
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.
+ */
+
+import { shallow } from 'enzyme';
+import * as React from 'react';
+import { getRuleTags } from '../../../../api/rules';
+import TagFacet from '../TagFacet';
+
+jest.mock('../../../../api/rules', () => ({
+  getRuleTags: jest.fn().mockResolvedValue([])
+}));
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot();
+});
+
+it('should handle search', async () => {
+  const wrapper = shallowRender();
+
+  const query = 'query';
+
+  await wrapper.instance().handleSearch(query);
+
+  expect(getRuleTags).toBeCalledWith({ ps: 50, q: query });
+});
+
+describe('ListStyleFacet Renderers', () => {
+  const instance = shallowRender().instance();
+
+  it('should include renderFacetItem', () => {
+    expect(instance.renderTag('tag')).toMatchSnapshot();
+  });
+
+  it('should include renderSearchResult', () => {
+    expect(instance.renderSearchResult('my-tag', 'tag')).toMatchSnapshot();
+  });
+});
+
+function shallowRender(props: Partial<TagFacet['props']> = {}) {
+  return shallow<TagFacet>(
+    <TagFacet
+      onChange={jest.fn()}
+      onToggle={jest.fn()}
+      open={false}
+      stats={{}}
+      values={[]}
+      {...props}
+    />
+  );
+}
index 247c393d5112077246e8d310f760ae8f84411f69..fdf6f2d444222a9141e56c8fd4acdd1b695615d5 100644 (file)
@@ -10,7 +10,6 @@ exports[`renderBulkButton should show bulk change button when everything is fine
       },
     }
   }
-  organization="foo"
   query={
     Object {
       "activation": undefined,
@@ -74,7 +73,6 @@ exports[`should render correctly: loaded (ScreenPositionHelper) 1`] = `
       />
       <FacetsList
         facets={Object {}}
-        hideProfileFacet={false}
         onFacetToggle={[Function]}
         onFilterChange={[Function]}
         openFacets={
@@ -87,7 +85,6 @@ exports[`should render correctly: loaded (ScreenPositionHelper) 1`] = `
             "types": true,
           }
         }
-        organization="foo"
         query={
           Object {
             "activation": undefined,
@@ -167,7 +164,6 @@ exports[`should render correctly: loaded 1`] = `
                   },
                 }
               }
-              organization="foo"
               query={
                 Object {
                   "activation": undefined,
@@ -220,7 +216,6 @@ exports[`should render correctly: loaded 1`] = `
           onDeactivate={[Function]}
           onFilterChange={[Function]}
           onOpen={[Function]}
-          organization="foo"
           rule={
             Object {
               "key": "javascript:S1067",
@@ -249,7 +244,6 @@ exports[`should render correctly: loaded 1`] = `
           onDeactivate={[Function]}
           onFilterChange={[Function]}
           onOpen={[Function]}
-          organization="foo"
           rule={
             Object {
               "key": "javascript:S1067",
@@ -371,7 +365,6 @@ exports[`should render correctly: open rule (ScreenPositionHelper) 1`] = `
       />
       <FacetsList
         facets={Object {}}
-        hideProfileFacet={false}
         onFacetToggle={[Function]}
         onFilterChange={[Function]}
         openFacets={
@@ -384,7 +377,6 @@ exports[`should render correctly: open rule (ScreenPositionHelper) 1`] = `
             "types": true,
           }
         }
-        organization="foo"
         query={
           Object {
             "activation": undefined,
@@ -486,7 +478,6 @@ exports[`should render correctly: open rule 1`] = `
         <RuleDetails
           allowCustomRules={true}
           canWrite={true}
-          hideQualityProfiles={false}
           onActivate={[Function]}
           onDeactivate={[Function]}
           onDelete={[Function]}
@@ -559,7 +550,6 @@ exports[`should render correctly: using permalink 1`] = `
         <RuleDetails
           allowCustomRules={true}
           canWrite={true}
-          hideQualityProfiles={false}
           onActivate={[Function]}
           onDeactivate={[Function]}
           onDelete={[Function]}
index 83f37e7d7a474177335a331de109e5cc78120507..85aaa9b4e934ba379dfb2529a3f0b0386feecfef 100644 (file)
@@ -17,7 +17,6 @@ exports[`should render correctly 1`] = `
     onChange={[MockFunction]}
     onToggle={[MockFunction]}
     open={false}
-    organization="foo"
   />
   <Connect(RepositoryFacet)
     onChange={[MockFunction]}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/TagFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/TagFacet-test.tsx.snap
new file mode 100644 (file)
index 0000000..198a569
--- /dev/null
@@ -0,0 +1,49 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ListStyleFacet Renderers should include renderFacetItem 1`] = `
+<React.Fragment>
+  <TagsIcon
+    className="little-spacer-right"
+    fill="#999"
+  />
+  tag
+</React.Fragment>
+`;
+
+exports[`ListStyleFacet Renderers should include renderSearchResult 1`] = `
+<React.Fragment>
+  <TagsIcon
+    className="little-spacer-right"
+    fill="#999"
+  />
+  <React.Fragment>
+    my-
+    <mark>
+      tag
+    </mark>
+  </React.Fragment>
+</React.Fragment>
+`;
+
+exports[`should render correctly 1`] = `
+<ListStyleFacet
+  facetHeader="coding_rules.facet.tags"
+  fetching={false}
+  getFacetItemText={[Function]}
+  getSearchResultKey={[Function]}
+  getSearchResultText={[Function]}
+  maxInitialItems={15}
+  maxItems={100}
+  minSearchLength={2}
+  onChange={[MockFunction]}
+  onSearch={[Function]}
+  onToggle={[MockFunction]}
+  open={false}
+  property="tags"
+  renderFacetItem={[Function]}
+  renderSearchResult={[Function]}
+  searchPlaceholder="search.search_for_tags"
+  stats={Object {}}
+  values={Array []}
+/>
+`;
index 5f0105abe68fb534f00d122400cfa704f79eccfc..30cf699c5aea58ad73f081206ef52721157427c0 100644 (file)
@@ -38,7 +38,7 @@ function shallowRender(props?: Partial<Props>) {
     { branchLike: undefined, key: 'foo' },
     { branchLike: undefined, key: 'bar' }
   ];
-  const rules = [{ key: 'qux', organization: 'org' }];
+  const rules = [{ key: 'qux' }];
   return shallow(
     <WorkspaceNav
       components={components}
index 61aa0ff5943f9a1447c8b4b342f0ec934d7b6ec8..088b04486bda3cba44c21dc901a207bfc39444b7 100644 (file)
@@ -40,7 +40,7 @@ it('should open', () => {
 });
 
 function shallowRender(props?: Partial<Props>) {
-  const rule = { key: 'foo', organization: 'org' };
+  const rule = { key: 'foo' };
   return shallow(
     <WorkspaceNavRule onClose={jest.fn()} onOpen={jest.fn()} rule={rule} {...props} />
   );
index a2c2ec96100aa3a7f0a8818c12c2de16fa7a10f6..de39561ba1b1a73e4c1f96c1b82377f81092723c 100644 (file)
@@ -22,11 +22,11 @@ import * as React from 'react';
 import WorkspaceRuleTitle from '../WorkspaceRuleTitle';
 
 it('should render rule', () => {
-  const rule = { key: 'foo', organization: 'org' };
+  const rule = { key: 'foo' };
   expect(shallow(<WorkspaceRuleTitle rule={rule} />)).toMatchSnapshot();
 });
 
 it('should render loaded rule', () => {
-  const rule = { key: 'foo', name: 'Foo', organization: 'org' };
+  const rule = { key: 'foo', name: 'Foo' };
   expect(shallow(<WorkspaceRuleTitle rule={rule} />)).toMatchSnapshot();
 });
index f1a2ff035165ed97d5cc827daa34350bb0667223..9aacdd946e2db9b6c7e9c4223768de55485b2bad 100644 (file)
@@ -28,7 +28,7 @@ it('should render', () => {
 });
 
 it('should correctly mark the content as busy loading (aria)', () => {
-  const rule = { key: 'foo', name: 'Foo', organization: 'org' };
+  const rule = { key: 'foo', name: 'Foo' };
   const wrapper = shallowRender({ rule });
   const instance = wrapper.instance();
   const container = () => wrapper.find('.workspace-viewer-container');
@@ -40,7 +40,7 @@ it('should correctly mark the content as busy loading (aria)', () => {
   wrapper.update();
   expect(container().prop('aria-busy')).toBe(false);
 
-  const newRule = { key: 'bar', name: 'Bar', organization: 'org' };
+  const newRule = { key: 'bar', name: 'Bar' };
   wrapper.setProps({ rule: newRule }).update();
   expect(container().prop('aria-busy')).toBe(true);
 
@@ -66,7 +66,7 @@ it('should call back after load', () => {
 });
 
 function shallowRender(props?: Partial<Props>) {
-  const rule = { key: 'foo', name: 'Foo', organization: 'org' };
+  const rule = { key: 'foo', name: 'Foo' };
   return shallow<WorkspaceRuleViewer>(
     <WorkspaceRuleViewer
       height={300}
index 28dfed90df5ef3dc95386ff6314dfb931b500d62..be3c8da9dcf0f248bd71bf7af16cc6cac7c49e36 100644 (file)
@@ -25,7 +25,6 @@ exports[`should not render open component 1`] = `
       rule={
         Object {
           "key": "qux",
-          "organization": "org",
         }
       }
     />
@@ -102,7 +101,6 @@ exports[`should render 1`] = `
       rule={
         Object {
           "key": "qux",
-          "organization": "org",
         }
       }
     />
index 2855436401d927efb3bf0b33b6873374e1a7e18a..c51776335794479f42536da61931fdc65cd96d50 100644 (file)
@@ -10,7 +10,6 @@ exports[`should render 1`] = `
     rule={
       Object {
         "key": "foo",
-        "organization": "org",
       }
     }
   />
index d7d1534c5397cd5c2cd1a6e32b8f2ff76427ae58..507b6979b9fdea3f31b0045ec2cedbc52faaeed1 100644 (file)
@@ -16,7 +16,6 @@ exports[`should render 1`] = `
         Object {
           "key": "foo",
           "name": "Foo",
-          "organization": "org",
         }
       }
     />
diff --git a/server/sonar-web/src/main/js/types/coding-rules.ts b/server/sonar-web/src/main/js/types/coding-rules.ts
new file mode 100644 (file)
index 0000000..ddeba3b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.
+ */
+export interface GetRulesAppResponse {
+  canWrite?: boolean;
+  repositories: { key: string; language: string; name: string }[];
+}
+
+export interface SearchRulesResponse {
+  actives?: T.Dict<T.RuleActivation[]>;
+  facets?: { property: string; values: { count: number; val: string }[] }[];
+  p: number;
+  ps: number;
+  rules: T.Rule[];
+  total: number;
+}