import DeferredSpinner from '../../../components/common/DeferredSpinner';
import DuplicationPopup from '../../../components/SourceViewer/components/DuplicationPopup';
import { SourceViewerContext } from '../../../components/SourceViewer/SourceViewerContext';
+import { Alert } from '../../../components/ui/Alert';
import { WorkspaceContext } from '../../../components/workspace/context';
import { getIssueFlowSnippets } from '../../../api/issues';
+import throwGlobalError from '../../../app/utils/throwGlobalError';
import {
filterDuplicationBlocksByLine,
- isDuplicationBlockInRemovedComponent,
- getDuplicationBlocksForIndex
+ getDuplicationBlocksForIndex,
+ isDuplicationBlockInRemovedComponent
} from '../../../components/SourceViewer/helpers/duplications';
import {
duplicationsByLine,
} from '../../../components/SourceViewer/helpers/indexing';
import { getDuplications } from '../../../api/components';
import { getBranchLikeQuery } from '../../../helpers/branches';
+import { translate } from '../../../helpers/l10n';
interface Props {
branchLike: T.Branch | T.PullRequest | undefined;
issuePopup?: { issue: string; name: string };
linePopup?: T.LinePopup & { component: string };
loading: boolean;
+ notAccessible: boolean;
}
export default class CrossComponentSourceViewerWrapper extends React.PureComponent<Props, State> {
state: State = {
components: {},
duplicationsByLine: {},
- loading: true
+ loading: true,
+ notAccessible: false
};
componentDidMount() {
}
}
},
- () => {
+ ({ response }: { response: Response }) => {
+ if (response.status !== 403) {
+ throwGlobalError({ response });
+ }
if (this.mounted) {
- this.setState({ loading: false });
+ this.setState({ loading: false, notAccessible: response.status === 403 });
}
}
);
};
render() {
- const { loading } = this.state;
+ const { loading, notAccessible } = this.state;
if (loading) {
return (
);
}
+ if (notAccessible) {
+ return (
+ <Alert className="spacer-top" variant="warning">
+ {translate('code_viewer.no_source_code_displayed_due_to_security')}
+ </Alert>
+ );
+ }
+
const { components, duplications, duplicationsByLine, linePopup } = this.state;
const issuesByComponent = issuesByComponentAndLine(this.props.issues);
const locationsByComponent = groupLocationsByComponent(this.props.locations, components);
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import * as React from 'react';
import { shallow } from 'enzyme';
-import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper';
+import * as React from 'react';
+import { getDuplications } from '../../../../api/components';
+import { getIssueFlowSnippets } from '../../../../api/issues';
import {
mockFlowLocation,
mockIssue,
mockSourceViewerFile
} from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { getIssueFlowSnippets } from '../../../../api/issues';
-import { getDuplications } from '../../../../api/components';
+import CrossComponentSourceViewerWrapper from '../CrossComponentSourceViewerWrapper';
jest.mock('../../../../api/issues', () => {
const { mockSnippetsByComponent } = require.requireActual('../../../../helpers/testMocks');
expect(getIssueFlowSnippets).toBeCalledWith('foo');
});
+it('Should handle no access rights', async () => {
+ (getIssueFlowSnippets as jest.Mock).mockRejectedValueOnce({ response: { status: 403 } });
+
+ const wrapper = shallowRender();
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().notAccessible).toBe(true);
+ expect(wrapper).toMatchSnapshot();
+});
+
it('should handle issue popup', () => {
const wrapper = shallowRender();
// open