UNPKG

ice-frontend-react-mobx

Version:
409 lines (345 loc) 12.1 kB
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: {} }; @inject('store') @observer 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 };