Created
April 10, 2019 18:26
-
-
Save DarkSector/3a58e7d4dace19ac58b25957736ab783 to your computer and use it in GitHub Desktop.
_this.props.loadConfig is not a function
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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