diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 9f9f5f35e..c182e8e2a 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -1,10 +1,15 @@ import debug from 'debug'; +import trimStart from 'lodash/trimStart'; +import reduce from 'lodash/reduce'; +import map from 'lodash/map'; +import each from 'lodash/each'; +import { fromJS } from 'immutable'; import ActionTypes from '../constants/action-types'; import { saveGraph } from '../utils/file-utils'; import { modulo } from '../utils/math-utils'; import { updateRoute } from '../utils/router-utils'; -import { parseQuery } from '../utils/search-utils'; +import { parseQuery, searchTopology } from '../utils/search-utils'; import { bufferDeltaUpdate, resumeUpdate, resetUpdateBuffer } from '../utils/update-buffer-utils'; import { doControlRequest, getAllNodes, getNodesDelta, getNodeDetails, @@ -681,3 +686,63 @@ export function toggleTroubleshootingMenu(ev) { type: ActionTypes.TOGGLE_TROUBLESHOOTING_MENU }; } + +function convertQueryString(paramString) { + const pairs = trimStart(paramString, '?').split('&'); + return reduce(pairs, (result, pair) => { + const [k, v] = pair.split('='); + result[k] = v; + return result; + }, {}); +} + +function waterfall(series, target, cb) { + function next(result) { + const fn = series.shift(); + if (fn) { + try { + fn(result, next); + } catch (e) { + cb(e); + } + } else { + cb(null, result); + } + } + next(target, next); +} + +export function translateUrlParamsToViewState(queryString) { + return () => { + const params = convertQueryString(queryString); + if (params.node) { + // Get the list of topologies + fetch('api/topology').then(response => response.json()) + .then((topologies) => { + // Queue up a list of functions to run, one after the other. + const series = map(topologies, topo => (result, cb) => { + // Fetch the node for each topology + // TODO: Get this buildOptions to work + // buildOptionsQuery(topo.options); + fetch(`${trimStart(topo.url, '/')}`) + .then(res => res.json()) + .then((json) => { + // Append each node in the list to the result object. + each(json.nodes, (node, id) => { + result[id] = node; + }); + cb(result); + }) + .catch((e) => { throw e; }); + }); + // Run the series + waterfall(series, {}, (err, nodes) => { + if (err) { throw err; } + // const collection = flatten(map(r, ({nodes}) => values(nodes))); + const result = searchTopology(fromJS(nodes), { query: params.node }); + console.log(result.toJS()); + }); + }); + } + }; +} diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 3361c7285..8424d61e6 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -13,7 +13,8 @@ import Topologies from './topologies'; import TopologyOptions from './topology-options'; import { getApiDetails, getTopologies } from '../utils/web-api-utils'; import { focusSearch, pinNextMetric, hitBackspace, hitEnter, hitEsc, unpinMetric, - selectMetric, toggleHelp, toggleGridMode } from '../actions/app-actions'; + selectMetric, toggleHelp, toggleGridMode, translateUrlParamsToViewState +} from '../actions/app-actions'; import Details from './details'; import Nodes from './nodes'; import GridModeSelector from './grid-mode-selector'; @@ -39,13 +40,13 @@ class App extends React.Component { componentDidMount() { window.addEventListener('keypress', this.onKeyPress); window.addEventListener('keyup', this.onKeyUp); - - getRouter(this.props.dispatch, this.props.urlState).start({hashbang: true}); + this.props.translateUrlParamsToViewState(window.location.search); + getRouter(this.context.store.dispatch, this.props.urlState).start({hashbang: true}); if (!this.props.routeSet) { // dont request topologies when already done via router - getTopologies(this.props.activeTopologyOptions, this.props.dispatch); + getTopologies(this.props.activeTopologyOptions, this.context.store.dispatch); } - getApiDetails(this.props.dispatch); + getApiDetails(this.context.store.dispatch); } componentWillUnmount() { @@ -59,11 +60,11 @@ class App extends React.Component { // don't get esc in onKeyPress if (ev.keyCode === ESC_KEY_CODE) { - this.props.dispatch(hitEsc()); + this.context.store.dispatch(hitEsc()); } else if (ev.keyCode === ENTER_KEY_CODE) { - this.props.dispatch(hitEnter()); + this.context.store.dispatch(hitEnter()); } else if (ev.keyCode === BACKSPACE_KEY_CODE) { - this.props.dispatch(hitBackspace()); + this.context.store.dispatch(hitBackspace()); } else if (ev.code === 'KeyD' && ev.ctrlKey && !showingTerminal) { toggleDebugToolbar(); this.forceUpdate(); @@ -157,7 +158,11 @@ function mapStateToProps(state) { }; } +App.contextTypes = { + store: React.PropTypes.object.isRequired +}; export default connect( - mapStateToProps + mapStateToProps, + { translateUrlParamsToViewState } )(App); diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index f3f035464..9f222641a 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -1,10 +1,7 @@ import page from 'page'; -import reduce from 'lodash/reduce'; -import trimStart from 'lodash/trimStart'; import { route } from '../actions/app-actions'; import { storageGet, storageSet } from './storage-utils'; -import { searchTopology } from './search-utils'; // // page.js won't match the routes below if ":state" has a slash in it, so replace those before we @@ -86,27 +83,9 @@ export function updateRoute(getState) { } } -export function translateUrlParams(paramString, nodes) { - // ?key=value&otherkey=othervalue - let state; - const pairs = trimStart(paramString, '?').split('&'); - const params = reduce(pairs, (result, pair) => { - const [k, v] = pair.split('='); - result[k] = v; - return result; - }, {}); - if (params.node) { - state = searchTopology(nodes, { query: params.node }); - } - - return state; -} - - export function getRouter(dispatch, initialState) { // strip any trailing '/'s. page.base(window.location.pathname.replace(/\/$/, '')); - console.log(translateUrlParams(window.location.search)); page('/', () => { // recover from storage state on empty URL diff --git a/client/app/scripts/utils/search-utils.js b/client/app/scripts/utils/search-utils.js index b8f74d047..a4c72552b 100644 --- a/client/app/scripts/utils/search-utils.js +++ b/client/app/scripts/utils/search-utils.js @@ -68,6 +68,7 @@ function findNodeMatch(nodeMatches, keyPath, text, query, prefix, label, truncat if (!prefix || matchPrefix(label, prefix)) { const queryRe = makeRegExp(query); const matches = text.match(queryRe); + if (matches) { const firstMatch = matches[0]; const index = text.search(queryRe); @@ -172,6 +173,7 @@ export function searchTopology(nodes, { prefix, query, metric, comp, value }) { } } }); + return nodeMatches; }