aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-01-07 17:11:07 +0100
committerStas Vilchik <vilchiks@gmail.com>2016-01-07 17:11:07 +0100
commit88726dbd19b93375a6e6290f05168e051a334e5a (patch)
treee4ab1f402199352fca52bd0c82dc769a9c22951a /server/sonar-web
parent45983670fed129aca63dedacb6387b271c66bd50 (diff)
downloadsonarqube-88726dbd19b93375a6e6290f05168e051a334e5a.tar.gz
sonarqube-88726dbd19b93375a6e6290f05168e051a334e5a.zip
SONAR-7149 display a list of sub-components when start searching
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/apps/code/actions/index.js11
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Code.js33
-rw-r--r--server/sonar-web/src/main/js/apps/code/components/Search.js70
-rw-r--r--server/sonar-web/src/main/js/apps/code/reducers/index.js4
-rw-r--r--server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs21
-rw-r--r--server/sonar-web/tests/apps/code/store-test.js2
6 files changed, 111 insertions, 30 deletions
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 1d3dfd73561..98526d00287 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
@@ -148,7 +148,14 @@ function retrieveComponent (componentKey, bucket) {
let requestTree = (query, baseComponent, dispatch) => {
dispatch(startFetching());
- return getTree(baseComponent.key, { q: query, s: 'qualifier,name' })
+
+ const params = { s: 'qualifier,name', qualifiers: 'BRC,FIL,UTS' };
+
+ if (query) {
+ params.q = query;
+ }
+
+ return getTree(baseComponent.key, params)
.then(r => dispatch(searchAction(r.components)))
.then(() => dispatch(stopFetching()));
};
@@ -199,7 +206,7 @@ export function browse (componentKey) {
export function search (query, baseComponent) {
return dispatch => {
dispatch(updateQueryAction(query));
- if (query) {
+ if (query != null) {
requestTree(query, baseComponent, dispatch);
} else {
dispatch(searchAction(null));
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 f2c61b51ec7..f7120d283df 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,7 @@ import Components from './Components';
import Breadcrumbs from './Breadcrumbs';
import SourceViewer from './SourceViewer';
import Search from './Search';
-import { initComponent, browse } from '../actions';
+import { initComponent, browse, search } from '../actions';
import { translate } from '../../../helpers/l10n';
@@ -33,8 +33,12 @@ class Code extends Component {
componentDidMount () {
const { dispatch, component, routing } = this.props;
const selectedKey = (routing.path && decodeURIComponent(routing.path.substr(1))) || component.key;
+
dispatch(initComponent(component.key, component.breadcrumbs))
.then(() => dispatch(browse(selectedKey)));
+
+ this.handleKeyDown = this.handleKeyDown.bind(this);
+ this.attachShortcuts();
}
componentWillReceiveProps (nextProps) {
@@ -47,11 +51,32 @@ class Code extends Component {
}
}
+ componentWillUnmount () {
+ this.removeShortcuts();
+ }
+
+ attachShortcuts () {
+ window.addEventListener('keyup', this.handleKeyDown);
+ }
+
+ removeShortcuts () {
+ window.removeEventListener('keyup', this.handleKeyDown);
+ }
+
handleBrowse (component) {
const { dispatch } = this.props;
dispatch(browse(component.key));
}
+ handleKeyDown (e) {
+ const { dispatch, component, searchQuery } = this.props;
+
+ // "t" key
+ if (e.keyCode === 84 && searchQuery == null) {
+ dispatch(search('', component));
+ }
+ }
+
render () {
const {
fetching,
@@ -65,7 +90,7 @@ class Code extends Component {
const shouldShowSearchResults = !!searchResults;
const shouldShowSourceViewer = !!sourceViewer;
const shouldShowComponents = !shouldShowSearchResults && !shouldShowSourceViewer && components;
- const shouldShowBreadcrumbs = !shouldShowSearchResults && Array.isArray(breadcrumbs) && breadcrumbs.length > 1;
+ const shouldShowBreadcrumbs = !shouldShowSearchResults && Array.isArray(breadcrumbs) && breadcrumbs.length > 1;
const componentsClassName = classNames('spacer-top', { 'new-loading': fetching });
@@ -80,7 +105,9 @@ class Code extends Component {
<i className="spinner"/>
</div>
- <Search component={this.props.component}/>
+ <div className="page-actions">
+ <Search component={this.props.component}/>
+ </div>
</header>
{errorMessage && (
diff --git a/server/sonar-web/src/main/js/apps/code/components/Search.js b/server/sonar-web/src/main/js/apps/code/components/Search.js
index 2a6c602926f..f71d5f4e424 100644
--- a/server/sonar-web/src/main/js/apps/code/components/Search.js
+++ b/server/sonar-web/src/main/js/apps/code/components/Search.js
@@ -21,40 +21,80 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { search } from '../actions';
+import { translate } from '../../../helpers/l10n';
class Search extends Component {
componentDidMount () {
- this.refs.input.focus();
+ this.focusSearchInput();
+ }
+
+ componentDidUpdate () {
+ this.focusSearchInput();
+ }
+
+ focusSearchInput () {
+ if (this.refs.input) {
+ this.refs.input.focus();
+ }
}
handleSearch (e) {
e.preventDefault();
const { dispatch, component } = this.props;
- const query = this.refs.input.value;
+ const query = this.refs.input ? this.refs.input.value : '';
dispatch(search(query, component));
}
+ handleStopSearch (e) {
+ e.preventDefault();
+ const { dispatch } = this.props;
+ dispatch(search(null));
+ }
+
+ handleKeyDown (e) {
+ const { dispatch } = this.props;
+
+ // "escape" key
+ if (e.keyCode === 27) {
+ dispatch(search(null));
+ }
+ }
+
render () {
const { query } = this.props;
+ const hasQuery = query != null;
return (
<form
onSubmit={this.handleSearch.bind(this)}
className="search-box code-search-box">
- <button className="search-box-submit button-clean">
- <i className="icon-search"></i>
- </button>
- <input
- ref="input"
- onChange={this.handleSearch.bind(this)}
- value={query}
- className="search-box-input"
- type="search"
- name="q"
- placeholder="Search"
- maxLength="100"
- autoComplete="off"/>
+ {hasQuery && (
+ <input
+ ref="input"
+ onChange={this.handleSearch.bind(this)}
+ onKeyDown={this.handleKeyDown.bind(this)}
+ value={query}
+ className="search-box-input"
+ type="search"
+ name="q"
+ placeholder="Search"
+ maxLength="100"
+ autoComplete="off"
+ style={{ visibility: hasQuery ? 'visible': 'hidden' }}/>
+ )}
+ {!hasQuery && (
+ <button className="search-box-submit">
+ {translate('search_verb')}
+ </button>
+ )}
+ {hasQuery && (
+ <button
+ className="search-box-submit"
+ onClick={this.handleStopSearch.bind(this)}>
+ {translate('cancel')}
+ </button>
+ )}
</form>
);
}
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 2c8b31a1ebb..596d92b91ea 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
@@ -76,7 +76,7 @@ export const initialState = {
breadcrumbs: null,
sourceViewer: null,
searchResults: null,
- searchQuery: '',
+ searchQuery: null,
coverageMetric: null,
baseBreadcrumbs: [],
errorMessage: null
@@ -104,7 +104,7 @@ export function current (state = initialState, action) {
breadcrumbs,
sourceViewer,
searchResults: null,
- searchQuery: '',
+ searchQuery: null,
errorMessage: null
};
case SEARCH:
diff --git a/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs b/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs
index 2ef8a865b8b..bfa98bc4495 100644
--- a/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs
+++ b/server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs
@@ -23,14 +23,21 @@
</ul>
</div>
- <h3 class="shortcuts-section-title">{{t 'shortcuts.section.rules'}}</h3>
+ <div class="spacer-bottom">
+ <h3 class="shortcuts-section-title">{{t 'shortcuts.section.rules'}}</h3>
+ <ul class="shortcuts-list">
+ <li><span class="shortcut-button">&uarr;</span> <span
+ class="shortcut-button">&darr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.navigate_between_rules'}}</li>
+ <li><span class="shortcut-button">&rarr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.open_details'}}</li>
+ <li><span class="shortcut-button">&larr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.return_to_list'}}</li>
+ <li><span class="shortcut-button">a</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.activate'}}</li>
+ <li><span class="shortcut-button">d</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.deactivate'}}</li>
+ </ul>
+ </div>
+
+ <h3 class="shortcuts-section-title">{{t 'shortcuts.section.code'}}</h3>
<ul class="shortcuts-list">
- <li><span class="shortcut-button">&uarr;</span> <span
- class="shortcut-button">&darr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.navigate_between_rules'}}</li>
- <li><span class="shortcut-button">&rarr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.open_details'}}</li>
- <li><span class="shortcut-button">&larr;</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.return_to_list'}}</li>
- <li><span class="shortcut-button">a</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.activate'}}</li>
- <li><span class="shortcut-button">d</span> &nbsp;&nbsp; {{t 'shortcuts.section.rules.deactivate'}}</li>
+ <li><span class="shortcut-button">t</span> &nbsp;&nbsp; {{t 'shortcuts.section.code.search'}}</li>
</ul>
</div>
diff --git a/server/sonar-web/tests/apps/code/store-test.js b/server/sonar-web/tests/apps/code/store-test.js
index e8b36a58e4b..fb54c02d32d 100644
--- a/server/sonar-web/tests/apps/code/store-test.js
+++ b/server/sonar-web/tests/apps/code/store-test.js
@@ -225,7 +225,7 @@ describe('Code :: Store', () => {
it('should be reset', () => {
const stateBefore = Object.assign({}, initialState, { searchQuery: 'query' });
expect(current(stateBefore, browseAction(exampleComponent)).searchQuery)
- .to.equal('');
+ .to.be.null;
});
});
describe('errorMessage', () => {