aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-04-07 15:44:07 +0200
committerStas Vilchik <vilchiks@gmail.com>2016-04-11 15:48:35 +0200
commit9bf2ebf04d26e49c844b264f767a0345cce0be20 (patch)
tree0c1402deb0243578e79718bf92de289f5b8efc4d /server/sonar-web
parentc8b01d4f1520a14be831547f6b35c072a8b9517e (diff)
downloadsonarqube-9bf2ebf04d26e49c844b264f767a0345cce0be20.tar.gz
sonarqube-9bf2ebf04d26e49c844b264f767a0345cce0be20.zip
SONAR-7531 Add pagination on the Code page
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/api/components.js2
-rw-r--r--server/sonar-web/src/main/js/apps/code/actions/index.js54
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Code.js22
-rw-r--r--server/sonar-web/src/main/js/apps/code/reducers/index.js23
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js2
-rw-r--r--server/sonar-web/tests/apps/code/store-test.js11
6 files changed, 93 insertions, 21 deletions
diff --git a/server/sonar-web/src/main/js/api/components.js b/server/sonar-web/src/main/js/api/components.js
index ac53aaf2ab3..934d7a9c1bb 100644
--- a/server/sonar-web/src/main/js/api/components.js
+++ b/server/sonar-web/src/main/js/api/components.js
@@ -55,7 +55,7 @@ export function getComponentTree (strategy, componentKey, metrics = [], addition
}
export function getChildren (componentKey, metrics, additional) {
- return getComponentTree('children', componentKey, metrics, additional).then(r => r.components);
+ return getComponentTree('children', componentKey, metrics, additional);
}
export function getComponentLeaves (componentKey, metrics, additional) {
diff --git a/server/sonar-web/src/main/js/apps/code/actions/index.js b/server/sonar-web/src/main/js/apps/code/actions/index.js
index fc143fa1ec1..2422d993362 100644
--- a/server/sonar-web/src/main/js/apps/code/actions/index.js
+++ b/server/sonar-web/src/main/js/apps/code/actions/index.js
@@ -40,8 +40,11 @@ const METRICS_WITH_COVERAGE = [
'overall_coverage'
];
+const PAGE_SIZE = 100;
+
export const INIT = 'INIT';
export const BROWSE = 'BROWSE';
+export const LOAD_MORE = 'LOAD_MORE';
export const SEARCH = 'SEARCH';
export const SELECT_NEXT = 'SELECT_NEXT';
export const SELECT_PREV = 'SELECT_PREV';
@@ -58,12 +61,21 @@ export function initComponentAction (component, breadcrumbs = []) {
};
}
-export function browseAction (component, children = [], breadcrumbs = []) {
+export function browseAction (component, children = [], breadcrumbs = [], total = 0) {
return {
type: BROWSE,
component,
children,
- breadcrumbs
+ breadcrumbs,
+ total
+ };
+}
+
+export function loadMoreAction (children, page) {
+ return {
+ type: LOAD_MORE,
+ children,
+ page
};
}
@@ -108,17 +120,23 @@ function getPath (componentKey) {
return '/' + encodeURIComponent(componentKey);
}
-function expandRootDir (components) {
- const rootDir = components.find(component => component.qualifier === 'DIR' && component.name === '/');
+function expandRootDir ({ children, total, ...other }) {
+ const rootDir = children.find(component => component.qualifier === 'DIR' && component.name === '/');
if (rootDir) {
- return getChildren(rootDir.key, METRICS_WITH_COVERAGE).then(files => {
- return _.without([...components, ...files], rootDir);
+ return getChildren(rootDir.key, METRICS_WITH_COVERAGE).then(r => {
+ const nextChildren = _.without([...children, ...r.components], rootDir);
+ const nextTotal = total + r.components.length - /* root dir */ 1;
+ return { children: nextChildren, total: nextTotal, ...other };
});
} else {
- return components;
+ return { children, total, ...other };
}
}
+function prepareChildren (r) {
+ return { children: r.components, total: r.paging.total, page: r.paging.pageIndex };
+}
+
function skipRootDir (breadcrumbs) {
return breadcrumbs.filter(component => {
return !(component.qualifier === 'DIR' && component.name === '/');
@@ -133,8 +151,8 @@ function retrieveComponentBase (componentKey, candidate) {
function retrieveComponentChildren (componentKey, candidate) {
return candidate && candidate.children ?
- Promise.resolve(candidate.children) :
- getChildren(componentKey, METRICS_WITH_COVERAGE).then(expandRootDir);
+ Promise.resolve({ children: candidate.children, total: candidate.total }) :
+ getChildren(componentKey, METRICS_WITH_COVERAGE, { ps: PAGE_SIZE }).then(prepareChildren).then(expandRootDir);
}
function retrieveComponentBreadcrumbs (componentKey, candidate) {
@@ -195,7 +213,7 @@ export function browse (componentKey) {
window.location = getComponentUrl(component.refKey);
return new Promise();
} else {
- dispatch(browseAction(component, children, breadcrumbs));
+ dispatch(browseAction(component, children.children, breadcrumbs, children.total));
}
})
.then(() => dispatch(pushPath(getPath(componentKey))))
@@ -207,6 +225,22 @@ export function browse (componentKey) {
};
}
+export function loadMore () {
+ return (dispatch, getState) => {
+ const { baseComponent, page } = getState().current;
+ return getChildren(baseComponent.key, METRICS_WITH_COVERAGE, { p: page + 1, ps: PAGE_SIZE })
+ .then(prepareChildren)
+ .then(({ children }) => {
+ dispatch(loadMoreAction(children, page + 1));
+ dispatch(stopFetching());
+ })
+ .catch(e => {
+ getErrorMessage(e.response)
+ .then(message => dispatch(raiseError(message)));
+ });
+ };
+}
+
let debouncedSearch = function (query, baseComponent, dispatch) {
if (query) {
requestTree(query, baseComponent, dispatch);
diff --git a/server/sonar-web/src/main/js/apps/code/components/Code.js b/server/sonar-web/src/main/js/apps/code/components/Code.js
index 47e2e13cf2e..b8f63763f72 100644
--- a/server/sonar-web/src/main/js/apps/code/components/Code.js
+++ b/server/sonar-web/src/main/js/apps/code/components/Code.js
@@ -25,7 +25,8 @@ import Components from './Components';
import Breadcrumbs from './Breadcrumbs';
import SourceViewer from './SourceViewer';
import Search from './Search';
-import { initComponent, browse } from '../actions';
+import ListFooter from '../../../components/shared/list-footer';
+import { initComponent, browse, loadMore } from '../actions';
class Code extends Component {
componentDidMount () {
@@ -50,6 +51,11 @@ class Code extends Component {
dispatch(browse(component.key));
}
+ handleLoadMore () {
+ const { dispatch } = this.props;
+ dispatch(loadMore());
+ }
+
render () {
const {
fetching,
@@ -59,7 +65,9 @@ class Code extends Component {
sourceViewer,
coverageMetric,
searchResults,
- errorMessage } = this.props;
+ errorMessage,
+ total
+ } = this.props;
const shouldShowSearchResults = !!searchResults;
const shouldShowSourceViewer = !!sourceViewer;
const shouldShowComponents = !shouldShowSearchResults && !shouldShowSourceViewer && components;
@@ -109,6 +117,13 @@ class Code extends Component {
</div>
)}
+ {shouldShowComponents && (
+ <ListFooter
+ count={components.length}
+ total={total}
+ loadMore={this.handleLoadMore.bind(this)}/>
+ )}
+
{shouldShowSourceViewer && (
<div className="spacer-top">
<SourceViewer component={sourceViewer}/>
@@ -129,6 +144,7 @@ export default connect(state => {
sourceViewer: state.current.sourceViewer,
coverageMetric: state.current.coverageMetric,
searchResults: state.current.searchResults,
- errorMessage: state.current.errorMessage
+ errorMessage: state.current.errorMessage,
+ total: state.current.total
};
})(Code);
diff --git a/server/sonar-web/src/main/js/apps/code/reducers/index.js b/server/sonar-web/src/main/js/apps/code/reducers/index.js
index b76be02a510..f061926e0e4 100644
--- a/server/sonar-web/src/main/js/apps/code/reducers/index.js
+++ b/server/sonar-web/src/main/js/apps/code/reducers/index.js
@@ -19,8 +19,18 @@
*/
import _ from 'underscore';
-import { INIT, BROWSE, SEARCH, UPDATE_QUERY, SELECT_NEXT, SELECT_PREV, START_FETCHING, STOP_FETCHING,
- RAISE_ERROR } from '../actions';
+import {
+ INIT,
+ BROWSE,
+ LOAD_MORE,
+ SEARCH,
+ UPDATE_QUERY,
+ SELECT_NEXT,
+ SELECT_PREV,
+ START_FETCHING,
+ STOP_FETCHING,
+ RAISE_ERROR
+} from '../actions';
function hasSourceCode (component) {
return component.qualifier === 'FIL' || component.qualifier === 'UTS';
@@ -125,11 +135,19 @@ export function current (state = initialState, action) {
components,
breadcrumbs,
sourceViewer,
+ total: action.total,
+ page: 1,
searchResults: null,
searchQuery: '',
searchSelectedItem: null,
errorMessage: null
};
+ case LOAD_MORE:
+ return {
+ ...state,
+ components: sortChildren([...state.components, ...action.children]),
+ page: action.page
+ };
case SEARCH:
return {
...state,
@@ -172,6 +190,7 @@ export function bucket (state = [], action) {
case BROWSE:
const candidate = Object.assign({}, action.component, {
children: action.children,
+ total: action.total,
breadcrumbs: action.breadcrumbs
});
const nextState = merge(state, candidate);
diff --git a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js
index 92615167cc3..7b75d0b65f5 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/details/treemap/MeasureTreemap.js
@@ -64,7 +64,7 @@ export default class MeasureTreemap extends React.Component {
};
return getChildren(componentKey, metrics, options).then(r => {
- const components = r.map(component => {
+ const components = r.components.map(component => {
const measures = {};
const key = component.refKey || component.key;
diff --git a/server/sonar-web/tests/apps/code/store-test.js b/server/sonar-web/tests/apps/code/store-test.js
index de5ddbfadf1..155c84a8720 100644
--- a/server/sonar-web/tests/apps/code/store-test.js
+++ b/server/sonar-web/tests/apps/code/store-test.js
@@ -313,7 +313,7 @@ describe('Code :: Store', () => {
const breadcrumbsBefore = [{ key: 'A' }];
const bucketAfter = [
- { key: 'A', breadcrumbs: [{ key: 'A' }], children: [{ key: 'B' }] },
+ { key: 'A', breadcrumbs: [{ key: 'A' }], children: [{ key: 'B' }], total: 0 },
{ key: 'B', breadcrumbs: [{ key: 'A' }, { key: 'B' }] }
];
@@ -335,7 +335,8 @@ describe('Code :: Store', () => {
{
key: 'A',
breadcrumbs: [{ key: 'A' }],
- children: [{ key: 'B' }]
+ children: [{ key: 'B' }],
+ total: 0
},
{
key: 'B',
@@ -360,12 +361,14 @@ describe('Code :: Store', () => {
{
key: 'A',
breadcrumbs: [{ key: 'A' }],
- children: [{ key: 'B' }]
+ children: [{ key: 'B' }],
+ total: 0
},
{
key: 'B',
breadcrumbs: [{ key: 'A' }, { key: 'B' }],
- children: [{ key: 'C' }]
+ children: [{ key: 'C' }],
+ total: 0
},
{
key: 'C',