Skip to content

Instantly share code, notes, and snippets.

@DarkSector
Created April 10, 2019 18:26
Show Gist options
  • Select an option

  • Save DarkSector/3a58e7d4dace19ac58b25957736ab783 to your computer and use it in GitHub Desktop.

Select an option

Save DarkSector/3a58e7d4dace19ac58b25957736ab783 to your computer and use it in GitHub Desktop.
_this.props.loadConfig is not a function
import React from 'react'
import { connect } from 'react-redux'
import { Button, Card } from 'antd'
import { executeCapability, loadConfig } from '../ducks/nodes'
class Capability extends React.Component {
constructor (props) {
super(props)
this.renderContent = this.renderContent.bind(this)
}
renderContent () {
return this.props.capabilities.map(capabilityObject => {
return <Card.Grid key={capabilityObject.name} style={gridStyle}>
<Button onClick={() => {
this.props.executeCapability(this.props.currentNode.name, capabilityObject.name)
}} type="primary">{capabilityObject.name.toUpperCase()}</Button>
<Button onClick={() => {
this.props.loadConfig(this.props.currentNode.name, capabilityObject.name)
}}>Config</Button>
</Card.Grid>
})
}
render () {
return (
<Card>
{this.renderContent()}
</Card>
)
}
}
const mapStateToProps = (state) => {
let capabilities = []
if (state.nodes.capabilities[state.nodes.current_node.name] !== undefined) {
capabilities = Object.entries(state.nodes.capabilities[state.nodes.current_node.name]).map((item, index) => {
let capabilityName = item[0]
// let capabilityData = item[1]
return { name: capabilityName }
})
}
return {
capabilities,
currentNode: state.nodes.current_node
}
}
const gridStyle = {
width: '100%',
display: 'flex',
justifyContent: 'space-between',
alignContent: 'space-evenly',
alignItems: 'center'
}
export default connect(mapStateToProps, { executeCapability, loadConfig })(Capability)
import axios from 'axios'
import capability from '../components/capability'
// actions
export let DISCOVERED = 'discovered'
export let LOADING_NODES = 'loadingnodes'
export let NODE_SELECTED = 'nodeselected'
export let LOADING_CAPABILITIES = 'loadingcapabilities'
export let CAPABILITIES_LOADED = 'capabilitiesloaded'
export let CAPABILITY_REQUEST_ERROR = 'capabilityrequesterror'
export let CAPABILITY_EXECUTION_UNDERWAY = 'capabilityexecuting'
export let CAPABILITY_EXECUTED = 'capabilityexecuted'
export let CAPABILITY_EXECUTION_FAILED = 'capabilityexecutionfailed'
export let LOADING_CONFIG = 'loadingconfig'
export let SHOW_CONFIG = 'showconfig'
export let HIDE_CONFIG = 'hideconfig'
export let CONFIG_ERROR = 'configerror'
export let CONFIG_FETCHED = 'configfetched'
export let SHOW_CARD = 0
export let SHOW_SPINNER = 1
export let SHOW_CONFIG_ON_CARD = 2
export let SHOW_ERROR_ON_CARD = 3
// initial state
const initialState = {
nodes: {},
current_node: { name: 'Home' },
loading: false,
capabilities: {},
loadingCapabilities: false,
requestError: {},
config: {}, // per nodeKey per capability
showConfig: {},
showConfigCard: {}
}
const nodeFilter = (nodeKey, nodes) => {
if (nodeKey === 'Home') {
return {
name: 'Home',
key: 'Home'
}
}
let nodeList = []
let nodeInfo = {}
Object.entries(nodes).map(item => {
let node = item[1]
node.forEach(x => {
nodeList.push(x)
})
})
nodeList.forEach(x => {
if (x.name === nodeKey) {
nodeInfo = x
}
})
return nodeInfo
}
const generateConfigFromCapabilities = (nodeKey, capabilities) => {
let capabilityObj = { [nodeKey]: {} }
Object.entries(capabilities).map(itemArray => {
let capabilityName = itemArray[0]
let capabilityConfig = itemArray[1].kwargs
capabilityObj[nodeKey][capabilityName] = capabilityConfig
})
return capabilityObj
}
export default function reducer (currentState = initialState, action) {
switch (action.type) {
case LOADING_NODES:
return {
...currentState,
loading: true
}
case DISCOVERED:
let node_list = {}
action.payload.forEach(x => {
if (x['type'] in node_list) {
node_list[x['type']].push(x)
} else {
node_list[x['type']] = [x]
}
})
return {
...currentState,
nodes: node_list,
loading: false,
current_node: { name: 'Home' }
}
case NODE_SELECTED:
return {
...currentState,
loading: false,
current_node: nodeFilter(action.payload, currentState.nodes)
}
case LOADING_CAPABILITIES:
return {
...currentState,
loading: false,
loadingCapabilities: true,
capabilities: { [action.payload.name]: [] }
}
case CAPABILITIES_LOADED:
return {
...currentState,
loading: false,
loadingCapabilities: false,
capabilities: { [action.payload.name]: action.payload.capabilities }
// config: generateConfigFromCapabilities(currentState.current_node.name, action.payload.capabilities)
}
case CAPABILITY_REQUEST_ERROR:
return {
...currentState,
loading: false,
loadingCapabilities: false,
requestError: { ...currentState['requestError'], [action.payload.name]: action.payload.error }
}
case SHOW_CONFIG:
let requiredShowConfigObject = { ...currentState.showConfigCard }
if (requiredShowConfigObject[action.payload.nodeKey]) {
requiredShowConfigObject[action.payload.nodeKey][action.payload.capabilityName] = true
} else {
requiredShowConfigObject[action.payload.nodeKey] = { [action.payload.capabilityName]: true }
}
return {
...currentState,
showConfigCard: requiredShowConfigObject
}
case LOADING_CONFIG:
requiredShowConfigObject = { ...currentState.showConfig }
requiredShowConfigObject[action.payload.nodeKey] = { [action.payload.capabilityName]: SHOW_SPINNER }
return {
...currentState,
showConfig: requiredShowConfigObject
}
case CONFIG_FETCHED:
let configObject = { ...currentState.config }
requiredShowConfigObject = { ...currentState.showConfig }
requiredShowConfigObject[action.payload.nodeKey] = { [action.payload.capabilityName]: SHOW_CONFIG_ON_CARD }
if (configObject[action.payload.nodeKey]) {
configObject[action.payload.nodeKey][action.payload.capabilityName] = action.payload.configResult
} else {
configObject[action.payload.nodeKey] = { [action.payload.capabilityName]: action.payload.configResult }
}
return {
...currentState,
showConfig: requiredShowConfigObject,
config: configObject
}
case CONFIG_ERROR:
requiredShowConfigObject = { ...currentState.showConfig }
requiredShowConfigObject[action.payload.nodeKey] = { [action.payload.capabilityName]: SHOW_ERROR_ON_CARD }
return {
...currentState,
showConfig: requiredShowConfigObject
}
case HIDE_CONFIG:
let currentConfig = { ...currentState.showConfig }
currentConfig[action.payload.nodeKey][action.payload.capabilityName] = false
return {
...currentState,
showConfig: currentConfig
}
default:
return currentState
}
}
// action creators
export const foundAvailableNodes = (nodes) => {
return { type: DISCOVERED, payload: nodes }
}
export const findingNodes = () => {
return { type: LOADING_NODES }
}
export const nodeSelected = (nodeKey) => {
return { type: NODE_SELECTED, payload: nodeKey }
}
export const loadingCapabilities = (name) => {
return {
type: LOADING_CAPABILITIES,
payload: {name}
}
}
export const capabilitiesFetched = (name, capabilities) => {
return {
type: CAPABILITIES_LOADED,
payload: { name, capabilities }
}
}
export const requestError = (name, error) => {
return {
type: CAPABILITY_REQUEST_ERROR,
payload: {
name, error
}
}
}
export const executingCapability = (name, capabilityName) => {
return {
type: CAPABILITY_EXECUTION_UNDERWAY,
payload: {name, capabilityName}
}
}
export const capabilityExecuted = (nodeKey, capabilityName, response) => {
return {
type: CAPABILITY_EXECUTED,
payload: {
nodeKey,
capabilityName,
response
}
}
}
export const capabilityExecutionFailed = (nodeKey, capabilityName, error) => {
return {
type: CAPABILITY_EXECUTION_FAILED,
payload: {}
}
}
export const fetchingConfig = (nodeKey, capabilityName) => {
return {
type: LOADING_CONFIG,
payload: {
nodeKey, capabilityName
}
}
}
export const showConfig = (nodeKey, capabilityName) => {
return {
type: SHOW_CONFIG,
payload: {
nodeKey, capabilityName
}
}
}
export const configFetched = (nodeKey, capabilityName, configResult) => {
return {
type: CONFIG_FETCHED,
payload: {
nodeKey, capabilityName, configResult
}
}
}
export const configError = (nodeKey, capabilityName, error) => {
return {
type: CONFIG_ERROR,
payload: {
nodeKey, capabilityName, error
}
}
}
export const hideConfig = (nodeKey, capabilityName) => {
return {
type: HIDE_CONFIG,
payload: {
nodeKey, capabilityName
}
}
}
// async thunks
export const discoverBroadcastingNodes = () => async dispatch => {
// here try and get all the available nodes broadcasting their position
dispatch(findingNodes())
let nodes = [
{
ip: '192.168.128.205',
port: 5511,
name: 'MEG',
tag: 'meg',
type: 'device'
},
{
ip: '192.168.31.55',
port: 5512,
name: 'EEG',
tag: 'eeg',
type: 'device'
},
{
ip: '192.168.31.51',
port: 5322,
name: 'Dekode',
tag: 'dekode',
type: 'analysis'
},
{
ip: '192.168.31.59',
port: 5321,
name: 'Twin ball',
tag: 'twin_ball',
type: 'task'
}]
dispatch(foundAvailableNodes(nodes))
}
export const selectNode = (nodeKey) => async (dispatch, getState) => {
dispatch(nodeSelected(nodeKey))
dispatch(loadCapabilitiesOnPage(nodeKey))
}
// fetch capabilities
export const loadCapabilitiesOnPage = (name) => async (dispatch, getState) => {
dispatch(loadingCapabilities(name))
if (name !== 'Home') {
let currentNode = getState().nodes.current_node
let url = `http://${currentNode.ip}:${currentNode.port}/${currentNode.tag}/`
axios.get(url, {
headers: { 'Access-Control-Allow-Origin': '*' }
})
.then(response => {
dispatch(capabilitiesFetched(name, response.data.capabilities))
})
.catch(error => {
if (error.request) {
dispatch(requestError(name, 'The server didn\'t respond. Are you sure that the client is running?'))
} else {
dispatch(requestError(name, 'Something went wrong, please try again'))
}
})
} else {
dispatch(capabilitiesFetched('Home', []))
}
}
// execute capability
export const executeCapability = (nodeKey, name) => async (dispatch, getState) => {
dispatch(executingCapability(nodeKey, name))
const { current_node, config } = getState().nodes
// console.log("current node: ", current_node)
let url = `http://${current_node.ip}:${current_node.port}/${current_node.tag}/${name}`
axios.post(url, JSON.stringify({
kwargs: config[nodeKey][name] ? config[nodeKey][name] : {},
args: []
}))
.then(response => {
// execution failed or succeeded
if (response.status === 200) {
capabilityExecuted(nodeKey, name, response.data.result)
}
})
.catch(error => {
// execution failed
// action must be picked up by the timeline reducer as well
capabilityExecutionFailed(nodeKey, name, 'Error executing capability')
})
}
// Show configuration window
// fetch corresponding config from remote server
export const loadConfig = (nodeKey, name) => async (dispatch, getState) => {
console.log("coming here")
// show config
dispatch(showConfig(nodeKey, name))
// fetching config
dispatch(fetchingConfig(nodeKey, name))
let currentNode = getState().nodes.current_node
let url = `http://${currentNode.ip}:${currentNode.port}/${currentNode.tag}/_${name}`
axios.post(url, JSON.stringify({
kwargs: {},
args: []
}))
.then(response => {
dispatch(configFetched(nodeKey, name, response.data.result))
})
.catch(error => {
console.log(error)
dispatch(configError(nodeKey, name, 'Something went wrong, trying to fetch the default config'))
})
}
// Hide configuration window
export const unloadConfig = (nodeKey, name) => async (dispatch, getState) => {
dispatch(hideConfig(nodeKey, name))
}
export const updateElementForConfig = (path, value) => async (dispatch, getState) => {
console.log('updating element: ', path, ' ', value)
let config = getState().nodes.config
}
import React from 'react'
import { connect } from 'react-redux'
import { Row, Col, Spin, Card, Table, Alert, Button } from 'antd'
import Capability from './capability'
import Log from './log'
import Config from './config'
import { loadCapabilitiesOnPage } from '../ducks/nodes'
const NodeInfo = (props) => {
return (
<Card title="Node details" bordered={false}>
<Table
size="small"
bordered
pagination={false}
columns={[
{
title: 'Key',
dataIndex: 'dataKey',
key: 'dataKey',
render: text => <strong>{text.toUpperCase()}</strong>
},
{
title: 'Value',
dataIndex: 'dataValue',
key: 'dataValue'
}
]}
dataSource={props.data}
/>
</Card>
)
}
class Node extends React.Component {
constructor (props) {
super(props)
this.renderData = this.renderData.bind(this)
}
renderData () {
if (this.props.loadingCapabilities) {
return (
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Spin size="large"/>
</div>
)
} else if (this.props.requestError) {
return (
<div>
<Alert
message="Error"
description={this.props.requestError}
type="error"
showIcon
/>
<Button
style={{ marginTop: 10 }}
type="primary"
onClick={() => {
this.props.loadCapabilitiesOnPage(this.props.nodeData.name)
}}>
Retry
</Button>
</div>
)
} else {
return <Capability/>
}
}
render () {
return (
<div>
<Row gutter={8}>
<Col span={8}>
<NodeInfo name={this.props.nodeData.name} data={this.props.nodeData.data}/>
</Col>
<Col span={16}>
<Card
title="Capabilities"
extra={
<Button
icon="reload"
shape="circle"
size="small"
onClick={() => {this.props.loadCapabilitiesOnPage(this.props.nodeData.name)}}/>}
>
{this.renderData()}
</Card>
</Col>
</Row>
<Row>
<Col span={24}>
<Config/>
</Col>
</Row>
<Row>
<Col span={24}>
<Log name={this.props.nodeData.name}/>
</Col>
</Row>
</div>
)
}
}
const mapStateToProps = state => {
let data = Object.entries(state.nodes.current_node).map(dataArray => {
let dataKey = dataArray[0]
let dataValue = dataArray[1]
return {
key: dataKey,
dataKey: dataKey,
dataValue: dataValue
}
})
return {
nodeData: { name: state.nodes.current_node.name, data },
capabilities: state.nodes.capabilities,
error: state.nodes.requestError,
loadingCapabilities: state.nodes.loadingCapabilities,
requestError: state.nodes.requestError[state.nodes.current_node.name]
}
}
export default connect(mapStateToProps, {
loadCapabilitiesOnPage
})(Node)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment