Browse Source

SONAR-13999 Remove orgs from issues

tags/8.7.0.41497
Jeremy Davis 3 years ago
parent
commit
4d95e4f93f
69 changed files with 356 additions and 531 deletions
  1. 4
    24
      server/sonar-web/src/main/js/api/issues.ts
  2. 17
    53
      server/sonar-web/src/main/js/apps/issues/components/App.tsx
  3. 6
    40
      server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx
  4. 3
    12
      server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx
  5. 1
    20
      server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx
  6. 0
    2
      server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx
  7. 1
    6
      server/sonar-web/src/main/js/apps/issues/components/ListItem.tsx
  8. 3
    7
      server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx
  9. 9
    3
      server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx
  10. 6
    12
      server/sonar-web/src/main/js/apps/issues/components/__tests__/ComponentBreadcrumbs-test.tsx
  11. 0
    1
      server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx
  12. 0
    26
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/App-test.tsx.snap
  13. 0
    8
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap
  14. 0
    6
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap
  15. 0
    4
      server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesSourceViewer-test.tsx.snap
  16. 0
    2
      server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/ConciseIssue-test.tsx
  17. 0
    2
      server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssue-test.tsx.snap
  18. 0
    12
      server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap
  19. 0
    4
      server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueLocationsNavigator-test.tsx.snap
  20. 0
    2
      server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap
  21. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx
  22. 2
    3
      server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx
  23. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx
  24. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx
  25. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx
  26. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx
  27. 3
    4
      server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
  28. 9
    19
      server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
  29. 2
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx
  30. 2
    3
      server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx
  31. 4
    4
      server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/ProjectFacet-test.tsx
  32. 80
    0
      server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/RuleFacet-test.tsx
  33. 0
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx
  34. 30
    0
      server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/RuleFacet-test.tsx.snap
  35. 1
    26
      server/sonar-web/src/main/js/apps/issues/utils.ts
  36. 0
    4
      server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap
  37. 0
    2
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssuesList-test.tsx
  38. 0
    28
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap
  39. 0
    4
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap
  40. 0
    4
      server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssuesList-test.tsx.snap
  41. 0
    8
      server/sonar-web/src/main/js/components/issue/__tests__/__snapshots__/IssueView-test.tsx.snap
  42. 1
    1
      server/sonar-web/src/main/js/components/issue/actions.ts
  43. 1
    1
      server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx
  44. 2
    5
      server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx
  45. 6
    11
      server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx
  46. 2
    1
      server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx
  47. 2
    8
      server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx
  48. 0
    1
      server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx
  49. 2
    1
      server/sonar-web/src/main/js/components/issue/components/IssueType.tsx
  50. 7
    5
      server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.tsx
  51. 3
    2
      server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx
  52. 0
    38
      server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueActionsBar-test.tsx.snap
  53. 0
    21
      server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap
  54. 0
    2
      server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.tsx.snap
  55. 0
    11
      server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.tsx.snap
  56. 0
    1
      server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx
  57. 2
    3
      server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.tsx
  58. 1
    6
      server/sonar-web/src/main/js/components/issue/popups/__tests__/SetAssigneePopup-test.tsx
  59. 1
    3
      server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.tsx
  60. 7
    9
      server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx
  61. 1
    3
      server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/Workspace-test.tsx.snap
  62. 0
    1
      server/sonar-web/src/main/js/components/workspace/context.ts
  63. 12
    0
      server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts
  64. 1
    29
      server/sonar-web/src/main/js/helpers/issues.ts
  65. 28
    0
      server/sonar-web/src/main/js/helpers/mocks/issues.ts
  66. 0
    2
      server/sonar-web/src/main/js/helpers/testMocks.ts
  67. 2
    2
      server/sonar-web/src/main/js/helpers/urls.ts
  68. 82
    0
      server/sonar-web/src/main/js/types/issues.ts
  69. 0
    2
      server/sonar-web/src/main/js/types/types.d.ts

+ 4
- 24
server/sonar-web/src/main/js/api/issues.ts View File

@@ -20,27 +20,7 @@
import { getJSON, post, postJSON, RequestData } from 'sonar-ui-common/helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';
import getCoverageStatus from '../components/SourceViewer/helpers/getCoverageStatus';
import { RawIssue } from '../helpers/issues';

export interface IssueResponse {
components?: Array<{ key: string; name: string }>;
issue: RawIssue;
rules?: Array<{}>;
users?: Array<T.UserBase>;
}

interface IssuesResponse {
components?: { key: string; organization: string; name: string }[];
effortTotal: number;
facets: Array<{
property: string;
values: { count: number; val: string }[];
}>;
issues: RawIssue[];
paging: T.Paging;
rules?: Array<{}>;
users?: Array<T.UserBase>;
}
import { IssueResponse, RawIssuesResponse } from '../types/issues';

type FacetName =
| 'assigned_to_me'
@@ -63,7 +43,7 @@ type FacetName =
| 'tags'
| 'types';

export function searchIssues(query: RequestData): Promise<IssuesResponse> {
export function searchIssues(query: RequestData): Promise<RawIssuesResponse> {
return getJSON('/api/issues/search', query);
}

@@ -72,7 +52,7 @@ export function getFacets(
facets: FacetName[]
): Promise<{
facets: Array<{ property: string; values: T.FacetValue[] }>;
response: IssuesResponse;
response: RawIssuesResponse;
}> {
const data = {
...query,
@@ -88,7 +68,7 @@ export function getFacets(
export function getFacet(
query: RequestData,
facet: FacetName
): Promise<{ facet: { count: number; val: string }[]; response: IssuesResponse }> {
): Promise<{ facet: { count: number; val: string }[]; response: RawIssuesResponse }> {
return getFacets(query, [facet]).then(r => {
return { facet: r.facets[0].values, response: r.response };
});

+ 17
- 53
server/sonar-web/src/main/js/apps/issues/components/App.tsx View File

@@ -51,6 +51,13 @@ import {
} from '../../../helpers/branch-like';
import { isSonarCloud } from '../../../helpers/system';
import { BranchLike } from '../../../types/branch-like';
import {
Facet,
FetchIssuesPromise,
ReferencedComponent,
ReferencedLanguage,
ReferencedRule
} from '../../../types/issues';
import { SecurityStandard } from '../../../types/security';
import * as actions from '../actions';
import ConciseIssuesList from '../conciseIssuesList/ConciseIssuesList';
@@ -60,16 +67,11 @@ import '../styles.css';
import {
areMyIssuesSelected,
areQueriesEqual,
Facet,
getOpen,
mapFacet,
parseFacets,
parseQuery,
Query,
RawFacet,
ReferencedComponent,
ReferencedLanguage,
ReferencedRule,
saveMyIssues,
scrollToIssue,
serializeQuery,
@@ -86,28 +88,15 @@ import NoIssues from './NoIssues';
import NoMyIssues from './NoMyIssues';
import PageActions from './PageActions';

interface FetchIssuesPromise {
components: ReferencedComponent[];
effortTotal: number;
facets: RawFacet[];
issues: T.Issue[];
languages: ReferencedLanguage[];
paging: T.Paging;
rules: ReferencedRule[];
users: T.UserBase[];
}

interface Props {
branchLike?: BranchLike;
component?: T.Component;
currentUser: T.CurrentUser;
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
fetchIssues: (query: T.RawQuery, requestOrganizations?: boolean) => Promise<FetchIssuesPromise>;
fetchIssues: (query: T.RawQuery) => Promise<FetchIssuesPromise>;
location: Location;
onBranchesChange?: () => void;
organization?: { key: string };
router: Pick<Router, 'push' | 'replace'>;
userOrganizations: T.Organization[];
}

export interface State {
@@ -424,17 +413,12 @@ export default class App extends React.PureComponent<Props, State> {
.join(',')
: undefined;

const organizationKey =
(component && component.organization) ||
(this.props.organization && this.props.organization.key);

const parameters: T.Dict<string | undefined> = {
...getBranchLikeQuery(this.props.branchLike),
componentKeys: component && component.key,
s: 'FILE_LINE',
...serializeQuery(query),
ps: '100',
organization: organizationKey,
facets,
...additional
};
@@ -452,7 +436,7 @@ export default class App extends React.PureComponent<Props, State> {
Object.assign(parameters, { assignees: '__me__' });
}

return this.props.fetchIssues(parameters, false);
return this.props.fetchIssues(parameters);
};

fetchFirstIssues() {
@@ -630,7 +614,9 @@ export default class App extends React.PureComponent<Props, State> {
}));
}
},
() => {}
() => {
/* Do nothing */
}
);
};

@@ -701,27 +687,20 @@ export default class App extends React.PureComponent<Props, State> {
const { component } = this.props;
const { myIssues, query } = this.state;

const organizationKey =
(component && component.organization) ||
(this.props.organization && this.props.organization.key);

const parameters = {
...getBranchLikeQuery(this.props.branchLike),
componentKeys: component && component.key,
facets: mapFacet(property),
s: 'FILE_LINE',
...serializeQuery({ ...query, ...changes }),
ps: 1,
organization: organizationKey
ps: 1
};

if (myIssues) {
Object.assign(parameters, { assignees: '__me__' });
}

return this.props
.fetchIssues(parameters, false)
.then(({ facets }) => parseFacets(facets)[property]);
return this.props.fetchIssues(parameters).then(({ facets }) => parseFacets(facets)[property]);
};

closeFacet = (property: string) => {
@@ -918,7 +897,6 @@ export default class App extends React.PureComponent<Props, State> {
fetchIssues={checkAll ? this.fetchIssues : this.getCheckedIssues}
onClose={this.handleCloseBulkChange}
onDone={this.handleBulkChangeDone}
organization={this.props.organization}
/>
)}
</div>
@@ -926,20 +904,9 @@ export default class App extends React.PureComponent<Props, State> {
}

renderFacets() {
const { component, currentUser, userOrganizations, branchLike } = this.props;
const { component, currentUser, branchLike } = this.props;
const { query } = this.state;

const organizationKey =
(component && component.organization) ||
(this.props.organization && this.props.organization.key);

const userOrganization =
!isSonarCloud() ||
userOrganizations.find(o => {
return o.key === organizationKey;
});
const hideAuthorFacet = !userOrganization;

return (
<div className="layout-page-filters">
{currentUser.isLoggedIn && !isSonarCloud() && (
@@ -954,14 +921,12 @@ export default class App extends React.PureComponent<Props, State> {
component={component}
createdAfterIncludesTime={this.createdAfterIncludesTime()}
facets={this.state.facets}
hideAuthorFacet={hideAuthorFacet}
loadSearchResultCount={this.loadSearchResultCount}
loadingFacets={this.state.loadingFacets}
myIssues={this.state.myIssues}
onFacetToggle={this.handleFacetToggle}
onFilterChange={this.handleFilterChange}
openFacets={this.state.openFacets}
organization={this.props.organization}
query={query}
referencedComponentsById={this.state.referencedComponentsById}
referencedComponentsByKey={this.state.referencedComponentsByKey}
@@ -1029,7 +994,7 @@ export default class App extends React.PureComponent<Props, State> {
}

renderList() {
const { branchLike, component, currentUser, organization } = this.props;
const { branchLike, component, currentUser } = this.props;
const { issues, loading, loadingMore, openIssue, paging } = this.state;
const selectedIndex = this.getSelectedIndex();
const selectedIssue = selectedIndex !== undefined ? issues[selectedIndex] : undefined;
@@ -1063,7 +1028,6 @@ export default class App extends React.PureComponent<Props, State> {
onIssueClick={this.openIssue}
onPopupToggle={this.handlePopupToggle}
openPopup={this.state.openPopup}
organization={organization}
selectedIssue={selectedIssue}
/>
)}
@@ -1101,7 +1065,7 @@ export default class App extends React.PureComponent<Props, State> {

{this.renderBulkChange(openIssue)}
<PageActions
canSetHome={Boolean(!this.props.organization && !this.props.component)}
canSetHome={!this.props.component}
effortTotal={this.state.effortTotal}
onReload={this.handleReload}
paging={paging}

+ 6
- 40
server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx View File

@@ -17,53 +17,29 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { uniq } from 'lodash';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { searchIssues } from '../../../api/issues';
import { getOrganizations } from '../../../api/organizations';
import throwGlobalError from '../../../app/utils/throwGlobalError';
import { withRouter } from '../../../components/hoc/withRouter';
import { parseIssueFromResponse } from '../../../helpers/issues';
import { receiveOrganizations } from '../../../store/organizations';
import { fetchBranchStatus } from '../../../store/rootActions';
import {
areThereCustomOrganizations,
getCurrentUser,
getMyOrganizations,
Store
} from '../../../store/rootReducer';
import { getCurrentUser, Store } from '../../../store/rootReducer';
import { FetchIssuesPromise } from '../../../types/issues';

const IssuesAppContainer = lazyLoadComponent(() => import('./App'), 'IssuesAppContainer');

interface StateProps {
currentUser: T.CurrentUser;
userOrganizations: T.Organization[];
fetchIssues: (query: T.RawQuery) => Promise<FetchIssuesPromise>;
}

const mapStateToProps = (state: Store): StateProps => ({
currentUser: getCurrentUser(state),
userOrganizations: getMyOrganizations(state)
fetchIssues
});

const fetchIssueOrganizations = (organizationKeys: string[]) => (dispatch: Dispatch) => {
if (!organizationKeys.length) {
return Promise.resolve();
}

return getOrganizations({ organizations: organizationKeys.join() }).then(
response => dispatch(receiveOrganizations(response.organizations)),
throwGlobalError
);
};

const fetchIssues = (query: T.RawQuery, requestOrganizations = true) => (
// use `Function` to be able to do `dispatch(...).then(...)`
dispatch: Function,
getState: () => Store
) => {
const organizationsEnabled = areThereCustomOrganizations(getState());
const fetchIssues = (query: T.RawQuery) => {
return searchIssues({
...query,
additionalFields: '_all',
@@ -75,22 +51,12 @@ const fetchIssues = (query: T.RawQuery, requestOrganizations = true) => (
);
return { ...response, issues: parsedIssues };
})
.then(response => {
const organizationKeys = uniq([
...response.issues.map(issue => issue.organization),
...(response.components || []).map(component => component.organization)
]);
return organizationsEnabled && requestOrganizations
? dispatch(fetchIssueOrganizations(organizationKeys)).then(() => response)
: response;
})
.catch(throwGlobalError);
};

// have to type cast this, because of async action
const mapDispatchToProps = {
fetchBranchStatus: fetchBranchStatus as any,
fetchIssues: fetchIssues as any
fetchBranchStatus: fetchBranchStatus as any
};

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IssuesAppContainer));

+ 3
- 12
server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx View File

@@ -56,7 +56,6 @@ interface Props {
fetchIssues: (x: {}) => Promise<{ issues: T.Issue[]; paging: T.Paging }>;
onClose: () => void;
onDone: () => void;
organization: { key: string } | undefined;
}

interface FormFields {
@@ -64,7 +63,6 @@ interface FormFields {
assignee?: AssigneeOption;
comment?: string;
notifications?: boolean;
organization?: string;
removeTags?: Array<{ label: string; value: string }>;
severity?: string;
transition?: string;
@@ -94,20 +92,13 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {

constructor(props: Props) {
super(props);
let organization = props.component && props.component.organization;
if (props.organization && !organization) {
organization = props.organization.key;
}
this.state = { initialTags: [], issues: [], loading: true, submitting: false, organization };
this.state = { initialTags: [], issues: [], loading: true, submitting: false };
}

componentDidMount() {
this.mounted = true;

Promise.all([
this.loadIssues(),
searchIssueTags({ organization: this.state.organization })
]).then(
Promise.all([this.loadIssues(), searchIssueTags({})]).then(
([{ issues, paging }, tags]) => {
if (this.mounted) {
if (issues.length > MAX_PAGE_SIZE) {
@@ -178,7 +169,7 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> {
};

handleTagsSearch = (query: string) => {
return searchIssueTags({ organization: this.state.organization, q: query }).then(tags =>
return searchIssueTags({ q: query }).then(tags =>
tags.map(tag => ({ label: tag, value: tag }))
);
};

+ 1
- 20
server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx View File

@@ -20,26 +20,12 @@
import * as React from 'react';
import QualifierIcon from 'sonar-ui-common/components/icons/QualifierIcon';
import { collapsePath, limitComponentName } from 'sonar-ui-common/helpers/path';
import Organization from '../../../components/shared/Organization';
import { getSelectedLocation } from '../utils';

interface Props {
component?: T.Component;
issue: Pick<
T.Issue,
| 'component'
| 'componentLongName'
| 'componentQualifier'
| 'flows'
| 'organization'
| 'project'
| 'projectName'
| 'secondaryLocations'
| 'subProject'
| 'subProjectName'
>;
issue: T.Issue;
link?: boolean;
organization: { key: string } | undefined;
selectedFlowIndex?: number;
selectedLocationIndex?: number;
}
@@ -47,12 +33,9 @@ interface Props {
export default function ComponentBreadcrumbs({
component,
issue,
organization,
selectedFlowIndex,
selectedLocationIndex
}: Props) {
const displayOrganization =
!organization && (!component || ['VW', 'SVW'].includes(component.qualifier));
const displayProject = !component || !['TRK', 'BRC', 'DIR'].includes(component.qualifier);
const displaySubProject = !component || !['BRC', 'DIR'].includes(component.qualifier);

@@ -63,8 +46,6 @@ export default function ComponentBreadcrumbs({
<div className="component-name text-ellipsis">
<QualifierIcon className="spacer-right" qualifier={issue.componentQualifier} />

{displayOrganization && <Organization link={false} organizationKey={issue.organization} />}

{displayProject && (
<span title={issue.projectName}>
{limitComponentName(issue.projectName)}

+ 0
- 2
server/sonar-web/src/main/js/apps/issues/components/IssuesList.tsx View File

@@ -33,7 +33,6 @@ interface Props {
onIssueClick: (issueKey: string) => void;
onPopupToggle: (issue: string, popupName: string, open?: boolean) => void;
openPopup: { issue: string; name: string } | undefined;
organization: { key: string } | undefined;
selectedIssue: T.Issue | undefined;
}

@@ -85,7 +84,6 @@ export default class IssuesList extends React.PureComponent<Props, State> {
onFilterChange={this.props.onFilterChange}
onPopupToggle={this.props.onPopupToggle}
openPopup={openPopup && openPopup.issue === issue.key ? openPopup.name : undefined}
organization={this.props.organization}
previousIssue={index > 0 ? issues[index - 1] : undefined}
selected={selectedIssue != null && selectedIssue.key === issue.key}
/>

+ 1
- 6
server/sonar-web/src/main/js/apps/issues/components/ListItem.tsx View File

@@ -34,7 +34,6 @@ interface Props {
onFilterChange: (changes: Partial<Query>) => void;
onPopupToggle: (issue: string, popupName: string, open?: boolean) => void;
openPopup: string | undefined;
organization: { key: string } | undefined;
previousIssue: T.Issue | undefined;
selected: boolean;
}
@@ -99,11 +98,7 @@ export default class ListItem extends React.PureComponent<Props> {
<div className="issues-workspace-list-item">
{displayComponent && (
<div className="issues-workspace-list-component note">
<ComponentBreadcrumbs
component={component}
issue={this.props.issue}
organization={this.props.organization}
/>
<ComponentBreadcrumbs component={component} issue={this.props.issue} />
</div>
)}
<Issue

+ 3
- 7
server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx View File

@@ -71,7 +71,7 @@ const ISSUES = [
const FACETS = [{ property: 'severities', values: [{ val: 'MINOR', count: 4 }] }];
const PAGING = { pageIndex: 1, pageSize: 100, total: 4 };

const referencedComponent = { key: 'foo-key', name: 'bar', organization: 'John', uuid: 'foo-uuid' };
const referencedComponent = { key: 'foo-key', name: 'bar', uuid: 'foo-uuid' };

it('should render a list of issue', async () => {
const wrapper = shallowRender();
@@ -393,13 +393,12 @@ it('should handle createAfter query param with time', async () => {

wrapper.instance().fetchIssues({});
expect(fetchIssues).toBeCalledWith(
expect.objectContaining({ createdAfter: '2020-10-21T17:21:00+0000' }),
false
expect.objectContaining({ createdAfter: '2020-10-21T17:21:00+0000' })
);
});

function fetchIssuesMockFactory(keyCount = 0, lineCount = 1) {
return jest.fn().mockImplementation(({ p }: any) =>
return jest.fn().mockImplementation(({ p }: { p: number }) =>
Promise.resolve({
components: [referencedComponent],
effortTotal: 1,
@@ -439,7 +438,6 @@ function shallowRender(props: Partial<App['props']> = {}) {
breadcrumbs: [],
key: 'foo',
name: 'bar',
organization: 'John',
qualifier: 'Doe'
}}
currentUser={mockLoggedInUser()}
@@ -456,9 +454,7 @@ function shallowRender(props: Partial<App['props']> = {}) {
})}
location={mockLocation({ pathname: '/issues', query: {} })}
onBranchesChange={() => {}}
organization={{ key: 'foo' }}
router={mockRouter()}
userOrganizations={[]}
{...props}
/>
);

+ 9
- 3
server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx View File

@@ -20,15 +20,16 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { searchIssueTags } from '../../../../api/issues';
import { mockIssue } from '../../../../helpers/testMocks';
import BulkChangeModal, { MAX_PAGE_SIZE } from '../BulkChangeModal';

jest.mock('../../../../api/issues', () => ({
searchIssueTags: () => Promise.resolve([undefined, []])
searchIssueTags: jest.fn().mockResolvedValue([undefined, []])
}));

jest.mock('../BulkChangeModal', () => {
const mock = require.requireActual('../BulkChangeModal');
const mock = jest.requireActual('../BulkChangeModal');
mock.MAX_PAGE_SIZE = 1;
return mock;
});
@@ -92,6 +93,12 @@ it('should properly handle the search for assignee', async () => {
expect(result).toMatchSnapshot();
});

it('should properly handle the search for tags', async () => {
const wrapper = getWrapper([]);
await wrapper.instance().handleTagsSearch('query');
expect(searchIssueTags).toBeCalled();
});

const getWrapper = (issues: T.Issue[]) => {
return shallow<BulkChangeModal>(
<BulkChangeModal
@@ -109,7 +116,6 @@ const getWrapper = (issues: T.Issue[]) => {
}
onClose={() => {}}
onDone={() => {}}
organization={undefined}
/>
);
};

+ 6
- 12
server/sonar-web/src/main/js/apps/issues/components/__tests__/ComponentBreadcrumbs-test.tsx View File

@@ -19,31 +19,25 @@
*/
import { shallow } from 'enzyme';
import * as React from 'react';
import { mockIssue } from '../../../../helpers/testMocks';
import { ComponentQualifier } from '../../../../types/component';
import ComponentBreadcrumbs from '../ComponentBreadcrumbs';

const baseIssue = {
const baseIssue = mockIssue(false, {
component: 'comp',
componentLongName: 'comp-name',
componentQualifier: ComponentQualifier.File,
flows: [],
organization: 'org',
project: 'proj',
projectName: 'proj-name',
secondaryLocations: []
};
projectName: 'proj-name'
});

it('renders', () => {
expect(
shallow(
<ComponentBreadcrumbs component={undefined} issue={baseIssue} organization={undefined} />
)
shallow(<ComponentBreadcrumbs component={undefined} issue={baseIssue} />)
).toMatchSnapshot();
});

it('renders with sub-project', () => {
const issue = { ...baseIssue, subProject: 'sub-proj', subProjectName: 'sub-proj-name' };
expect(
shallow(<ComponentBreadcrumbs component={undefined} issue={issue} organization={undefined} />)
).toMatchSnapshot();
expect(shallow(<ComponentBreadcrumbs component={undefined} issue={issue} />)).toMatchSnapshot();
});

+ 0
- 1
server/sonar-web/src/main/js/apps/issues/components/__tests__/IssuesList-test.tsx View File

@@ -46,7 +46,6 @@ function shallowRender(overrides: Partial<IssuesList['props']> = {}) {
onIssueClick={jest.fn()}
onPopupToggle={jest.fn()}
openPopup={undefined}
organization={undefined}
selectedIssue={undefined}
{...overrides}
/>

+ 0
- 26
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/App-test.tsx.snap View File

@@ -103,7 +103,6 @@ exports[`should switch to source view if an issue is selected 1`] = `
"breadcrumbs": Array [],
"key": "foo",
"name": "bar",
"organization": "John",
"qualifier": "Doe",
}
}
@@ -121,11 +120,9 @@ exports[`should switch to source view if an issue is selected 1`] = `
"key": "foo",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -152,11 +149,9 @@ exports[`should switch to source view if an issue is selected 1`] = `
"key": "bar",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -233,11 +228,9 @@ exports[`should switch to source view if an issue is selected 1`] = `
"key": "third",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -283,11 +276,9 @@ exports[`should switch to source view if an issue is selected 1`] = `
"key": "fourth",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -309,11 +300,6 @@ exports[`should switch to source view if an issue is selected 1`] = `
onIssueCheck={[Function]}
onIssueClick={[Function]}
onPopupToggle={[Function]}
organization={
Object {
"key": "foo",
}
}
selectedIssue={
Object {
"actions": Array [],
@@ -327,11 +313,9 @@ exports[`should switch to source view if an issue is selected 1`] = `
"key": "foo",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -403,11 +387,9 @@ exports[`should switch to source view if an issue is selected 2`] = `
"key": "foo",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -434,11 +416,9 @@ exports[`should switch to source view if an issue is selected 2`] = `
"key": "bar",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -515,11 +495,9 @@ exports[`should switch to source view if an issue is selected 2`] = `
"key": "third",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -565,11 +543,9 @@ exports[`should switch to source view if an issue is selected 2`] = `
"key": "fourth",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -654,11 +630,9 @@ exports[`should switch to source view if an issue is selected 2`] = `
"key": "third",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [

+ 0
- 8
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/ComponentBreadcrumbs-test.tsx.snap View File

@@ -8,10 +8,6 @@ exports[`renders 1`] = `
className="spacer-right"
qualifier="FIL"
/>
<Connect(Organization)
link={false}
organizationKey="org"
/>
<span
title="proj-name"
>
@@ -36,10 +32,6 @@ exports[`renders with sub-project 1`] = `
className="spacer-right"
qualifier="FIL"
/>
<Connect(Organization)
link={false}
organizationKey="org"
/>
<span
title="proj-name"
>

+ 0
- 6
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesList-test.tsx.snap View File

@@ -25,11 +25,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -68,11 +66,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN3",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -107,11 +103,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 4
server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/IssuesSourceViewer-test.tsx.snap View File

@@ -77,11 +77,9 @@ exports[`should render CrossComponentSourceViewer correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -180,11 +178,9 @@ exports[`should render CrossComponentSourceViewer correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [

+ 0
- 2
server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/ConciseIssue-test.tsx View File

@@ -32,11 +32,9 @@ const issue: T.Issue = {
fromHotspot: false,
key: '',
message: '',
organization: '',
project: '',
projectKey: '',
projectName: '',
projectOrganization: '',
rule: '',
ruleName: '',
secondaryLocations: [],

+ 0
- 2
server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssue-test.tsx.snap View File

@@ -18,11 +18,9 @@ exports[`should render 1`] = `
"fromHotspot": false,
"key": "",
"message": "",
"organization": "",
"project": "",
"projectKey": "",
"projectName": "",
"projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],

+ 0
- 12
server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueBox-test.tsx.snap View File

@@ -33,11 +33,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -71,11 +69,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -110,11 +106,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -217,11 +211,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -324,11 +316,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -432,11 +422,9 @@ exports[`should render correctly 2`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [

+ 0
- 4
server/sonar-web/src/main/js/apps/issues/conciseIssuesList/__tests__/__snapshots__/ConciseIssueLocationsNavigator-test.tsx.snap View File

@@ -40,11 +40,9 @@ exports[`should render flow locations in different file 1`] = `
"key": "",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -211,11 +209,9 @@ exports[`should render taint analysis issues correctly 1`] = `
"key": "",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 2
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/__snapshots__/CrossComponentSourceViewerWrapper-test.tsx.snap View File

@@ -111,11 +111,9 @@ exports[`should render correctly 2`] = `
"key": "1",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.tsx View File

@@ -24,7 +24,8 @@ import { highlightTerm } from 'sonar-ui-common/helpers/search';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import Avatar from '../../../components/ui/Avatar';
import { isUserActive } from '../../../helpers/users';
import { Facet, Query, searchAssignees } from '../utils';
import { Facet } from '../../../types/issues';
import { Query, searchAssignees } from '../utils';

interface Props {
assigned: boolean;

+ 2
- 3
server/sonar-web/src/main/js/apps/issues/sidebar/AuthorFacet.tsx View File

@@ -23,7 +23,8 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { highlightTerm } from 'sonar-ui-common/helpers/search';
import { searchIssueAuthors } from '../../../api/issues';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { Facet, Query } from '../utils';
import { Facet } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
component: T.Component | undefined;
@@ -32,7 +33,6 @@ interface Props {
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
organization: string | undefined;
query: Query;
stats: T.Dict<number> | undefined;
authors: string[];
@@ -50,7 +50,6 @@ export default class AuthorFacet extends React.PureComponent<Props> {
const project =
component && ['TRK', 'VW', 'APP'].includes(component.qualifier) ? component.key : undefined;
return searchIssueAuthors({
organization: this.props.organization,
project,
ps: SEARCH_SIZE, // maximum
q: query

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx View File

@@ -28,7 +28,8 @@ import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { BranchLike } from '../../../types/branch-like';
import { TreeComponentWithPath } from '../../../types/component';
import { Facet, Query } from '../utils';
import { Facet } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
branchLike?: BranchLike;

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/FileFacet.tsx View File

@@ -29,7 +29,8 @@ import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { BranchLike } from '../../../types/branch-like';
import { TreeComponentWithPath } from '../../../types/component';
import { Facet, Query } from '../utils';
import { Facet } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
branchLike?: BranchLike;

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/LanguageFacet.tsx View File

@@ -24,7 +24,8 @@ import { translate } from 'sonar-ui-common/helpers/l10n';
import { highlightTerm } from 'sonar-ui-common/helpers/search';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { getLanguages, Store } from '../../../store/rootReducer';
import { Facet, Query, ReferencedLanguage } from '../utils';
import { Facet, ReferencedLanguage } from '../../../types/issues';
import { Query } from '../utils';

interface InstalledLanguage {
key: string;

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/ProjectFacet.tsx View File

@@ -25,7 +25,8 @@ import { highlightTerm } from 'sonar-ui-common/helpers/search';
import { getTree, searchProjects } from '../../../api/components';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { ComponentQualifier } from '../../../types/component';
import { Facet, Query, ReferencedComponent } from '../utils';
import { Facet, ReferencedComponent } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
component: T.Component | undefined;

+ 3
- 4
server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx View File

@@ -22,7 +22,8 @@ import * as React from 'react';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { searchRules } from '../../../api/rules';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { Facet, Query, ReferencedRule } from '../utils';
import { Facet, ReferencedRule } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
fetching: boolean;
@@ -31,7 +32,6 @@ interface Props {
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
organization: string | undefined;
query: Query;
referencedRules: T.Dict<ReferencedRule>;
rules: string[];
@@ -40,11 +40,10 @@ interface Props {

export default class RuleFacet extends React.PureComponent<Props> {
handleSearch = (query: string, page = 1) => {
const { languages, organization } = this.props;
const { languages } = this.props;
return searchRules({
f: 'name,langName',
languages: languages.length ? languages.join() : undefined,
organization,
q: query,
p: page,
ps: 30,

+ 9
- 19
server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx View File

@@ -22,7 +22,13 @@ import { connect } from 'react-redux';
import { getGlobalSettingValue, Store } from '../../../store/rootReducer';
import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier } from '../../../types/component';
import { Facet, Query, ReferencedComponent, ReferencedLanguage, ReferencedRule } from '../utils';
import {
Facet,
ReferencedComponent,
ReferencedLanguage,
ReferencedRule
} from '../../../types/issues';
import { Query } from '../utils';
import AssigneeFacet from './AssigneeFacet';
import AuthorFacet from './AuthorFacet';
import CreationDateFacet from './CreationDateFacet';
@@ -44,14 +50,12 @@ export interface Props {
component: T.Component | undefined;
createdAfterIncludesTime: boolean;
facets: T.Dict<Facet | undefined>;
hideAuthorFacet?: boolean;
loadSearchResultCount: (property: string, changes: Partial<Query>) => Promise<Facet>;
loadingFacets: T.Dict<boolean>;
myIssues: boolean;
onFacetToggle: (property: string) => void;
onFilterChange: (changes: Partial<Query>) => void;
openFacets: T.Dict<boolean>;
organization: { key: string } | undefined;
query: Query;
referencedComponentsById: T.Dict<ReferencedComponent>;
referencedComponentsByKey: T.Dict<ReferencedComponent>;
@@ -99,22 +103,11 @@ export class Sidebar extends React.PureComponent<Props> {
}

render() {
const {
component,
createdAfterIncludesTime,
facets,
hideAuthorFacet,
openFacets,
query
} = this.props;
const { component, createdAfterIncludesTime, facets, openFacets, query } = this.props;

const displayProjectsFacet =
!component || !['TRK', 'BRC', 'DIR', 'DEV_PRJ'].includes(component.qualifier);
const displayAuthorFacet = !hideAuthorFacet && (!component || component.qualifier !== 'DEV');

const organizationKey =
(component && component.organization) ||
(this.props.organization && this.props.organization.key);
const displayAuthorFacet = !component || component.qualifier !== 'DEV';

return (
<>
@@ -214,7 +207,6 @@ export class Sidebar extends React.PureComponent<Props> {
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.rules}
organization={organizationKey}
query={query}
referencedRules={this.props.referencedRules}
rules={query.rules}
@@ -227,7 +219,6 @@ export class Sidebar extends React.PureComponent<Props> {
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.tags}
organization={organizationKey}
query={query}
stats={facets.tags}
tags={query.tags}
@@ -270,7 +261,6 @@ export class Sidebar extends React.PureComponent<Props> {
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.authors}
organization={organizationKey}
query={query}
stats={facets.authors}
/>

+ 2
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx View File

@@ -34,8 +34,9 @@ import {
renderSansTop25Category,
renderSonarSourceSecurityCategory
} from '../../../helpers/security-standard';
import { Facet } from '../../../types/issues';
import { SecurityStandard, Standards, StandardType } from '../../../types/security';
import { Facet, formatFacetStat, Query, STANDARDS } from '../utils';
import { formatFacetStat, Query, STANDARDS } from '../utils';

interface Props {
cwe: string[];

+ 2
- 3
server/sonar-web/src/main/js/apps/issues/sidebar/TagFacet.tsx View File

@@ -25,7 +25,8 @@ import { highlightTerm } from 'sonar-ui-common/helpers/search';
import { searchIssueTags } from '../../../api/issues';
import { colors } from '../../../app/theme';
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import { Facet, Query } from '../utils';
import { Facet } from '../../../types/issues';
import { Query } from '../utils';

interface Props {
component: T.Component | undefined;
@@ -34,7 +35,6 @@ interface Props {
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
organization: string | undefined;
query: Query;
stats: T.Dict<number> | undefined;
tags: string[];
@@ -48,7 +48,6 @@ export default class TagFacet extends React.PureComponent<Props> {
const project =
component && ['TRK', 'VW', 'APP'].includes(component.qualifier) ? component.key : undefined;
return searchIssueTags({
organization: this.props.organization,
project,
ps: SEARCH_SIZE,
q: query

+ 4
- 4
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/ProjectFacet-test.tsx View File

@@ -23,7 +23,8 @@ import * as React from 'react';
import { getTree, searchProjects } from '../../../../api/components';
import { mockComponent } from '../../../../helpers/testMocks';
import { ComponentQualifier } from '../../../../types/component';
import { Query, ReferencedComponent } from '../../utils';
import { ReferencedComponent } from '../../../../types/issues';
import { Query } from '../../utils';
import ProjectFacet from '../ProjectFacet';

jest.mock('../../../../api/components', () => ({
@@ -31,7 +32,6 @@ jest.mock('../../../../api/components', () => ({
searchProjects: jest.fn().mockResolvedValue({
components: [],
facets: [],
organizations: [],
paging: {}
})
}));
@@ -77,8 +77,8 @@ it('should handle search for projects in portfolio', async () => {

describe("ListStyleFacet's renderers", () => {
const components: ReferencedComponent[] = [
{ key: 'projectKey', name: 'First Project Name', organization: '', uuid: '141324' },
{ key: 'projectKey2', name: 'Second Project Name', organization: '', uuid: '643878' }
{ key: 'projectKey', name: 'First Project Name', uuid: '141324' },
{ key: 'projectKey2', name: 'Second Project Name', uuid: '643878' }
];
const referencedComponents = keyBy(components, c => c.key);
const wrapper = shallowRender({ referencedComponents });

+ 80
- 0
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/RuleFacet-test.tsx View File

@@ -0,0 +1,80 @@
/*
* 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 { searchRules } from '../../../../api/rules';
import { mockReferencedRule } from '../../../../helpers/mocks/issues';
import { mockRule } from '../../../../helpers/testMocks';
import { Query } from '../../utils';
import RuleFacet from '../RuleFacet';

jest.mock('../../../../api/rules', () => ({
searchRules: 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(searchRules).toBeCalledWith(expect.objectContaining({ languages: 'js,java', q: query }));
});

describe('ListStyleFacet Renderers', () => {
const referencedRules = { r1: mockReferencedRule() };
const instance = shallowRender({ referencedRules }).instance();

it('should include renderFacetItem', () => {
const rule = referencedRules.r1;
expect(instance.getRuleName('r1')).toBe(`(${rule.langName}) ${rule.name}`);
expect(instance.getRuleName('nonexistent')).toBe('nonexistent');
});

it('should include renderSearchResult', () => {
const rule = mockRule();
expect(instance.renderSearchResult(rule)).toBe(`(${rule.langName}) ${rule.name}`);
expect(instance.renderSearchResult(mockRule({ langName: '' }))).toBe(rule.name);
});
});

function shallowRender(props: Partial<RuleFacet['props']> = {}) {
return shallow<RuleFacet>(
<RuleFacet
fetching={true}
languages={['js', 'java']}
loadSearchResultCount={jest.fn()}
onChange={jest.fn()}
onToggle={jest.fn()}
open={false}
query={{} as Query}
referencedRules={{}}
rules={['r1']}
stats={{}}
{...props}
/>
);
}

+ 0
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/Sidebar-test.tsx View File

@@ -85,7 +85,6 @@ const renderSidebar = (props?: Partial<Sidebar['props']>) => {
onFacetToggle={jest.fn()}
onFilterChange={jest.fn()}
openFacets={{}}
organization={undefined}
query={{ types: [''] } as Query}
referencedComponentsById={{}}
referencedComponentsByKey={{}}

+ 30
- 0
server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/RuleFacet-test.tsx.snap View File

@@ -0,0 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<ListStyleFacet
facetHeader="issues.facet.rules"
fetching={true}
getFacetItemText={[Function]}
getSearchResultKey={[Function]}
getSearchResultText={[Function]}
loadSearchResultCount={[Function]}
maxInitialItems={15}
maxItems={100}
minSearchLength={2}
onChange={[MockFunction]}
onSearch={[Function]}
onToggle={[MockFunction]}
open={false}
property="rules"
query={Object {}}
renderFacetItem={[Function]}
renderSearchResult={[Function]}
searchPlaceholder="search.search_for_rules"
stats={Object {}}
values={
Array [
"r1",
]
}
/>
`;

+ 1
- 26
server/sonar-web/src/main/js/apps/issues/utils.ts View File

@@ -32,6 +32,7 @@ import {
import { scrollToElement } from 'sonar-ui-common/helpers/scrolling';
import { get, save } from 'sonar-ui-common/helpers/storage';
import { searchUsers } from '../../api/users';
import { Facet, RawFacet } from '../../types/issues';
import { SecurityStandard, StandardType } from '../../types/security';

export interface Query {
@@ -150,15 +151,6 @@ export function serializeQuery(query: Query): T.RawQuery {
export const areQueriesEqual = (a: T.RawQuery, b: T.RawQuery) =>
queriesEqual(parseQuery(a), parseQuery(b));

export interface RawFacet {
property: string;
values: Array<{ val: string; count: number }>;
}

export interface Facet {
[value: string]: number;
}

export function mapFacet(facet: string) {
const propertyMapping: T.Dict<string> = {
modules: 'moduleUuids'
@@ -192,23 +184,6 @@ export function formatFacetStat(stat: number | undefined) {
return stat && formatMeasure(stat, 'SHORT_INT');
}

export interface ReferencedComponent {
key: string;
name: string;
organization: string;
path?: string;
uuid: string;
}

export interface ReferencedLanguage {
name: string;
}

export interface ReferencedRule {
langName?: string;
name: string;
}

export const searchAssignees = (
query: string,
page = 1

+ 0
- 4
server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerBase-test.tsx.snap View File

@@ -84,11 +84,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -120,11 +118,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 2
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/LineIssuesList-test.tsx View File

@@ -32,10 +32,8 @@ const issueBase: T.Issue = {
flows: [],
fromHotspot: false,
message: '',
organization: '',
project: '',
projectName: '',
projectOrganization: '',
projectKey: '',
rule: '',
ruleName: '',

+ 0
- 28
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/Line-test.tsx.snap View File

@@ -65,11 +65,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -96,11 +94,9 @@ exports[`should render correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -207,11 +203,9 @@ exports[`should render correctly for last, new, and highlighted lines 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -238,11 +232,9 @@ exports[`should render correctly for last, new, and highlighted lines 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -364,11 +356,9 @@ exports[`should render correctly with coverage 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -395,11 +385,9 @@ exports[`should render correctly with coverage 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -567,11 +555,9 @@ exports[`should render correctly with duplication information 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -598,11 +584,9 @@ exports[`should render correctly with duplication information 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -694,11 +678,9 @@ exports[`should render correctly with issues info 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -725,11 +707,9 @@ exports[`should render correctly with issues info 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -789,11 +769,9 @@ exports[`should render correctly with issues info 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -820,11 +798,9 @@ exports[`should render correctly with issues info 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -916,11 +892,9 @@ exports[`should render correctly: no SCM 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -947,11 +921,9 @@ exports[`should render correctly: no SCM 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 4
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineCode-test.tsx.snap View File

@@ -64,11 +64,9 @@ exports[`render code 1`] = `
"key": "issue-1",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -95,11 +93,9 @@ exports[`render code 1`] = `
"key": "issue-2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 4
server/sonar-web/src/main/js/components/SourceViewer/components/__tests__/__snapshots__/LineIssuesList-test.tsx.snap View File

@@ -17,11 +17,9 @@ exports[`render issues list 1`] = `
"fromHotspot": false,
"key": "foo",
"message": "",
"organization": "",
"project": "",
"projectKey": "",
"projectName": "",
"projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],
@@ -50,11 +48,9 @@ exports[`render issues list 1`] = `
"fromHotspot": false,
"key": "bar",
"message": "",
"organization": "",
"project": "",
"projectKey": "",
"projectName": "",
"projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],

+ 0
- 8
server/sonar-web/src/main/js/components/issue/__tests__/__snapshots__/IssueView-test.tsx.snap View File

@@ -22,11 +22,9 @@ exports[`should render hotspots correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -58,11 +56,9 @@ exports[`should render hotspots correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -121,11 +117,9 @@ exports[`should render issues correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -171,11 +165,9 @@ exports[`should render issues correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 1
- 1
server/sonar-web/src/main/js/components/issue/actions.ts View File

@@ -17,9 +17,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { IssueResponse } from '../../api/issues';
import throwGlobalError from '../../app/utils/throwGlobalError';
import { parseIssueFromResponse } from '../../helpers/issues';
import { IssueResponse } from '../../types/issues';

export const updateIssue = (
onChange: (issue: T.Issue) => void,

+ 1
- 1
server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx View File

@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { IssueResponse } from '../../../api/issues';
import { IssueResponse } from '../../../types/issues';
import { updateIssue } from '../actions';
import IssueAssign from './IssueAssign';
import IssueCommentAction from './IssueCommentAction';

+ 2
- 5
server/sonar-web/src/main/js/components/issue/components/IssueAssign.tsx View File

@@ -27,10 +27,7 @@ import SetAssigneePopup from '../popups/SetAssigneePopup';

interface Props {
isOpen: boolean;
issue: Pick<
T.Issue,
'assignee' | 'assigneeActive' | 'assigneeAvatar' | 'assigneeName' | 'projectOrganization'
>;
issue: T.Issue;
canAssign: boolean;
onAssign: (login: string) => void;
togglePopup: (popup: string, show?: boolean) => void;
@@ -80,7 +77,7 @@ export default class IssueAssign extends React.PureComponent<Props> {
closeOnEscape={true}
onRequestClose={this.handleClose}
open={this.props.isOpen && this.props.canAssign}
overlay={<SetAssigneePopup issue={this.props.issue} onSelect={this.props.onAssign} />}>
overlay={<SetAssigneePopup onSelect={this.props.onAssign} />}>
<ButtonLink
className="issue-action issue-action-with-options js-issue-assign"
onClick={this.toggleAssign}>

+ 6
- 11
server/sonar-web/src/main/js/components/issue/components/IssueMessage.tsx View File

@@ -31,21 +31,12 @@ export interface IssueMessageProps {
manualVulnerability: boolean;
message: string;
onOpenRule: WorkspaceContextShape['openRule'];
organization: string;
ruleKey: string;
ruleStatus?: RuleStatus;
}

export default function IssueMessage(props: IssueMessageProps) {
const {
engine,
engineName,
manualVulnerability,
message,
organization,
ruleKey,
ruleStatus
} = props;
const { engine, engineName, manualVulnerability, message, ruleKey, ruleStatus } = props;
const ruleEngine = engineName ? engineName : engine;

return (
@@ -54,7 +45,11 @@ export default function IssueMessage(props: IssueMessageProps) {
<ButtonLink
aria-label={translate('issue.why_this_issue.long')}
className="issue-see-rule spacer-right text-baseline"
onClick={() => props.onOpenRule({ key: ruleKey, organization })}>
onClick={() =>
props.onOpenRule({
key: ruleKey
})
}>
{translate('issue.why_this_issue')}
</ButtonLink>


+ 2
- 1
server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx View File

@@ -21,7 +21,8 @@ import * as React from 'react';
import { ButtonLink } from 'sonar-ui-common/components/controls/buttons';
import Toggler from 'sonar-ui-common/components/controls/Toggler';
import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import { IssueResponse, setIssueSeverity } from '../../../api/issues';
import { setIssueSeverity } from '../../../api/issues';
import { IssueResponse } from '../../../types/issues';
import SeverityHelper from '../../shared/SeverityHelper';
import SetSeverityPopup from '../popups/SetSeverityPopup';


+ 2
- 8
server/sonar-web/src/main/js/components/issue/components/IssueTags.tsx View File

@@ -29,7 +29,7 @@ import SetIssueTagsPopup from '../popups/SetIssueTagsPopup';
interface Props {
canSetTags: boolean;
isOpen: boolean;
issue: Pick<T.Issue, 'key' | 'projectOrganization' | 'tags'>;
issue: Pick<T.Issue, 'key' | 'tags'>;
onChange: (issue: T.Issue) => void;
togglePopup: (popup: string, show?: boolean) => void;
}
@@ -64,13 +64,7 @@ export default class IssueTags extends React.PureComponent<Props> {
<Toggler
onRequestClose={this.handleClose}
open={this.props.isOpen}
overlay={
<SetIssueTagsPopup
organization={issue.projectOrganization}
selectedTags={tags}
setTags={this.setTags}
/>
}>
overlay={<SetIssueTagsPopup selectedTags={tags} setTags={this.setTags} />}>
<ButtonLink
className="issue-action issue-action-with-options js-issue-edit-tags"
onClick={this.toggleSetTags}>

+ 0
- 1
server/sonar-web/src/main/js/components/issue/components/IssueTitleBar.tsx View File

@@ -84,7 +84,6 @@ export default function IssueTitleBar(props: IssueTitleBarProps) {
manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'}
message={issue.message}
onOpenRule={openRule}
organization={issue.organization}
ruleKey={issue.rule}
ruleStatus={issue.ruleStatus as RuleStatus | undefined}
/>

+ 2
- 1
server/sonar-web/src/main/js/components/issue/components/IssueType.tsx View File

@@ -23,8 +23,9 @@ import Toggler from 'sonar-ui-common/components/controls/Toggler';
import DropdownIcon from 'sonar-ui-common/components/icons/DropdownIcon';
import IssueTypeIcon from 'sonar-ui-common/components/icons/IssueTypeIcon';
import { translate } from 'sonar-ui-common/helpers/l10n';
import { IssueResponse, setIssueType } from '../../../api/issues';
import { setIssueType } from '../../../api/issues';
import { colors } from '../../../app/theme';
import { IssueResponse } from '../../../types/issues';
import SetTypePopup from '../popups/SetTypePopup';

interface Props {

+ 7
- 5
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueAssign-test.tsx View File

@@ -20,14 +20,14 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import { click } from 'sonar-ui-common/helpers/testUtils';
import { mockIssue } from '../../../../helpers/testMocks';
import IssueAssign from '../IssueAssign';

const issue = {
const issue = mockIssue(false, {
assignee: 'john',
assigneeAvatar: 'gravatarhash',
assigneeName: 'John Doe',
projectOrganization: 'org'
};
assigneeName: 'John Doe'
});

it('should render without the action when the correct rights are missing', () => {
expect(shallowRender({ canAssign: false })).toMatchSnapshot();
@@ -38,7 +38,9 @@ it('should render with the action', () => {
});

it('should render a fallback assignee display if assignee info are not available', () => {
expect(shallowRender({ issue: { projectOrganization: 'org' } })).toMatchSnapshot();
expect(
shallowRender({ issue: mockIssue(false, { assignee: undefined, assigneeName: undefined }) })
).toMatchSnapshot();
});

it('should open the popup when the button is clicked', () => {

+ 3
- 2
server/sonar-web/src/main/js/components/issue/components/__tests__/IssueMessage-test.tsx View File

@@ -40,7 +40,9 @@ it('should handle click correctly', () => {
const onOpenRule = jest.fn();
const wrapper = shallowRender({ onOpenRule });
click(wrapper.find(ButtonLink));
expect(onOpenRule).toBeCalledWith({ key: 'javascript:S1067', organization: 'myorg' });
expect(onOpenRule).toBeCalledWith({
key: 'javascript:S1067'
});
});

function shallowRender(props: Partial<IssueMessageProps> = {}) {
@@ -49,7 +51,6 @@ function shallowRender(props: Partial<IssueMessageProps> = {}) {
manualVulnerability={false}
message="Reduce the number of conditional operators (4) used in the expression"
onOpenRule={jest.fn()}
organization="myorg"
ruleKey="javascript:S1067"
{...props}
/>

+ 0
- 38
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueActionsBar-test.tsx.snap View File

@@ -28,11 +28,9 @@ exports[`should render commentable correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -73,11 +71,9 @@ exports[`should render commentable correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -118,11 +114,9 @@ exports[`should render commentable correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -163,11 +157,9 @@ exports[`should render commentable correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -219,11 +211,9 @@ exports[`should render commentable correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -274,11 +264,9 @@ exports[`should render effort correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -318,11 +306,9 @@ exports[`should render effort correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -362,11 +348,9 @@ exports[`should render effort correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -406,11 +390,9 @@ exports[`should render effort correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -463,11 +445,9 @@ exports[`should render effort correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -517,11 +497,9 @@ exports[`should render issue correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -560,11 +538,9 @@ exports[`should render issue correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -603,11 +579,9 @@ exports[`should render issue correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -646,11 +620,9 @@ exports[`should render issue correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -693,11 +665,9 @@ exports[`should render issue correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -747,11 +717,9 @@ exports[`should render security hotspot correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -790,11 +758,9 @@ exports[`should render security hotspot correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -833,11 +799,9 @@ exports[`should render security hotspot correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -880,11 +844,9 @@ exports[`should render security hotspot correctly 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],

+ 0
- 21
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueAssign-test.tsx.snap View File

@@ -19,14 +19,6 @@ exports[`should open the popup when the button is clicked 2`] = `
open={true}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
issue={
Object {
"assignee": "john",
"assigneeAvatar": "gravatarhash",
"assigneeName": "John Doe",
"projectOrganization": "org",
}
}
onSelect={[MockFunction]}
/>
}
@@ -68,11 +60,6 @@ exports[`should render a fallback assignee display if assignee info are not avai
open={false}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
issue={
Object {
"projectOrganization": "org",
}
}
onSelect={[MockFunction]}
/>
}
@@ -104,14 +91,6 @@ exports[`should render with the action 1`] = `
open={false}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
issue={
Object {
"assignee": "john",
"assigneeAvatar": "gravatarhash",
"assigneeName": "John Doe",
"projectOrganization": "org",
}
}
onSelect={[MockFunction]}
/>
}

+ 0
- 2
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTags-test.tsx.snap View File

@@ -18,7 +18,6 @@ exports[`should open the popup when the button is clicked 2`] = `
open={true}
overlay={
<SetIssueTagsPopup
organization="foo"
selectedTags={
Array [
"mytag",
@@ -56,7 +55,6 @@ exports[`should render with the action 1`] = `
open={false}
overlay={
<SetIssueTagsPopup
organization="foo"
selectedTags={
Array [
"mytag",

+ 0
- 11
server/sonar-web/src/main/js/components/issue/components/__tests__/__snapshots__/IssueTitleBar-test.tsx.snap View File

@@ -33,11 +33,9 @@ exports[`should render correctly: default 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -102,7 +100,6 @@ exports[`should render correctly: issue message 1`] = `
manualVulnerability={false}
message="Reduce the number of conditional operators (4) used in the expression"
onOpenRule={[Function]}
organization="myorg"
ruleKey="javascript:S1067"
/>
`;
@@ -140,11 +137,9 @@ exports[`should render correctly: with filter 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -217,11 +212,9 @@ exports[`should render correctly: with filter 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [],
@@ -328,11 +321,9 @@ exports[`should render correctly: with multi locations 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [
@@ -503,11 +494,9 @@ exports[`should render correctly: with multi locations and link 1`] = `
"key": "AVsae-CQS-9G3txfbFN2",
"line": 25,
"message": "Reduce the number of conditional operators (4) used in the expression",
"organization": "myorg",
"project": "myproject",
"projectKey": "foo",
"projectName": "Foo",
"projectOrganization": "org",
"rule": "javascript:S1067",
"ruleName": "foo",
"secondaryLocations": Array [

+ 0
- 1
server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.tsx View File

@@ -31,7 +31,6 @@ import Avatar from '../../ui/Avatar';

interface Props {
currentUser: T.CurrentUser;
issue: Pick<T.Issue, 'projectOrganization'>;
onSelect: (login: string) => void;
}


+ 2
- 3
server/sonar-web/src/main/js/components/issue/popups/SetIssueTagsPopup.tsx View File

@@ -25,7 +25,6 @@ import { searchIssueTags } from '../../../api/issues';
import TagsSelector from '../../tags/TagsSelector';

interface Props {
organization: string;
selectedTags: string[];
setTags: (tags: string[]) => void;
}
@@ -35,6 +34,7 @@ interface State {
}

const LIST_SIZE = 10;
const MAX_LIST_SIZE = 100;

export default class SetIssueTagsPopup extends React.PureComponent<Props, State> {
mounted = false;
@@ -51,8 +51,7 @@ export default class SetIssueTagsPopup extends React.PureComponent<Props, State>
onSearch = (query: string) => {
return searchIssueTags({
q: query,
ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, 100),
organization: this.props.organization
ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, MAX_LIST_SIZE)
}).then(
(tags: string[]) => {
if (this.mounted) {

+ 1
- 6
server/sonar-web/src/main/js/components/issue/popups/__tests__/SetAssigneePopup-test.tsx View File

@@ -47,11 +47,6 @@ it('should allow to search for a user on SQ', async () => {

function shallowRender(props: Partial<SetAssigneePopup['props']> = {}) {
return shallow(
<SetAssigneePopup
currentUser={mockLoggedInUser()}
issue={{ projectOrganization: 'foo' }}
onSelect={jest.fn()}
{...props}
/>
<SetAssigneePopup currentUser={mockLoggedInUser()} onSelect={jest.fn()} {...props} />
);
}

+ 1
- 3
server/sonar-web/src/main/js/components/issue/popups/__tests__/SetIssueTagsPopup-test.tsx View File

@@ -22,9 +22,7 @@ import * as React from 'react';
import SetIssueTagsPopup from '../SetIssueTagsPopup';

it('should render tags popup correctly', () => {
const element = shallow(
<SetIssueTagsPopup organization="foo" selectedTags={['mytag']} setTags={jest.fn()} />
);
const element = shallow(<SetIssueTagsPopup selectedTags={['mytag']} setTags={jest.fn()} />);
element.setState({ searchResult: ['mytag', 'test', 'second'] });
expect(element).toMatchSnapshot();
});

+ 7
- 9
server/sonar-web/src/main/js/components/workspace/__tests__/Workspace-test.tsx View File

@@ -79,19 +79,18 @@ it('should render correctly', () => {
).toMatchSnapshot('open component');
expect(
shallowRender({
rules: [{ key: 'foo', organization: 'default' }],
rules: [{ key: 'foo' }],
open: { rule: 'foo' }
})
).toMatchSnapshot('open rule');
});

it('should correctly load data from local storage', () => {
const rule1 = { [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo', organization: 'default' };
const rule1 = { [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo' };
const rule2 = {
[TYPE_KEY]: WorkspaceTypes.Rule,
key: 'baz',
name: 'Baz',
organization: 'default'
name: 'Baz'
};
const component = {
[TYPE_KEY]: WorkspaceTypes.Component,
@@ -115,7 +114,7 @@ it('should correctly load data from local storage', () => {
it('should correctly store data locally', () => {
const wrapper = shallowRender({
components: [{ branchLike: mockBranch(), key: 'foo' }],
rules: [{ key: 'foo', organization: 'default' }]
rules: [{ key: 'foo' }]
});
wrapper.instance().saveWorkspace();
expect((save as jest.Mock).mock.calls[0][1]).toMatchSnapshot();
@@ -129,7 +128,7 @@ it('should load rule engine names', async () => {

it('should allow elements to be loaded and updated', () => {
const component = { key: 'foo', branchLike: mockBranch() };
const rule = { key: 'bar', organization: 'default' };
const rule = { key: 'bar' };
const wrapper = shallowRender({
components: [component],
rules: [rule]
@@ -155,7 +154,7 @@ it('should allow elements to be loaded and updated', () => {

it('should be resizable', () => {
(get as jest.Mock).mockReturnValue(
JSON.stringify([{ [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo', organization: 'default' }])
JSON.stringify([{ [TYPE_KEY]: WorkspaceTypes.Rule, key: 'foo' }])
);
const wrapper = shallowRender({ open: { rule: 'foo' } });
const instance = wrapper.instance();
@@ -180,8 +179,7 @@ it('should be resizable', () => {
it('should be openable/collapsible', () => {
const rule = {
key: 'baz',
name: 'Baz',
organization: 'default'
name: 'Baz'
};
const component = {
branchLike: mockBranch(),

+ 1
- 3
server/sonar-web/src/main/js/components/workspace/__tests__/__snapshots__/Workspace-test.tsx.snap View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should correctly store data locally 1`] = `"[{\\"branchLike\\":{\\"analysisDate\\":\\"2018-01-01\\",\\"excludedFromPurge\\":true,\\"isMain\\":false,\\"name\\":\\"branch-6.7\\"},\\"key\\":\\"foo\\",\\"__type__\\":\\"component\\"},{\\"key\\":\\"foo\\",\\"organization\\":\\"default\\",\\"__type__\\":\\"rule\\"}]"`;
exports[`should correctly store data locally 1`] = `"[{\\"branchLike\\":{\\"analysisDate\\":\\"2018-01-01\\",\\"excludedFromPurge\\":true,\\"isMain\\":false,\\"name\\":\\"branch-6.7\\"},\\"key\\":\\"foo\\",\\"__type__\\":\\"component\\"},{\\"key\\":\\"foo\\",\\"__type__\\":\\"rule\\"}]"`;

exports[`should render correctly: default 1`] = `
<ContextProvider
@@ -111,7 +111,6 @@ exports[`should render correctly: open rule 1`] = `
Array [
Object {
"key": "foo",
"organization": "default",
},
]
}
@@ -127,7 +126,6 @@ exports[`should render correctly: open rule 1`] = `
rule={
Object {
"key": "foo",
"organization": "default",
}
}
/>

+ 0
- 1
server/sonar-web/src/main/js/components/workspace/context.ts View File

@@ -31,7 +31,6 @@ export interface ComponentDescriptor {
export interface RuleDescriptor {
key: string;
name?: string;
organization: string;
}

export interface WorkspaceContextShape {

+ 12
- 0
server/sonar-web/src/main/js/helpers/__tests__/urls-test.ts View File

@@ -18,11 +18,13 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { ComponentQualifier } from '../../types/component';
import { IssueType } from '../../types/issues';
import {
getComponentDrilldownUrl,
getComponentIssuesUrl,
getComponentOverviewUrl,
getComponentSecurityHotspotsUrl,
getIssuesUrl,
getQualityGatesUrl,
getQualityGateUrl
} from '../urls';
@@ -121,3 +123,13 @@ describe('#getQualityGate(s)Url', () => {
expect(getQualityGateUrl('bar')).toEqual({ pathname: '/quality_gates/show/bar' });
});
});

describe('getIssuesUrl', () => {
it('should work as expected', () => {
const type = IssueType.Bug;
expect(getIssuesUrl({ type })).toEqual({
pathname: '/issues',
query: { type }
});
});
});

+ 1
- 29
server/sonar-web/src/main/js/helpers/issues.ts View File

@@ -22,15 +22,10 @@ import BugIcon from 'sonar-ui-common/components/icons/BugIcon';
import CodeSmellIcon from 'sonar-ui-common/components/icons/CodeSmellIcon';
import SecurityHotspotIcon from 'sonar-ui-common/components/icons/SecurityHotspotIcon';
import VulnerabilityIcon from 'sonar-ui-common/components/icons/VulnerabilityIcon';
import { IssueType } from '../types/issues';
import { IssueType, RawIssue } from '../types/issues';
import { MetricKey } from '../types/metrics';
import { ISSUE_TYPES } from './constants';

interface Comment {
login: string;
[x: string]: any;
}

interface Rule {}

interface Component {
@@ -38,29 +33,6 @@ interface Component {
name: string;
}

interface IssueBase {
severity: string;
[x: string]: any;
}

export interface RawIssue extends IssueBase {
assignee?: string;
author?: string;
comments?: Array<Comment>;
component: string;
flows?: Array<{
// `componentName` is not available in RawIssue
locations?: Array<T.Omit<T.FlowLocation, 'componentName'>>;
}>;
key: string;
line?: number;
project: string;
rule: string;
status: string;
subProject?: string;
textRange?: T.TextRange;
}

export function sortByType<T extends Pick<T.Issue, 'type'>>(issues: T[]): T[] {
return sortBy(issues, issue => ISSUE_TYPES.indexOf(issue.type));
}

+ 28
- 0
server/sonar-web/src/main/js/helpers/mocks/issues.ts View File

@@ -0,0 +1,28 @@
/*
* 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 { ReferencedRule } from '../../types/issues';

export function mockReferencedRule(overrides: Partial<ReferencedRule> = {}): ReferencedRule {
return {
langName: 'Javascript',
name: 'RuleFoo',
...overrides
};
}

+ 0
- 2
server/sonar-web/src/main/js/helpers/testMocks.ts View File

@@ -407,11 +407,9 @@ export function mockIssue(withLocations = false, overrides: Partial<T.Issue> = {
key: 'AVsae-CQS-9G3txfbFN2',
line: 25,
message: 'Reduce the number of conditional operators (4) used in the expression',
organization: 'myorg',
project: 'myproject',
projectKey: 'foo',
projectName: 'Foo',
projectOrganization: 'org',
rule: 'javascript:S1067',
ruleName: 'foo',
secondaryLocations: [],

+ 2
- 2
server/sonar-web/src/main/js/helpers/urls.ts View File

@@ -99,8 +99,8 @@ export function getPullRequestUrl(project: string, pullRequest: string): Locatio
/**
* Generate URL for a global issues page
*/
export function getIssuesUrl(query: Query, organization?: string): Location {
const pathname = organization ? `/organizations/${organization}/issues` : '/issues';
export function getIssuesUrl(query: Query): Location {
const pathname = '/issues';
return { pathname, query };
}


+ 82
- 0
server/sonar-web/src/main/js/types/issues.ts View File

@@ -29,3 +29,85 @@ export enum IssueScope {
Main = 'MAIN',
Test = 'TEST'
}

interface Comment {
login: string;
[x: string]: any;
}

interface IssueBase {
severity: string;
[x: string]: any;
}

export interface RawIssue extends IssueBase {
assignee?: string;
author?: string;
comments?: Array<Comment>;
component: string;
flows?: Array<{
// `componentName` is not available in RawIssue
locations?: Array<T.Omit<T.FlowLocation, 'componentName'>>;
}>;
key: string;
line?: number;
project: string;
rule: string;
status: string;
subProject?: string;
textRange?: T.TextRange;
}

export interface IssueResponse {
components?: Array<{ key: string; name: string }>;
issue: RawIssue;
rules?: Array<{}>;
users?: Array<T.UserBase>;
}

export interface RawIssuesResponse {
components: ReferencedComponent[];
effortTotal: number;
facets: RawFacet[];
issues: RawIssue[];
languages: ReferencedLanguage[];
paging: T.Paging;
rules?: Array<{}>;
users?: Array<T.UserBase>;
}

export interface FetchIssuesPromise {
components: ReferencedComponent[];
effortTotal: number;
facets: RawFacet[];
issues: T.Issue[];
languages: ReferencedLanguage[];
paging: T.Paging;
rules: ReferencedRule[];
users: T.UserBase[];
}

export interface ReferencedComponent {
key: string;
name: string;
path?: string;
uuid: string;
}

export interface ReferencedLanguage {
name: string;
}

export interface ReferencedRule {
langName?: string;
name: string;
}

export interface RawFacet {
property: string;
values: Array<{ val: string; count: number }>;
}

export interface Facet {
[value: string]: number;
}

+ 0
- 2
server/sonar-web/src/main/js/types/types.d.ts View File

@@ -343,10 +343,8 @@ declare namespace T {
fromHotspot: boolean;
line?: number;
message: string;
organization: string;
project: string;
projectName: string;
projectOrganization: string;
projectKey: string;
pullRequest?: string;
resolution?: string;

Loading…
Cancel
Save