From aed4140165da7195ebf82f6149603be31a3ac198 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Fri, 9 Dec 2016 15:25:05 +0100 Subject: [PATCH] refactor SearchView to remove $ and _ dependencies (#1449) and add flow annotations --- .../sonar-web/src/main/js/api/components.js | 46 ++++++----- server/sonar-web/src/main/js/api/favorites.js | 4 +- .../app/components/nav/global/SearchView.js | 77 ++++++++++--------- 3 files changed, 73 insertions(+), 54 deletions(-) diff --git a/server/sonar-web/src/main/js/api/components.js b/server/sonar-web/src/main/js/api/components.js index ac46a7680f1..8c422a1c9ba 100644 --- a/server/sonar-web/src/main/js/api/components.js +++ b/server/sonar-web/src/main/js/api/components.js @@ -17,40 +17,46 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +// @flow import { getJSON, postJSON, post } from '../helpers/request.js'; -export function getComponents (data) { +export function getComponents (data?: Object) { const url = '/api/components/search'; return getJSON(url, data); } -export function getProvisioned (data) { +export function getProvisioned (data?: Object) { const url = '/api/projects/provisioned'; return getJSON(url, data); } -export function getGhosts (data) { +export function getGhosts (data?: Object) { const url = '/api/projects/ghosts'; return getJSON(url, data); } -export function deleteComponents (data) { +export function deleteComponents (data?: Object) { const url = '/api/projects/bulk_delete'; return post(url, data); } -export function deleteProject (key) { +export function deleteProject (key: string) { const url = '/api/projects/delete'; const data = { key }; return post(url, data); } -export function createProject (data) { +export function createProject (data?: Object) { const url = '/api/projects/create'; return postJSON(url, data); } -export function getComponentTree (strategy, componentKey, metrics = [], additional = {}) { +export function getComponentTree ( + strategy: string, + componentKey: string, + metrics: Array = [], + additional?: Object = {} +) { const url = '/api/measures/component_tree'; const data = Object.assign({}, additional, { baseComponentKey: componentKey, @@ -60,33 +66,33 @@ export function getComponentTree (strategy, componentKey, metrics = [], addition return getJSON(url, data); } -export function getChildren (componentKey, metrics, additional) { +export function getChildren (componentKey: string, metrics?: Array, additional?: Object) { return getComponentTree('children', componentKey, metrics, additional); } -export function getComponentLeaves (componentKey, metrics, additional) { +export function getComponentLeaves (componentKey: string, metrics?: Array, additional?: Object) { return getComponentTree('leaves', componentKey, metrics, additional); } -export function getComponent (componentKey, metrics = []) { +export function getComponent (componentKey: string, metrics: Array = []) { const url = '/api/measures/component'; const data = { componentKey, metricKeys: metrics.join(',') }; return getJSON(url, data).then(r => r.component); } -export function getTree (baseComponentKey, options = {}) { +export function getTree (baseComponentKey: string, options?: Object = {}) { const url = '/api/components/tree'; const data = Object.assign({}, options, { baseComponentKey }); return getJSON(url, data); } -export function getParents ({ id, key }) { +export function getParents ({ id, key }: { id: string, key: string }) { const url = '/api/components/show'; const data = id ? { id } : { key }; return getJSON(url, data).then(r => r.ancestors); } -export function getBreadcrumbs ({ id, key }) { +export function getBreadcrumbs ({ id, key }: { id: string, key: string }) { const url = '/api/components/show'; const data = id ? { id } : { key }; return getJSON(url, data).then(r => { @@ -95,7 +101,7 @@ export function getBreadcrumbs ({ id, key }) { }); } -export function getProjectsWithInternalId (query) { +export function getProjectsWithInternalId (query: string) { const url = '/api/resources/search'; const data = { f: 's2', @@ -105,12 +111,12 @@ export function getProjectsWithInternalId (query) { return getJSON(url, data).then(r => r.results); } -export function getMyProjects (data) { +export function getMyProjects (data?: Object) { const url = '/api/projects/search_my_projects'; return getJSON(url, data); } -export function searchProjects (data) { +export function searchProjects (data?: Object) { const url = '/api/components/search_projects'; return getJSON(url, data); } @@ -121,7 +127,7 @@ export function searchProjects (data) { * @param {string} newKey * @returns {Promise} */ -export function changeKey (key, newKey) { +export function changeKey (key: string, newKey: string) { const url = '/api/components/update_key'; const data = { key, newKey }; return post(url, data); @@ -135,8 +141,12 @@ export function changeKey (key, newKey) { * @param {boolean} dryRun * @returns {Promise} */ -export function bulkChangeKey (key, from, to, dryRun = false) { +export function bulkChangeKey (key: string, from: string, to: string, dryRun?: boolean = false) { const url = '/api/components/bulk_update_key'; const data = { key, from, to, dryRun }; return postJSON(url, data); } + +export const getSuggestions = (query: string): Promise => ( + getJSON('/api/components/suggestions', { s: query }) +); diff --git a/server/sonar-web/src/main/js/api/favorites.js b/server/sonar-web/src/main/js/api/favorites.js index fe210e0132e..2c7149bd3c4 100644 --- a/server/sonar-web/src/main/js/api/favorites.js +++ b/server/sonar-web/src/main/js/api/favorites.js @@ -20,7 +20,9 @@ /* @flow */ import { post, requestDelete, getJSON } from '../helpers/request'; -export const getFavorites = () => getJSON('/api/favourites'); +export const getFavorites = (): Promise => ( + getJSON('/api/favourites') +); export function addFavorite (componentKey: string) { const url = '/api/favourites'; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js index 47d9fe6ae13..6d30a446290 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/SearchView.js @@ -17,10 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import $ from 'jquery'; -import _ from 'underscore'; +// @flow import Backbone from 'backbone'; import Marionette from 'backbone.marionette'; +import debounce from 'lodash/debounce'; +import sortBy from 'lodash/sortBy'; import SelectableCollectionView from '../../../../components/common/selectable-collection-view'; import SearchItemTemplate from '../templates/nav-search-item.hbs'; import EmptySearchTemplate from '../templates/nav-search-empty.hbs'; @@ -29,6 +30,14 @@ import RecentHistory from '../component/RecentHistory'; import { translate } from '../../../../helpers/l10n'; import { collapsedDirFromPath, fileFromPath } from '../../../../helpers/path'; import { isUserAdmin } from '../../../../helpers/users'; +import { getFavorites } from '../../../../api/favorites'; +import { getSuggestions } from '../../../../api/components'; + +type Finding = { + name: string, + url: string, + extra?: string +}; const SearchItemView = Marionette.ItemView.extend({ tagName: 'li', @@ -60,9 +69,10 @@ const SearchItemView = Marionette.ItemView.extend({ }, serializeData () { - return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { + return { + ...Marionette.ItemView.prototype.serializeData.apply(this, arguments), index: this.options.index - }); + }; } }); @@ -94,18 +104,18 @@ export default Marionette.LayoutView.extend({ }, initialize () { - const that = this; this.results = new Backbone.Collection(); this.favorite = []; if (this.model.get('currentUser').isLoggedIn) { - this.fetchFavorite().always(function () { - that.resetResultsToDefault(); - }); + this.fetchFavorite().then( + () => this.resetResultsToDefault(), + () => this.resetResultsToDefault() + ); } else { this.resetResultsToDefault(); } this.resultsView = new SearchResultsView({ collection: this.results }); - this.debouncedSearch = _.debounce(this.search, 250); + this.debouncedSearch = debounce(this.search, 250); this._bufferedValue = ''; }, @@ -150,10 +160,9 @@ export default Marionette.LayoutView.extend({ return false; }, - fetchFavorite () { - const that = this; - return $.get(window.baseUrl + '/api/favourites').done(function (r) { - that.favorite = r.map(function (f) { + fetchFavorite (): Promise<*> { + return getFavorites().then(r => { + this.favorite = r.map(f => { const isFile = ['FIL', 'UTS'].indexOf(f.qualifier) !== -1; return { url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(f.key) + window.dashboardParameters(true), @@ -161,7 +170,7 @@ export default Marionette.LayoutView.extend({ icon: 'favorite' }; }); - that.favorite = _.sortBy(that.favorite, 'name'); + this.favorite = sortBy(this.favorite, 'name'); }); }, @@ -177,8 +186,8 @@ export default Marionette.LayoutView.extend({ extra: index === 0 ? translate('browsed_recently') : null }; }); - const favorite = _.first(this.favorite, 6).map(function (f, index) { - return _.extend(f, { extra: index === 0 ? translate('favorite') : null }); + const favorite = this.favorite.slice(0, 6).map(function (f, index) { + return { ...f, extra: index === 0 ? translate('favorite') : null }; }); this.results.reset([].concat(history, favorite)); }, @@ -188,33 +197,31 @@ export default Marionette.LayoutView.extend({ this.resetResultsToDefault(); return; } - const that = this; - const url = window.baseUrl + '/api/components/suggestions'; - const options = { s: q }; - return $.get(url, options).done(function (r) { + return getSuggestions(q).then(r => { // if the input value has changed since we sent the request, // just ignore the output, because another request already sent - if (q !== that._bufferedValue) { + if (q !== this._bufferedValue) { return; } const collection = []; - r.results.forEach(function (domain) { - domain.items.forEach(function (item, index) { - collection.push(_.extend(item, { + r.results.forEach(domain => { + domain.items.forEach((item, index) => { + collection.push({ + ...item, q: domain.q, extra: index === 0 ? domain.name : null, url: window.baseUrl + '/dashboard/index?id=' + encodeURIComponent(item.key) + window.dashboardParameters(true) - })); + }); }); }); - that.results.reset([].concat( - that.getNavigationFindings(q), - that.getGlobalDashboardFindings(q), - that.getFavoriteFindings(q), - collection - )); + this.results.reset([ + ...this.getNavigationFindings(q), + ...this.getGlobalDashboardFindings(q), + ...this.getFavoriteFindings(q), + ...collection + ]); }); }, @@ -226,7 +233,7 @@ export default Marionette.LayoutView.extend({ { name: translate('quality_profiles.page'), url: window.baseUrl + '/profiles' }, { name: translate('quality_gates.page'), url: window.baseUrl + '/quality_gates' } ]; - const customItems = []; + const customItems: Array = []; if (isUserAdmin(this.model.get('currentUser'))) { customItems.push({ name: translate('layout.settings'), url: window.baseUrl + '/settings' }); } @@ -236,7 +243,7 @@ export default Marionette.LayoutView.extend({ if (findings.length > 0) { findings[0].extra = translate('navigation'); } - return _.first(findings, 6); + return findings.slice(0, 6); }, getGlobalDashboardFindings (q) { @@ -250,7 +257,7 @@ export default Marionette.LayoutView.extend({ if (findings.length > 0) { findings[0].extra = translate('dashboard.global_dashboards'); } - return _.first(findings, 6); + return findings.slice(0, 6); }, getFavoriteFindings (q) { @@ -260,6 +267,6 @@ export default Marionette.LayoutView.extend({ if (findings.length > 0) { findings[0].extra = translate('favorite'); } - return _.first(findings, 6); + return findings.slice(0, 6); } }); -- 2.39.5