diff --git a/client/.babelrc b/client/.babelrc index 431d458d29..5a6095063a 100644 --- a/client/.babelrc +++ b/client/.babelrc @@ -1,4 +1,7 @@ { - "plugins": ["lodash"], + "plugins": [ + "lodash", + ["transform-object-rest-spread", { "useBuiltIns": true }] + ], "presets": ["es2015", "react"] } diff --git a/client/app/scripts/actions.js b/client/app/scripts/actions.js new file mode 100644 index 0000000000..ffcdfb3ddb --- /dev/null +++ b/client/app/scripts/actions.js @@ -0,0 +1 @@ +module.exports = require('./actions/app-actions'); diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 89b44722a5..740175de19 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -17,6 +17,8 @@ import { getNodeDetails, getTopologies, deletePipe, + stopTopologyPolling, + teardownWebsockets, } from '../utils/web-api-utils'; import { getCurrentTopologyUrl } from '../utils/topology-utils'; import { storageSet } from '../utils/storage-utils'; @@ -735,3 +737,8 @@ export function changeInstance() { ); }; } + +export function shutdown() { + stopTopologyPolling(); + teardownWebsockets(); +} diff --git a/client/app/scripts/component.js b/client/app/scripts/component.js new file mode 100644 index 0000000000..55f61da4c3 --- /dev/null +++ b/client/app/scripts/component.js @@ -0,0 +1 @@ +module.exports = require('./components/app').default; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 43970c0ef8..adc1251f48 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -13,7 +13,7 @@ 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, shutdown } from '../actions/app-actions'; import Details from './details'; import Nodes from './nodes'; import GridModeSelector from './grid-mode-selector'; @@ -52,6 +52,7 @@ class App extends React.Component { componentWillUnmount() { window.removeEventListener('keypress', this.onKeyPress); window.removeEventListener('keyup', this.onKeyUp); + shutdown(); } onKeyUp(ev) { diff --git a/client/app/scripts/index.js b/client/app/scripts/index.js index f4ae21fc80..7f5362bfed 100644 --- a/client/app/scripts/index.js +++ b/client/app/scripts/index.js @@ -1,4 +1,3 @@ exports.reducer = require('./reducers/root').default; exports.Scope = require('./components/app').default; exports.actions = require('./actions/app-actions'); -exports.ContrastStyleCompiler = require('./contrast-compiler'); diff --git a/client/app/scripts/reducer.js b/client/app/scripts/reducer.js new file mode 100644 index 0000000000..8252204872 --- /dev/null +++ b/client/app/scripts/reducer.js @@ -0,0 +1 @@ +module.exports = require('./reducers/root').default; diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index 6bc7d330cb..66ba020778 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -90,21 +90,20 @@ export function updateRoute(getState) { export function getRouter(dispatch, initialState) { + let mergedState = initialState; // strip any trailing '/'s. page.base(window.location.pathname.replace(/\/$/, '')); + const storageState = storageGet(STORAGE_STATE_KEY); + if (storageState) { + window.location.hash = `!/state/${storageState}`; + const parsedState = JSON.parse(decodeURL(storageState)); + mergedState = { ...initialState, ...parsedState }; + } + page('/', () => { // recover from storage state on empty URL - const storageState = storageGet(STORAGE_STATE_KEY); - if (storageState) { - // push storage state to URL - window.location.hash = `!/state/${storageState}`; - const parsedState = JSON.parse(decodeURL(storageState)); - const mergedState = Object.assign(initialState, parsedState); - dispatch(route(mergedState)); - } else { - dispatch(route(initialState)); - } + dispatch(route(mergedState)); }); page('/state/:state', (ctx) => { diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index 70cf089cd2..90423118c6 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -142,7 +142,10 @@ function createWebsocket(topologyUrl, optionsQuery, dispatch) { * Any opts that get passed in will override the defaults. */ function doRequest(opts) { - const config = defaults(opts, { contentType: 'application/json' }); + const config = defaults(opts, { + contentType: 'application/json', + type: 'json' + }); if (csrfToken) { config.headers = Object.assign({}, config.headers, { 'X-CSRF-Token': csrfToken }); } @@ -193,9 +196,10 @@ export function getTopologies(options, dispatch) { export function getNodesDelta(topologyUrl, options, dispatch, forceReload) { const optionsQuery = buildOptionsQuery(options); - // only recreate websocket if url changed or if forced (weave cloud instance reload); - const isNewUrl = topologyUrl && (topologyUrl !== currentUrl || currentOptions !== optionsQuery); - + // Only recreate websocket if url changed or if forced (weave cloud instance reload); + // Check for truthy options and that options have changed. + const isNewOptions = currentOptions && currentOptions !== optionsQuery; + const isNewUrl = topologyUrl && (topologyUrl !== currentUrl || isNewOptions); if (forceReload || isNewUrl) { createWebsocket(topologyUrl, optionsQuery, dispatch); currentUrl = topologyUrl; @@ -348,3 +352,21 @@ export function getPipeStatus(pipeId, dispatch) { } }); } + +export function stopTopologyPolling() { + clearTimeout(topologyTimer); + topologyTimer = 0; +} + +export function teardownWebsockets() { + clearTimeout(reconnectTimer); + if (socket) { + socket.onerror = null; + socket.onclose = null; + socket.onmessage = null; + socket.onopen = null; + socket.close(); + socket = null; + currentOptions = null; + } +} diff --git a/client/package.json b/client/package.json index 95b4f5eb31..d07113fa34 100644 --- a/client/package.json +++ b/client/package.json @@ -52,6 +52,7 @@ "babel-eslint": "7.1.1", "babel-jest": "17.0.2", "babel-loader": "6.2.8", + "babel-plugin-transform-object-rest-spread": "^6.23.0", "babel-preset-es2015": "6.18.0", "babel-preset-react": "6.16.0", "clean-webpack-plugin": "0.1.14", @@ -93,7 +94,8 @@ "scripts": { "build": "webpack --config webpack.production.config.js", "build-external": "EXTERNAL=true webpack --config webpack.production.config.js", - "build-pkg": "mkdir -p build-pkg && node node_modules/.bin/babel app/scripts --ignore __tests__ --out-dir build-pkg && cp package.json build-pkg/ && cp -R app/styles build-pkg/", + "copy-pkg-files": "cp package.json build-pkg/ && cp -R app/styles build-pkg/", + "build-pkg": "mkdir -p build-pkg && node node_modules/.bin/babel app/scripts --ignore __tests__ --out-dir build-pkg && npm run copy-pkg-files", "bundle": "npm run build-pkg && npm pack ./build-pkg && mv weave-scope-$npm_package_version.tgz ./tmp/weave-scope.tgz", "start": "node server.js", "start-production": "NODE_ENV=production node server.js",