diff --git a/client/app/scripts/components/node-details/node-details-health-link-item.js b/client/app/scripts/components/node-details/node-details-health-link-item.js index 54ae18b24..1641d94c9 100644 --- a/client/app/scripts/components/node-details/node-details-health-link-item.js +++ b/client/app/scripts/components/node-details/node-details-health-link-item.js @@ -1,6 +1,7 @@ import React from 'react'; import moment from 'moment'; import { connect } from 'react-redux'; +import stableStringify from 'json-stable-stringify'; import NodeDetailsHealthItem from './node-details-health-item'; import CloudLink from '../cloud-link'; @@ -30,7 +31,7 @@ export function appendTime(url, time) { return url; } - return `${url.substr(0, pos + cloudLinkPathEnd.length)}${encodeURIComponent(JSON.stringify(payload) || '')}`; + return `${url.substr(0, pos + cloudLinkPathEnd.length)}${encodeURIComponent(stableStringify(payload) || '')}`; } if (url.indexOf('?') !== -1) { diff --git a/client/app/scripts/components/terminal.js b/client/app/scripts/components/terminal.js index 5dda94fd7..faee037c3 100644 --- a/client/app/scripts/components/terminal.js +++ b/client/app/scripts/components/terminal.js @@ -6,6 +6,7 @@ import classNames from 'classnames'; import { debounce } from 'lodash'; import { Terminal as Term } from 'xterm'; import * as fit from 'xterm/lib/addons/fit/fit'; +import stableStringify from 'json-stable-stringify'; import { closeTerminal } from '../actions/app-actions'; import { getPipeStatus } from '../actions/request-actions'; @@ -230,7 +231,7 @@ class Terminal extends React.Component { handlePopoutTerminal(ev) { ev.preventDefault(); - const paramString = JSON.stringify(this.props); + const paramString = stableStringify(this.props); this.props.dispatch(closeTerminal(this.getPipeId())); this.setState({detached: true}); diff --git a/client/app/scripts/components/zoomable-canvas.js b/client/app/scripts/components/zoomable-canvas.js index 51b51c73e..365a0a67b 100644 --- a/client/app/scripts/components/zoomable-canvas.js +++ b/client/app/scripts/components/zoomable-canvas.js @@ -3,6 +3,7 @@ import classNames from 'classnames'; import { connect } from 'react-redux'; import { clamp, debounce, pick } from 'lodash'; import { fromJS } from 'immutable'; +import stableStringify from 'json-stable-stringify'; import { drag } from 'd3-drag'; import { event as d3Event, select } from 'd3-selection'; @@ -275,7 +276,7 @@ function mapStateToProps(state, props) { canvasMargins: canvasMarginsSelector(state), forceRelayout: state.get('forceRelayout'), height: canvasHeightSelector(state), - layoutId: JSON.stringify(activeTopologyZoomCacheKeyPathSelector(state)), + layoutId: stableStringify(activeTopologyZoomCacheKeyPathSelector(state)), layoutLimits: props.limitsSelector(state), layoutZoomState: props.zoomStateSelector(state), width: canvasWidthSelector(state), diff --git a/client/app/scripts/selectors/zooming.js b/client/app/scripts/selectors/zooming.js index ec354bfac..03f6e60af 100644 --- a/client/app/scripts/selectors/zooming.js +++ b/client/app/scripts/selectors/zooming.js @@ -1,5 +1,6 @@ import { createSelector } from 'reselect'; import { Map as makeMap } from 'immutable'; +import stableStringify from 'json-stable-stringify'; import { isGraphViewModeSelector, activeTopologyOptionsSelector } from './topology'; @@ -10,7 +11,7 @@ export const activeTopologyZoomCacheKeyPathSelector = createSelector( state => state.get('topologyViewMode'), state => state.get('currentTopologyId'), state => state.get('pinnedMetricType'), - state => JSON.stringify(activeTopologyOptionsSelector(state)), + state => stableStringify(activeTopologyOptionsSelector(state)), ], (isGraphViewMode, viewMode, topologyId, pinnedMetricType, topologyOptions) => ( isGraphViewMode diff --git a/client/app/scripts/utils/hash-utils.js b/client/app/scripts/utils/hash-utils.js index 76c358d38..2a1c3d595 100644 --- a/client/app/scripts/utils/hash-utils.js +++ b/client/app/scripts/utils/hash-utils.js @@ -1,13 +1,14 @@ import { isPlainObject, mapValues, isEmpty, omitBy } from 'lodash'; +import stableStringify from 'json-stable-stringify'; export function hashDifferenceDeep(A, B) { // If the elements have exactly the same content, the difference is an empty object. // This could fail if the objects are both hashes with different permutation of keys, // but this case we handle below by digging in recursively. - if (JSON.stringify(A) === JSON.stringify(B)) return {}; + if (stableStringify(A) === stableStringify(B)) return {}; // Otherwise, if either element is not a hash, always return the first element // unchanged as this function only takes difference of hash objects. diff --git a/client/app/scripts/utils/storage-utils.js b/client/app/scripts/utils/storage-utils.js index 45bd293e5..0aacfacdf 100644 --- a/client/app/scripts/utils/storage-utils.js +++ b/client/app/scripts/utils/storage-utils.js @@ -1,4 +1,5 @@ import debug from 'debug'; +import stableStringify from 'json-stable-stringify'; const log = debug('scope:storage-utils'); @@ -62,7 +63,7 @@ export function storageGetObject( export function storageSetObject(key, obj, storage = localSessionStorage) { try { - return storageSet(key, JSON.stringify(obj), storage); + return storageSet(key, stableStringify(obj), storage); } catch (e) { log('Error encoding object for key', key); } diff --git a/client/app/scripts/utils/topology-utils.js b/client/app/scripts/utils/topology-utils.js index 2c6991164..ee76f4cc0 100644 --- a/client/app/scripts/utils/topology-utils.js +++ b/client/app/scripts/utils/topology-utils.js @@ -1,5 +1,6 @@ import { endsWith } from 'lodash'; import { Set as makeSet, List as makeList, Map as makeMap } from 'immutable'; +import stableStringify from 'json-stable-stringify'; import { isPausedSelector } from '../selectors/time-travel'; import { isResourceViewModeSelector } from '../selectors/topology'; @@ -44,7 +45,7 @@ export function buildTopologyCacheId(topologyId, topologyOptions) { if (topologyId) { id = topologyId; if (topologyOptions) { - id += JSON.stringify(topologyOptions); + id += stableStringify(topologyOptions); } } return id; diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index 7a2b57634..25d9d6a8f 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -2,6 +2,7 @@ import debug from 'debug'; import reqwest from 'reqwest'; import { defaults } from 'lodash'; import { Map as makeMap, List } from 'immutable'; +import stableStringify from 'json-stable-stringify'; import { receiveError, @@ -226,7 +227,7 @@ export function doResizeTty(pipeId, control, cols, rows) { + `${encodeURIComponent(control.nodeId)}/${control.id}`; return doRequest({ - data: JSON.stringify({ height: rows.toString(), pipeID: pipeId, width: cols.toString() }), + data: stableStringify({ height: rows.toString(), pipeID: pipeId, width: cols.toString() }), method: 'POST', url, })