UNPKG

smart-home

Version:

Netbeast dashboard, IoT apps manager

179 lines (150 loc) 5.82 kB
/* global toastr */ import React from 'react' import mqtt from 'mqtt' import request from 'superagent-bluebird-promise' import { OverlayTrigger, Popover } from 'react-bootstrap' import Pulse from '../misc/activity-pulse.jsx' import { Session } from '../lib' export default class App extends React.Component { constructor (props, context) { super(props) this.state = { isRunning: false, inactive: false, menuHidden: true } this.router = context.router } handleClick () { const { type } = this.props if (type !== 'explore') this.launch() } toggleMenu (event) { if (event) event.preventDefault() && event.stopPropagation() const { menuHidden } = this.state if (menuHidden) this.refs.contextMenu.show() else this.refs.contextMenu.hide() this.setState({ menuHidden: !menuHidden }) } launch () { const { name } = this.props request.post('/api/activities/' + name).then(() => { return request.get('/i/' + name).promise() }).then(() => { this.router.push('/live/' + name) }).catch((err) => { if (err.status === 404) { this.setState({ isRunning: true }) return toastr.info(`${name} is running`) } if (err.res) toastr.error(err.res.text) else toastr.error(err.message) }) } install () { const url = this.props.git_url const loader = window.notify({ body: ( <span> <div className='loader'></div> Installing app... </span> ), timeout: 0} ) request.post('/api/apps').send({ url }).then((res) => { const name = res.body.name const props = res.body.netbeast const type = props ? props.type : 'app' toastr.success(`${name} has been installed!`) toastr.dismiss(loader) if (type === 'plugin' || type === 'service' || props.bootOnLoad) return request.post('/api/activities/' + name).promise() }).then((res) => { toastr.success(`${res.body.name} is running`) }) .catch((fail, res) => toastr.error(res.text)) } stop () { const { name, kind, dismiss } = this.props request.del('/api/activities/' + name).end((err, res) => { if (err) return this.setState({ isRunning: false }) toastr.info(name + ' has been stopped.') if (kind !== 'apps' && kind !== 'plugins') dismiss(name) }) } uninstall () { const { name, kind, dismiss } = this.props if (!confirm('Do you really want to remove', name, '?')) return const loader = window.notify({ body: ( <span> <div className='loader'></div> Uninstalling {name}... </span> ), timeout: 0} ) request.del('/api/apps/' + name).end((err, res) => { if (err) return dismiss(name) toastr.dismiss(loader) toastr.info(name + ' has been removed.') }) } contextMenu () { const { name, netbeast } = this.props const settings = netbeast && netbeast.settings return ( <Popover id={name} className='context-menu'> <a href='javascript:void(0)' onClick={this.stop.bind(this)} className='stop btn btn-filled btn-warning'> Stop </a> <a href='javascript:void(0)' onClick={this.uninstall.bind(this)} className='remove btn btn-filled btn-primary'> Remove </a> {settings ? <a onClick={this.router.push.bind(this, '/i/' + name + ((settings === true && typeof settings === 'boolean') ? '/settings' : settings))} className='settings btn btn-filled btn-success'> Settings </a> : null} </Popover> ) } renderButton () { const { kind, git_url } = this.props switch (kind) { case 'activities': return <a href='javascript:void(0)' onClick={this.stop.bind(this)} className='stop btn btn-filled btn-warning'> Stop </a> case 'remove': return <a href='javascript:void(0)' onClick={this.uninstall.bind(this)} className='remove btn btn-filled btn-primary'> Remove </a> case 'explore': return <a href='javascript:void(0)' onClick={API.install.bind(API, git_url)} className='install btn btn-filled btn-info'> Install </a> } } componentDidMount () { const { name, netbeast } = this.props this.mqtt = mqtt.connect(window.mqttUri) this.mqtt.subscribe('netbeast/activities/close') this.mqtt.on('message', (topic, message) => { if (message.toString() === name) this.setState({ isRunning: false }) }) request.get('/api/activities/' + name).end((err, res) => { if (!err && res.body.port > 0) this.setState({ isRunning: true }) }) if (netbeast && (netbeast.type === 'plugin')) { const devices = Session.load('devices') || [] const found = devices.find((d) => { return d.app === name }) this.setState({ inactive: !found }) } } componentWillUnmount () { this.mqtt.end() } render () { const { name, author, logo, netbeast } = this.props const isPlugin = netbeast && (netbeast.type === 'plugin') const defaultLogo = isPlugin ? 'url(/img/plugin.png)' : 'url(/img/dflt.png)' const logoStyle = { backgroundImage: logo ? `url(/api/apps/${name}/logo)` : defaultLogo } const { inactive, isRunning } = this.state const inactiveClass = inactive && isRunning ? ' warning' : '' return ( <div className={'app' + inactiveClass}> {(isRunning) ? <Pulse {...this.props} /> : null} <OverlayTrigger ref='contextMenu' trigger={[]} rootClose placement='bottom' overlay={this.contextMenu()}> <div className='logo' title='Launch app' style={logoStyle} onClick={this.handleClick.bind(this)} onContextMenu={this.toggleMenu.bind(this)} /> </OverlayTrigger> {this.renderButton()} <p className='name'>{name}</p> </div> ) } } App.contextTypes = { router: React.PropTypes.object.isRequired }