Browse Source

SONAR-7149 display a list of sub-components when start searching

tags/5.4-M4
Stas Vilchik 8 years ago
parent
commit
88726dbd19

+ 9
- 2
server/sonar-web/src/main/js/apps/code/actions/index.js View File



let requestTree = (query, baseComponent, dispatch) => { let requestTree = (query, baseComponent, dispatch) => {
dispatch(startFetching()); 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(r => dispatch(searchAction(r.components)))
.then(() => dispatch(stopFetching())); .then(() => dispatch(stopFetching()));
}; };
export function search (query, baseComponent) { export function search (query, baseComponent) {
return dispatch => { return dispatch => {
dispatch(updateQueryAction(query)); dispatch(updateQueryAction(query));
if (query) {
if (query != null) {
requestTree(query, baseComponent, dispatch); requestTree(query, baseComponent, dispatch);
} else { } else {
dispatch(searchAction(null)); dispatch(searchAction(null));

+ 30
- 3
server/sonar-web/src/main/js/apps/code/components/Code.js View File

import Breadcrumbs from './Breadcrumbs'; import Breadcrumbs from './Breadcrumbs';
import SourceViewer from './SourceViewer'; import SourceViewer from './SourceViewer';
import Search from './Search'; import Search from './Search';
import { initComponent, browse } from '../actions';
import { initComponent, browse, search } from '../actions';
import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';




componentDidMount () { componentDidMount () {
const { dispatch, component, routing } = this.props; const { dispatch, component, routing } = this.props;
const selectedKey = (routing.path && decodeURIComponent(routing.path.substr(1))) || component.key; const selectedKey = (routing.path && decodeURIComponent(routing.path.substr(1))) || component.key;

dispatch(initComponent(component.key, component.breadcrumbs)) dispatch(initComponent(component.key, component.breadcrumbs))
.then(() => dispatch(browse(selectedKey))); .then(() => dispatch(browse(selectedKey)));

this.handleKeyDown = this.handleKeyDown.bind(this);
this.attachShortcuts();
} }


componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
} }
} }


componentWillUnmount () {
this.removeShortcuts();
}

attachShortcuts () {
window.addEventListener('keyup', this.handleKeyDown);
}

removeShortcuts () {
window.removeEventListener('keyup', this.handleKeyDown);
}

handleBrowse (component) { handleBrowse (component) {
const { dispatch } = this.props; const { dispatch } = this.props;
dispatch(browse(component.key)); dispatch(browse(component.key));
} }


handleKeyDown (e) {
const { dispatch, component, searchQuery } = this.props;

// "t" key
if (e.keyCode === 84 && searchQuery == null) {
dispatch(search('', component));
}
}

render () { render () {
const { const {
fetching, fetching,
const shouldShowSearchResults = !!searchResults; const shouldShowSearchResults = !!searchResults;
const shouldShowSourceViewer = !!sourceViewer; const shouldShowSourceViewer = !!sourceViewer;
const shouldShowComponents = !shouldShowSearchResults && !shouldShowSourceViewer && components; 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 }); const componentsClassName = classNames('spacer-top', { 'new-loading': fetching });


<i className="spinner"/> <i className="spinner"/>
</div> </div>


<Search component={this.props.component}/>
<div className="page-actions">
<Search component={this.props.component}/>
</div>
</header> </header>


{errorMessage && ( {errorMessage && (

+ 55
- 15
server/sonar-web/src/main/js/apps/code/components/Search.js View File

import { connect } from 'react-redux'; import { connect } from 'react-redux';


import { search } from '../actions'; import { search } from '../actions';
import { translate } from '../../../helpers/l10n';




class Search extends Component { class Search extends Component {
componentDidMount () { componentDidMount () {
this.refs.input.focus();
this.focusSearchInput();
}

componentDidUpdate () {
this.focusSearchInput();
}

focusSearchInput () {
if (this.refs.input) {
this.refs.input.focus();
}
} }


handleSearch (e) { handleSearch (e) {
e.preventDefault(); e.preventDefault();
const { dispatch, component } = this.props; const { dispatch, component } = this.props;
const query = this.refs.input.value;
const query = this.refs.input ? this.refs.input.value : '';
dispatch(search(query, component)); 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 () { render () {
const { query } = this.props; const { query } = this.props;
const hasQuery = query != null;


return ( return (
<form <form
onSubmit={this.handleSearch.bind(this)} onSubmit={this.handleSearch.bind(this)}
className="search-box code-search-box"> 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> </form>
); );
} }

+ 2
- 2
server/sonar-web/src/main/js/apps/code/reducers/index.js View File

breadcrumbs: null, breadcrumbs: null,
sourceViewer: null, sourceViewer: null,
searchResults: null, searchResults: null,
searchQuery: '',
searchQuery: null,
coverageMetric: null, coverageMetric: null,
baseBreadcrumbs: [], baseBreadcrumbs: [],
errorMessage: null errorMessage: null
breadcrumbs, breadcrumbs,
sourceViewer, sourceViewer,
searchResults: null, searchResults: null,
searchQuery: '',
searchQuery: null,
errorMessage: null errorMessage: null
}; };
case SEARCH: case SEARCH:

+ 14
- 7
server/sonar-web/src/main/js/main/nav/templates/nav-shortcuts-help.hbs View File

</ul> </ul>
</div> </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"> <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> </ul>
</div> </div>



+ 1
- 1
server/sonar-web/tests/apps/code/store-test.js View File

it('should be reset', () => { it('should be reset', () => {
const stateBefore = Object.assign({}, initialState, { searchQuery: 'query' }); const stateBefore = Object.assign({}, initialState, { searchQuery: 'query' });
expect(current(stateBefore, browseAction(exampleComponent)).searchQuery) expect(current(stateBefore, browseAction(exampleComponent)).searchQuery)
.to.equal('');
.to.be.null;
}); });
}); });
describe('errorMessage', () => { describe('errorMessage', () => {

Loading…
Cancel
Save