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'
| 'tags'
| 'types';
-export function searchIssues(query: RequestData): Promise<IssuesResponse> {
+export function searchIssues(query: RequestData): Promise<RawIssuesResponse> {
return getJSON('/api/issues/search', query);
}
facets: FacetName[]
): Promise<{
facets: Array<{ property: string; values: T.FacetValue[] }>;
- response: IssuesResponse;
+ response: RawIssuesResponse;
}> {
const data = {
...query,
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 };
});
} 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';
import {
areMyIssuesSelected,
areQueriesEqual,
- Facet,
getOpen,
mapFacet,
parseFacets,
parseQuery,
Query,
- RawFacet,
- ReferencedComponent,
- ReferencedLanguage,
- ReferencedRule,
saveMyIssues,
scrollToIssue,
serializeQuery,
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 {
.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
};
Object.assign(parameters, { assignees: '__me__' });
}
- return this.props.fetchIssues(parameters, false);
+ return this.props.fetchIssues(parameters);
};
fetchFirstIssues() {
}));
}
},
- () => {}
+ () => {
+ /* Do nothing */
+ }
);
};
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) => {
fetchIssues={checkAll ? this.fetchIssues : this.getCheckedIssues}
onClose={this.handleCloseBulkChange}
onDone={this.handleBulkChangeDone}
- organization={this.props.organization}
/>
)}
</div>
}
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() && (
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}
}
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;
onIssueClick={this.openIssue}
onPopupToggle={this.handlePopupToggle}
openPopup={this.state.openPopup}
- organization={organization}
selectedIssue={selectedIssue}
/>
)}
{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}
* 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',
);
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));
fetchIssues: (x: {}) => Promise<{ issues: T.Issue[]; paging: T.Paging }>;
onClose: () => void;
onDone: () => void;
- organization: { key: string } | undefined;
}
interface FormFields {
assignee?: AssigneeOption;
comment?: string;
notifications?: boolean;
- organization?: string;
removeTags?: Array<{ label: string; value: string }>;
severity?: string;
transition?: string;
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) {
};
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 }))
);
};
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;
}
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);
<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)}
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;
}
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}
/>
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;
}
<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
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();
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,
breadcrumbs: [],
key: 'foo',
name: 'bar',
- organization: 'John',
qualifier: 'Doe'
}}
currentUser={mockLoggedInUser()}
})}
location={mockLocation({ pathname: '/issues', query: {} })}
onBranchesChange={() => {}}
- organization={{ key: 'foo' }}
router={mockRouter()}
- userOrganizations={[]}
{...props}
/>
);
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;
});
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
}
onClose={() => {}}
onDone={() => {}}
- organization={undefined}
/>
);
};
*/
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();
});
onIssueClick={jest.fn()}
onPopupToggle={jest.fn()}
openPopup={undefined}
- organization={undefined}
selectedIssue={undefined}
{...overrides}
/>
"breadcrumbs": Array [],
"key": "foo",
"name": "bar",
- "organization": "John",
"qualifier": "Doe",
}
}
"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 [],
"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 [],
"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 [
"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 [],
onIssueCheck={[Function]}
onIssueClick={[Function]}
onPopupToggle={[Function]}
- organization={
- Object {
- "key": "foo",
- }
- }
selectedIssue={
Object {
"actions": Array [],
"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 [],
"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 [],
"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 [],
"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 [
"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 [],
"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 [
className="spacer-right"
qualifier="FIL"
/>
- <Connect(Organization)
- link={false}
- organizationKey="org"
- />
<span
title="proj-name"
>
className="spacer-right"
qualifier="FIL"
/>
- <Connect(Organization)
- link={false}
- organizationKey="org"
- />
<span
title="proj-name"
>
"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 [],
"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 [],
"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 [],
"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 [
"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 [
fromHotspot: false,
key: '',
message: '',
- organization: '',
project: '',
projectKey: '',
projectName: '',
- projectOrganization: '',
rule: '',
ruleName: '',
secondaryLocations: [],
"fromHotspot": false,
"key": "",
"message": "",
- "organization": "",
"project": "",
"projectKey": "",
"projectName": "",
- "projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],
"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 [],
"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 [],
"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 [],
"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 [
"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 [
"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 [
"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 [],
"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 [],
"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 [
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;
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;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
- organization: string | undefined;
query: Query;
stats: T.Dict<number> | undefined;
authors: string[];
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
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;
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;
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;
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;
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;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
- organization: string | undefined;
query: Query;
referencedRules: T.Dict<ReferencedRule>;
rules: string[];
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,
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';
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>;
}
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 (
<>
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.rules}
- organization={organizationKey}
query={query}
referencedRules={this.props.referencedRules}
rules={query.rules}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.tags}
- organization={organizationKey}
query={query}
stats={facets.tags}
tags={query.tags}
onChange={this.props.onFilterChange}
onToggle={this.props.onFacetToggle}
open={!!openFacets.authors}
- organization={organizationKey}
query={query}
stats={facets.authors}
/>
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[];
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;
onChange: (changes: Partial<Query>) => void;
onToggle: (property: string) => void;
open: boolean;
- organization: string | undefined;
query: Query;
stats: T.Dict<number> | undefined;
tags: string[];
const project =
component && ['TRK', 'VW', 'APP'].includes(component.qualifier) ? component.key : undefined;
return searchIssueTags({
- organization: this.props.organization,
project,
ps: SEARCH_SIZE,
q: query
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', () => ({
searchProjects: jest.fn().mockResolvedValue({
components: [],
facets: [],
- organizations: [],
paging: {}
})
}));
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 });
--- /dev/null
+/*
+ * 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}
+ />
+ );
+}
onFacetToggle={jest.fn()}
onFilterChange={jest.fn()}
openFacets={{}}
- organization={undefined}
query={{ types: [''] } as Query}
referencedComponentsById={{}}
referencedComponentsByKey={{}}
--- /dev/null
+// 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",
+ ]
+ }
+/>
+`;
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 {
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'
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
"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 [],
"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 [],
flows: [],
fromHotspot: false,
message: '',
- organization: '',
project: '',
projectName: '',
- projectOrganization: '',
projectKey: '',
rule: '',
ruleName: '',
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"fromHotspot": false,
"key": "foo",
"message": "",
- "organization": "",
"project": "",
"projectKey": "",
"projectName": "",
- "projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],
"fromHotspot": false,
"key": "bar",
"message": "",
- "organization": "",
"project": "",
"projectKey": "",
"projectName": "",
- "projectOrganization": "",
"rule": "",
"ruleName": "",
"secondaryLocations": Array [],
"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 [],
"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 [],
"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 [],
"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 [],
* 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,
*/
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';
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;
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}>
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 (
<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>
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';
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;
}
<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}>
manualVulnerability={issue.fromHotspot && issue.type === 'VULNERABILITY'}
message={issue.message}
onOpenRule={openRule}
- organization={issue.organization}
ruleKey={issue.rule}
ruleStatus={issue.ruleStatus as RuleStatus | undefined}
/>
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 {
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();
});
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', () => {
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> = {}) {
manualVulnerability={false}
message="Reduce the number of conditional operators (4) used in the expression"
onOpenRule={jest.fn()}
- organization="myorg"
ruleKey="javascript:S1067"
{...props}
/>
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
"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 [],
open={true}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
- issue={
- Object {
- "assignee": "john",
- "assigneeAvatar": "gravatarhash",
- "assigneeName": "John Doe",
- "projectOrganization": "org",
- }
- }
onSelect={[MockFunction]}
/>
}
open={false}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
- issue={
- Object {
- "projectOrganization": "org",
- }
- }
onSelect={[MockFunction]}
/>
}
open={false}
overlay={
<Connect(withCurrentUser(SetAssigneePopup))
- issue={
- Object {
- "assignee": "john",
- "assigneeAvatar": "gravatarhash",
- "assigneeName": "John Doe",
- "projectOrganization": "org",
- }
- }
onSelect={[MockFunction]}
/>
}
open={true}
overlay={
<SetIssueTagsPopup
- organization="foo"
selectedTags={
Array [
"mytag",
open={false}
overlay={
<SetIssueTagsPopup
- organization="foo"
selectedTags={
Array [
"mytag",
"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 [],
manualVulnerability={false}
message="Reduce the number of conditional operators (4) used in the expression"
onOpenRule={[Function]}
- organization="myorg"
ruleKey="javascript:S1067"
/>
`;
"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 [],
"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 [],
"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 [
"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 [
interface Props {
currentUser: T.CurrentUser;
- issue: Pick<T.Issue, 'projectOrganization'>;
onSelect: (login: string) => void;
}
import TagsSelector from '../../tags/TagsSelector';
interface Props {
- organization: string;
selectedTags: string[];
setTags: (tags: string[]) => void;
}
}
const LIST_SIZE = 10;
+const MAX_LIST_SIZE = 100;
export default class SetIssueTagsPopup extends React.PureComponent<Props, State> {
mounted = false;
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) {
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} />
);
}
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();
});
).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,
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();
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]
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();
it('should be openable/collapsible', () => {
const rule = {
key: 'baz',
- name: 'Baz',
- organization: 'default'
+ name: 'Baz'
};
const component = {
branchLike: mockBranch(),
// 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
Array [
Object {
"key": "foo",
- "organization": "default",
},
]
}
rule={
Object {
"key": "foo",
- "organization": "default",
}
}
/>
export interface RuleDescriptor {
key: string;
name?: string;
- organization: string;
}
export interface WorkspaceContextShape {
* 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';
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 }
+ });
+ });
+});
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 {
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));
}
--- /dev/null
+/*
+ * 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
+ };
+}
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: [],
/**
* 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 };
}
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;
+}
fromHotspot: boolean;
line?: number;
message: string;
- organization: string;
project: string;
projectName: string;
- projectOrganization: string;
projectKey: string;
pullRequest?: string;
resolution?: string;