mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 02:00:43 +00:00
Changed option value to list
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { changeTopologyOption } from '../actions/app-actions';
|
||||
|
||||
class TopologyOptionAction extends React.Component {
|
||||
export default class TopologyOptionAction extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
@@ -13,13 +10,14 @@ class TopologyOptionAction extends React.Component {
|
||||
onClick(ev) {
|
||||
ev.preventDefault();
|
||||
const { optionId, topologyId, item } = this.props;
|
||||
this.props.changeTopologyOption(optionId, item.get('value'), topologyId);
|
||||
this.props.onClick(optionId, item.get('value'), topologyId);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { activeValue, item } = this.props;
|
||||
const className = activeValue === item.get('value')
|
||||
? 'topology-option-action topology-option-action-selected' : 'topology-option-action';
|
||||
const className = activeValue.includes(item.get('value'))
|
||||
? 'topology-option-action topology-option-action-selected'
|
||||
: 'topology-option-action';
|
||||
return (
|
||||
<div className={className} onClick={this.onClick}>
|
||||
{item.get('label')}
|
||||
@@ -27,8 +25,3 @@ class TopologyOptionAction extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{ changeTopologyOption }
|
||||
)(TopologyOptionAction);
|
||||
|
||||
@@ -4,8 +4,18 @@ import { connect } from 'react-redux';
|
||||
import { getCurrentTopologyOptions } from '../utils/topology-utils';
|
||||
import { activeTopologyOptionsSelector } from '../selectors/topology';
|
||||
import TopologyOptionAction from './topology-option-action';
|
||||
import { changeTopologyOption } from '../actions/app-actions';
|
||||
|
||||
class TopologyOptions extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.handleOptionClick = this.handleOptionClick.bind(this);
|
||||
}
|
||||
|
||||
handleOptionClick(optionId, value, topologyId) {
|
||||
this.props.changeTopologyOption(optionId, value, topologyId);
|
||||
}
|
||||
|
||||
renderOption(option) {
|
||||
const { activeOptions, topologyId } = this.props;
|
||||
@@ -19,6 +29,7 @@ class TopologyOptions extends React.Component {
|
||||
<div className="topology-option-wrapper">
|
||||
{option.get('options').map(item => (
|
||||
<TopologyOptionAction
|
||||
onClick={this.handleOptionClick}
|
||||
optionId={optionId}
|
||||
topologyId={topologyId}
|
||||
key={item.get('value')}
|
||||
@@ -32,9 +43,10 @@ class TopologyOptions extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { options } = this.props;
|
||||
return (
|
||||
<div className="topology-options">
|
||||
{this.props.options && this.props.options.toIndexedSeq().map(
|
||||
{options && options.toIndexedSeq().map(
|
||||
option => this.renderOption(option))}
|
||||
</div>
|
||||
);
|
||||
@@ -50,5 +62,6 @@ function mapStateToProps(state) {
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps
|
||||
mapStateToProps,
|
||||
{ changeTopologyOption }
|
||||
)(TopologyOptions);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { is, fromJS } from 'immutable';
|
||||
import expect from 'expect';
|
||||
|
||||
import { TABLE_VIEW_MODE } from '../../constants/naming';
|
||||
// Root reducer test suite using Jasmine matchers
|
||||
import { constructEdgeId } from '../../utils/layouter-utils';
|
||||
@@ -307,7 +309,16 @@ describe('RootReducer', () => {
|
||||
expect(nextState.get('topologies').size).toBe(2);
|
||||
expect(nextState.get('currentTopology').get('name')).toBe('Topo1');
|
||||
expect(nextState.get('currentTopology').get('url')).toBe('/topo1');
|
||||
expect(nextState.get('currentTopology').get('options').first().get('id')).toBe('option1');
|
||||
expect(nextState.get('currentTopology').get('options').first().get('id')).toEqual(['option1']);
|
||||
expect(nextState.getIn(['currentTopology', 'options']).toJS()).toEqual([{
|
||||
id: 'option1',
|
||||
defaultValue: 'off',
|
||||
selectType: 'one',
|
||||
options: [
|
||||
{ value: 'on'},
|
||||
{ value: 'off'}
|
||||
]
|
||||
}]);
|
||||
});
|
||||
|
||||
it('get sub-topology', () => {
|
||||
@@ -318,7 +329,7 @@ describe('RootReducer', () => {
|
||||
expect(nextState.get('topologies').size).toBe(2);
|
||||
expect(nextState.get('currentTopology').get('name')).toBe('topo 1 grouped');
|
||||
expect(nextState.get('currentTopology').get('url')).toBe('/topo1-grouped');
|
||||
expect(nextState.get('currentTopology').get('options')).toBeUndefined();
|
||||
expect(nextState.get('currentTopology').get('options')).toNotExist();
|
||||
});
|
||||
|
||||
// topology options
|
||||
@@ -330,51 +341,49 @@ describe('RootReducer', () => {
|
||||
|
||||
// default options
|
||||
expect(activeTopologyOptionsSelector(nextState).has('option1')).toBeTruthy();
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('off');
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('off');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBeA('array');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['off']);
|
||||
|
||||
// turn on
|
||||
nextState = reducer(nextState, ChangeTopologyOptionAction);
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('on');
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('on');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['on']);
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['on']);
|
||||
|
||||
// turn off
|
||||
nextState = reducer(nextState, ChangeTopologyOptionAction2);
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('off');
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('off');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['off']);
|
||||
|
||||
// sub-topology should retain main topo options
|
||||
nextState = reducer(nextState, ClickSubTopologyAction);
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('off');
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('off');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['off']);
|
||||
|
||||
// other topology w/o options dont return options, but keep in app state
|
||||
nextState = reducer(nextState, ClickTopology2Action);
|
||||
expect(activeTopologyOptionsSelector(nextState)).toBeUndefined();
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('off');
|
||||
expect(activeTopologyOptionsSelector(nextState)).toNotExist();
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['off']);
|
||||
});
|
||||
it('changes topologyOptions for selectType "many"', () => {
|
||||
const action = {
|
||||
type: ActionTypes.CHANGE_TOPOLOGY_OPTION,
|
||||
|
||||
it('adds/removes a topology option', () => {
|
||||
const addAction = {
|
||||
type: ActionTypes.ADD_TOPOLOGY_OPTION,
|
||||
topologyId: 'services',
|
||||
option: 'namespace',
|
||||
value: ['scope', 'monitoring']
|
||||
value: 'scope'
|
||||
};
|
||||
const removeAction = {
|
||||
type: ActionTypes.REMOVE_TOPOLOGY_OPTION,
|
||||
topologyId: 'services',
|
||||
option: 'namespace',
|
||||
value: 'scope'
|
||||
};
|
||||
let nextState = initialState;
|
||||
nextState = reducer(nextState, {
|
||||
type: ActionTypes.RECEIVE_TOPOLOGIES,
|
||||
topologies
|
||||
});
|
||||
nextState = reducer(nextState, {
|
||||
type: ActionTypes.CLICK_TOPOLOGY,
|
||||
topologyId: 'services'
|
||||
});
|
||||
nextState = reducer(nextState, { type: ActionTypes.RECEIVE_TOPOLOGIES, topologies});
|
||||
nextState = reducer(nextState, { type: ActionTypes.CLICK_TOPOLOGY, topologyId: 'services' });
|
||||
|
||||
nextState = reducer(nextState, action);
|
||||
expect(activeTopologyOptionsSelector(nextState).toJS()).toEqual({
|
||||
namespace: ['scope', 'monitoring'],
|
||||
pseudo: 'hide'
|
||||
});
|
||||
nextState = reducer(nextState, addAction);
|
||||
});
|
||||
|
||||
it('sets topology options from route', () => {
|
||||
@@ -404,8 +413,8 @@ describe('RootReducer', () => {
|
||||
nextState = reducer(nextState, RouteAction);
|
||||
nextState = reducer(nextState, ReceiveTopologiesAction);
|
||||
nextState = reducer(nextState, ClickTopologyAction);
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('off');
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('off');
|
||||
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
|
||||
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['off']);
|
||||
});
|
||||
|
||||
// nodes delta
|
||||
@@ -423,7 +432,7 @@ describe('RootReducer', () => {
|
||||
it('shows nodes that were received', () => {
|
||||
let nextState = initialState;
|
||||
nextState = reducer(nextState, ReceiveNodesDeltaAction);
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
});
|
||||
|
||||
it('knows a route was set', () => {
|
||||
@@ -439,11 +448,11 @@ describe('RootReducer', () => {
|
||||
nextState = reducer(nextState, ClickNodeAction);
|
||||
|
||||
expect(nextState.get('selectedNodeId')).toBe('n1');
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
|
||||
nextState = reducer(nextState, deSelectNode);
|
||||
expect(nextState.get('selectedNodeId')).toBe(null);
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
});
|
||||
|
||||
it('keeps showing nodes on navigating back after node click', () => {
|
||||
@@ -460,7 +469,7 @@ describe('RootReducer', () => {
|
||||
RouteAction.state = {topologyId: 'topo1', selectedNodeId: null};
|
||||
nextState = reducer(nextState, RouteAction);
|
||||
expect(nextState.get('selectedNodeId')).toBe(null);
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
});
|
||||
|
||||
it('closes details when changing topologies', () => {
|
||||
@@ -486,12 +495,12 @@ describe('RootReducer', () => {
|
||||
it('resets topology on websocket reconnect', () => {
|
||||
let nextState = initialState;
|
||||
nextState = reducer(nextState, ReceiveNodesDeltaAction);
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
|
||||
nextState = reducer(nextState, CloseWebsocketAction);
|
||||
expect(nextState.get('websocketClosed')).toBeTruthy();
|
||||
// keep showing old nodes
|
||||
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
|
||||
expect(nextState.get('nodes').toJS()).toInclude(NODE_SET);
|
||||
|
||||
nextState = reducer(nextState, OpenWebsocketAction);
|
||||
expect(nextState.get('websocketClosed')).toBeFalsy();
|
||||
|
||||
@@ -87,15 +87,32 @@ export const initialState = makeMap({
|
||||
zoomCache: makeMap(),
|
||||
});
|
||||
|
||||
function calcSelectType(topology) {
|
||||
const result = {
|
||||
...topology,
|
||||
options: topology.options && topology.options.map((option) => {
|
||||
// Server doesn't return the `selectType` key unless the option is something other than `one`.
|
||||
// Default to `one` if undefined, so the component doesn't have to handle this.
|
||||
option.selectType = option.selectType || 'one';
|
||||
return option;
|
||||
})
|
||||
};
|
||||
|
||||
if (topology.sub_topologies) {
|
||||
result.sub_topologies = topology.sub_topologies.map(calcSelectType);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// adds ID field to topology (based on last part of URL path) and save urls in
|
||||
// map for easy lookup
|
||||
function processTopologies(state, nextTopologies) {
|
||||
// filter out hidden topos
|
||||
const visibleTopologies = filterHiddenTopologies(nextTopologies);
|
||||
|
||||
// set `selectType` field for topology and sub_topologies options (recursive).
|
||||
const topologiesWithSelectType = visibleTopologies.map(calcSelectType);
|
||||
// add IDs to topology objects in-place
|
||||
const topologiesWithId = updateTopologyIds(visibleTopologies);
|
||||
|
||||
const topologiesWithId = updateTopologyIds(topologiesWithSelectType);
|
||||
// cache URLs by ID
|
||||
state = state.set('topologyUrlsById',
|
||||
setTopologyUrlsById(state.get('topologyUrlsById'), topologiesWithId));
|
||||
@@ -106,8 +123,7 @@ function processTopologies(state, nextTopologies) {
|
||||
}
|
||||
|
||||
function setTopology(state, topologyId) {
|
||||
state = state.set('currentTopology', findTopologyById(
|
||||
state.get('topologies'), topologyId));
|
||||
state = state.set('currentTopology', findTopologyById(state.get('topologies'), topologyId));
|
||||
return state.set('currentTopologyId', topologyId);
|
||||
}
|
||||
|
||||
@@ -118,7 +134,7 @@ function setDefaultTopologyOptions(state, topologyList) {
|
||||
topology.get('options').forEach((option) => {
|
||||
const optionId = option.get('id');
|
||||
const defaultValue = option.get('defaultValue');
|
||||
defaultOptions = defaultOptions.set(optionId, defaultValue);
|
||||
defaultOptions = defaultOptions.set(optionId, [defaultValue]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,7 +201,7 @@ export function rootReducer(state = initialState, action) {
|
||||
}
|
||||
state = state.setIn(
|
||||
['topologyOptions', topologyId, action.option],
|
||||
action.value
|
||||
[action.value]
|
||||
);
|
||||
}
|
||||
return state;
|
||||
|
||||
Reference in New Issue
Block a user