ice-frontend-react-mobx
Version:
ICE Frontend REACT+MobX
409 lines (345 loc) • 12.1 kB
JavaScript
const debug = require('debug')('ice:Zones:ZoneBuilder'); // eslint-disable-line no-unused-vars
import React, { Component, PropTypes } from 'react';
import { Dialog, Input, Tab, Tabs } from 'react-toolbox';
import { inject, observer } from 'mobx-react';
import Notify from '../../../common/helpers/Notify';
let styles = require('./ZoneBuilder.css');
import { RackDropTarget, RackDragSource, RackDroppedCard, GroupDropTarget, GroupDragSource, GroupDroppedCard } from '../../common/dnd';
const defaultState = {
tabIndex: 1,
zone: null,
racks: [],
groups: [],
feeds: [],
breakerLimits: {},
iceLimits: {}
};
export default class ZoneBuilder extends Component {
constructor (props) {
super(props);
this.zones = this.props.store.zoneStore;
this.groups = this.props.store.groupStore;
this.racks = this.props.store.rackStore;
this.devices = this.props.store.deviceStore;
this.feeds = this.props.store.feedStore;
this.wordStore = this.props.store.wordStore;
this.state = defaultState;
}
_getAllDeviceIds (groups, racks) {
let devices = [];
groups.forEach((group) => {
devices = devices.concat(group.deviceIds.slice());
});
racks.forEach((rack) => {
devices = devices.concat(rack.rpduIds.slice());
});
// dedupe
let seen = {};
devices = devices.filter((item) => {
return seen.hasOwnProperty(item) ? false : (seen[item] = true);
});
return devices;
}
_computeUsedFeeds = (groups, racks) => {
debug('state.groups', this.state.groups);
let groupDevices = groups.reduce((devices, group) => {
debug('Group:', group);
return devices.concat(group.devices.slice());
}, []);
let rackDevices = racks.reduce((devices, rack) => {
return devices.concat(rack.rpdus.slice());
}, []);
debug('g devices:', groupDevices, 'r devices:', rackDevices);
let devices = groupDevices.concat(rackDevices);
let feeds = {};
devices.forEach((device) => {
if (device.feed) {
feeds[device.feed.id] = true;
}
});
return Object.keys(feeds).map((feedId) => {
return this.feeds.getById(feedId);
});
}
componentWillReceiveProps (nextProps) {
if (nextProps.zoneId) {
let zone = this.zones.getById(nextProps.zoneId);
let groups = zone.groups.slice();
let racks = zone.racks.slice();
let feeds = this._computeUsedFeeds(groups, racks);
let breakerLimits = zone.breakerLimits.reduce((limits, bl) => {
limits[bl.feed] = bl;
return limits;
}, {});
let iceLimits = zone.iceLimits.reduce((limits, il) => {
limits[il.feed] = il;
return limits;
}, {});
this.setState({
tabIndex: 0,
zone: zone,
racks: racks,
groups: groups,
feeds: feeds,
breakerLimits: breakerLimits,
iceLimits: iceLimits
});
}
}
cancel = () => {
this.props.onCancel();
}
save = () => {
let zone = this.state.zone;
zone.groups.replace(this.state.groups);
zone.racks.replace(this.state.racks);
zone.breakerLimits.clear();
zone.iceLimits.clear();
this.state.feeds.forEach((feed) => {
let id = feed.id;
let limitA = (this.state.breakerLimits[id] && this.state.breakerLimits[id].limitA) ? this.state.breakerLimits[id].limitA : 0;
let nominalVoltage = (this.state.breakerLimits[id] && this.state.breakerLimits[id].nominalVoltage) ? this.state.breakerLimits[id].nominalVoltage : 0;
let deratingFactor = (this.state.breakerLimits[id] && this.state.breakerLimits[id].deratingFactor) ? this.state.breakerLimits[id].deratingFactor : 0;
zone.breakerLimits.push({
feed: id,
limitA: limitA,
nominalVoltage: nominalVoltage,
deratingFactor: deratingFactor
});
let limitW = (this.state.iceLimits[id] && this.state.iceLimits[id].limitW) ? this.state.iceLimits[id].limitW : 0;
zone.iceLimits.push({
feed: id,
limitW: limitW
});
});
zone.save().then(() => {
Notify.success(this.wordStore.translate('Zone saved'));
this.props.onSave();
}).catch((error) => {
if (error.response && error.response.data && error.response.data.errorMessage) {
Notify.error(error.response.data.errorMessage);
} else {
Notify.error(this.wordStore.translate('Error saving zone'));
}
this.props.onSave();
});
}
dropRack = (item) => {
item = this.racks.getById(item.id);
let racks = this.state.racks.concat(item);
let feeds = this._computeUsedFeeds(this.state.groups, racks);
this.setState({racks: racks, feeds: feeds});
}
dropGroup = (group) => {
group = this.groups.getById(group.id);
let groups = this.state.groups.concat(group);
let feeds = this._computeUsedFeeds(groups, this.state.racks);
this.setState({groups: groups, feeds: feeds});
}
deleteRack = (rack) => {
let racks = this.state.racks.filter((item) => {
return item.id !== rack.id;
});
let feeds = this._computeUsedFeeds(this.state.groups, racks);
this.setState({racks: racks, feeds: feeds});
}
deleteGroup = (group) => {
let groups = this.state.groups.filter((item) => {
return item.id !== group.id;
});
let feeds = this._computeUsedFeeds(groups, this.state.racks);
this.setState({groups: groups, feeds: feeds});
}
handleTabChange = (tabIndex) => {
this.setState({tabIndex});
}
handleBreakerLimitChange (feed, field, value) {
let newState = { breakerLimits: this.state.breakerLimits };
if (!newState.breakerLimits[feed.id]) {
newState.breakerLimits[feed.id] = {};
}
newState.breakerLimits[feed.id][field] = value;
this.setState(newState);
}
handleIceLimitChange (feed, field, value) {
let newState = { iceLimits: this.state.iceLimits };
if (!newState.iceLimits[feed.id]) {
newState.iceLimits[feed.id] = {};
}
newState.iceLimits[feed.id][field] = value;
this.setState(newState);
}
renderGroupDragList () {
let zoneGroupIds = (this.state.zone && this.state.zone.groups) ? this.state.zone.groups : [];
let usedGroups = this.zones.usedGroups.filter((used) => (zoneGroupIds.indexOf(used) === -1)).concat(this.state.groups.map((group) => (group.id)));
let groups = this.groups.all.filter((group) => {
return usedGroups.indexOf(group.id) === -1;
}).map((group, index) => {
return <GroupDragSource key={index} id={group.id} name={group.name} />;
});
return (
<div className={styles.dragSourceWrapper}>
<h5>Groups:</h5>
<div className={styles.dragSourceContent}>
<div className={styles.dragSourceList}>
{groups}
</div>
</div>
</div>
);
}
renderGroupDropTarget () {
let groups = this.state.groups.map((group, index) => {
return <GroupDroppedCard key={index} group={group} onDelete={this.deleteGroup} />;
});
return (
<div className={styles.targetsWrapper}>
<GroupDropTarget onDrop={this.dropGroup}>
{groups}
</GroupDropTarget>
</div>
);
}
renderGroupsTab () {
return (
<div className={styles.dragWrapper}>
{this.renderGroupDropTarget()}
{this.renderGroupDragList()}
</div>
);
}
renderRacksDragList () {
let zoneRackIds = (this.state.zone && this.state.zone.rackIds) ? this.state.zone.rackIds : [];
let usedRacks = this.zones.usedRacks.filter((used) => (zoneRackIds.indexOf(used) === -1)).concat(this.state.racks.map((rack) => (rack.id)));
let racks = this.racks.all.filter((rack) => {
return usedRacks.indexOf(rack.id) === -1;
}).map((rack) => {
return <RackDragSource key={rack.id} name={rack.name} type={rack.redundancy} id={rack.id} />;
});
return (
<div className={styles.dragSourceWrapper}>
<h5>Racks:</h5>
<div className={styles.dragSourceContent}>
<div className={styles.dragList}>
{racks}
</div>
</div>
</div>
);
}
renderRackDropTarget () {
let racks = this.state.racks.map((rack) => {
return <RackDroppedCard key={rack.id} rack={rack} onDelete={this.deleteRack} />;
});
return (
<div className={styles.targetsWrapper}>
<RackDropTarget onDrop={this.dropRack}>
{racks}
</RackDropTarget>
</div>
);
}
renderRacksTab () {
return (
<div className={styles.dragWrapper}>
{this.renderRackDropTarget()}
{this.renderRacksDragList()}
</div>
);
}
renderBreakerLimitsTab () {
let forms = this.state.feeds.map((feed, index) => {
let limitA = (this.state.breakerLimits[feed.id] && this.state.breakerLimits[feed.id].limitA) ? this.state.breakerLimits[feed.id].limitA : '';
let nominalVoltage = (this.state.breakerLimits[feed.id] && this.state.breakerLimits[feed.id].nominalVoltage) ? this.state.breakerLimits[feed.id].nominalVoltage : '';
let deratingFactor = (this.state.breakerLimits[feed.id] && this.state.breakerLimits[feed.id].deratingFactor) ? this.state.breakerLimits[feed.id].deratingFactor : '';
return (
<div key={index}>
<h6>{feed.name}</h6>
<div className={styles.threeColumn}>
<div className={styles.column}>
<Input
type='text'
label={this.wordStore.translate('LimitA')}
value={limitA}
onChange={this.handleBreakerLimitChange.bind(this, feed, 'limitA')} />
</div>
<div className={styles.column}>
<Input
type='text'
label={this.wordStore.translate('Nominal Voltage')}
value={nominalVoltage}
onChange={this.handleBreakerLimitChange.bind(this, feed, 'nominalVoltage')} />
</div>
<div className={styles.column}>
<Input
type='text'
label={this.wordStore.translate('Derating Factor')}
value={deratingFactor}
onChange={this.handleBreakerLimitChange.bind(this, feed, 'deratingFactor')} />
</div>
</div>
</div>
);
});
return (
<div>{forms}</div>
);
}
renderIceLimitsTab () {
let forms = this.state.feeds.map((feed, index) => {
let limitW = (this.state.iceLimits[feed.id] && this.state.iceLimits[feed.id].limitW) ? this.state.iceLimits[feed.id].limitW : '';
return (
<div key={index}>
<h6>{feed.name}</h6>
<Input
type='text'
label={this.wordStore.translate('LimitW')}
value={limitW}
onChange={this.handleIceLimitChange.bind(this, feed, 'limitW')} />
</div>
);
});
return (
<div>{forms}</div>
);
}
render () {
let actions = [
{ label: 'Cancel', onClick: this.cancel },
{ label: 'Save', onClick: this.save }
];
let name = (this.state.zone && this.state.zone.name) ? this.state.zone.name : '';
let title = 'Configure Zone: ' + name;
return (
<Dialog
title={title}
active={this.props.active}
actions={actions}
type='normal'>
<section>
<Tabs index={this.state.tabIndex} onChange={this.handleTabChange} fixed>
<Tab label='Groups'>
<div>{this.renderGroupsTab()}</div>
</Tab>
<Tab label='Racks'>
{this.renderRacksTab()}
</Tab>
<Tab label='Breaker Limits'>
{this.renderBreakerLimitsTab()}
</Tab>
<Tab label='ICE Limits'>
{this.renderIceLimitsTab()}
</Tab>
</Tabs>
</section>
</Dialog>
);
}
}
ZoneBuilder.wrappedComponent.propTypes = {
active: PropTypes.bool.isRequired,
zoneId: PropTypes.string,
onCancel: PropTypes.func.isRequired,
onSave: PropTypes.func.isRequired
};