SONAR-4004 handle failed requests

This commit is contained in:
Stas Vilchik 2015-12-29 14:03:22 +01:00
parent 87e9d4629c
commit 458d8b3314
6 changed files with 86 additions and 7 deletions

View File

@ -26,6 +26,7 @@ export const SEARCH = 'SEARCH';
export const UPDATE_QUERY = 'UPDATE_QUERY';
export const START_FETCHING = 'START_FETCHING';
export const STOP_FETCHING = 'STOP_FETCHING';
export const RAISE_ERROR = 'RAISE_ERROR';
export function initComponentAction (component, breadcrumbs = []) {
@ -67,6 +68,13 @@ export function stopFetching () {
return { type: STOP_FETCHING };
}
export function raiseError (message) {
return {
type: RAISE_ERROR,
message
};
}
function getPath (componentKey) {
return '/' + encodeURIComponent(componentKey);
@ -107,6 +115,22 @@ let requestTree = (query, baseComponent, dispatch) => {
};
requestTree = _.debounce(requestTree, 250);
async function getErrorMessage (response) {
switch (response.status) {
case 401:
return window.t('not_authorized');
default:
try {
let json = await response.json();
return json['err_msg'] ||
(json.errors && _.pluck(json.errors, 'msg').join('. ')) ||
window.t('default_error_message');
} catch (e) {
return window.t('default_error_message');
}
}
}
export function initComponent (componentKey, breadcrumbs) {
return dispatch => {
dispatch(startFetching());
@ -125,7 +149,11 @@ export function browse (componentKey) {
dispatch(browseAction(component, children, breadcrumbs));
})
.then(() => dispatch(pushPath(getPath(componentKey))))
.then(() => dispatch(stopFetching()));
.then(() => dispatch(stopFetching()))
.catch(e => {
getErrorMessage(e.response)
.then(message => dispatch(raiseError(message)));
});
};
}

View File

@ -33,7 +33,15 @@ class Code extends Component {
}
render () {
const { fetching, baseComponent, components, breadcrumbs, sourceViewer, coverageMetric, searchResults } = this.props;
const {
fetching,
baseComponent,
components,
breadcrumbs,
sourceViewer,
coverageMetric,
searchResults,
errorMessage } = this.props;
const shouldShowBreadcrumbs = Array.isArray(breadcrumbs) && breadcrumbs.length > 1;
const shouldShowSearchResults = !!searchResults;
const shouldShowSourceViewer = !!sourceViewer;
@ -55,6 +63,12 @@ class Code extends Component {
<Search component={this.props.component}/>
</header>
{errorMessage && (
<div className="alert alert-danger">
{errorMessage}
</div>
)}
{shouldShowBreadcrumbs && (
<Breadcrumbs
breadcrumbs={breadcrumbs}

View File

@ -1,6 +1,6 @@
import _ from 'underscore';
import { INIT, BROWSE, SEARCH, UPDATE_QUERY, START_FETCHING, STOP_FETCHING } from '../actions';
import { INIT, BROWSE, SEARCH, UPDATE_QUERY, START_FETCHING, STOP_FETCHING, RAISE_ERROR } from '../actions';
function hasSourceCode (component) {
@ -37,7 +37,8 @@ export const initialState = {
searchResults: null,
searchQuery: '',
coverageMetric: null,
baseBreadcrumbs: []
baseBreadcrumbs: [],
errorMessage: null
};
@ -55,15 +56,34 @@ export function current (state = initialState, action) {
const breadcrumbs = action.breadcrumbs.slice(baseBreadcrumbsLength);
const sourceViewer = hasSourceCode(action.component) ? action.component : null;
return { ...state, baseComponent, components, breadcrumbs, sourceViewer, searchResults: null, searchQuery: '' };
return {
...state,
baseComponent,
components,
breadcrumbs,
sourceViewer,
searchResults: null,
searchQuery: '',
errorMessage: null
};
case SEARCH:
return { ...state, searchResults: action.components };
return {
...state,
searchResults: action.components,
errorMessage: null
};
case UPDATE_QUERY:
return { ...state, searchQuery: action.query };
case START_FETCHING:
return { ...state, fetching: true };
case STOP_FETCHING:
return { ...state, fetching: false };
case RAISE_ERROR:
return {
...state,
errorMessage: action.message,
fetching: false
};
default:
return state;
}

View File

@ -7,7 +7,8 @@ import {
searchAction,
updateQueryAction,
startFetching,
stopFetching
stopFetching,
raiseError
} from '../../../src/main/js/apps/code/actions';
@ -207,6 +208,20 @@ describe('Code :: Store', () => {
.to.equal('');
});
});
describe('errorMessage', () => {
it('should be set', () => {
expect(current(initialState, raiseError('error!')).errorMessage)
.to.equal('error!');
});
it('should be reset', () => {
const stateBefore = Object.assign({}, initialState, { errorMessage: 'error!' });
expect(current(stateBefore, browseAction(exampleComponent)).errorMessage)
.to.be.null;
expect(current(stateBefore, searchAction(exampleComponents)).errorMessage)
.to.be.null;
});
});
});
describe('bucket', () => {
it('should add initial component', () => {

View File

@ -1,4 +1,5 @@
/* globals global: false */
require("babel-polyfill");
var jsdom = require('jsdom');

View File

@ -236,6 +236,7 @@ new_window=New window
no_data=No data
no_lines_match_your_filter_criteria=No lines match your filter criteria.
no_results=No results
not_authorized=You are not authorized.
not_authorized_to_access_project=You are not authorized to access to this '{0}' project
over_x_days=over {0} days
over_x_days.short={0} days