From 558f0b37e194c5616a7a40c83ea7d4bb24a739ad Mon Sep 17 00:00:00 2001 From: futpib Date: Thu, 22 Nov 2018 17:12:53 +0300 Subject: [PATCH] wip --- actions/preferences.js | 2 + actions/pulse.js | 3 + components/graph/base.js | 4 + components/modals/add-remote-server-modal.js | 83 ++++++++++++++++++++ components/modals/index.js | 12 +++ components/network/index.js | 78 +++++++++++++++++- index.css | 7 ++ reducers/preferences.js | 12 ++- reducers/pulse.js | 9 +++ selectors/index.js | 4 + 10 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 components/modals/add-remote-server-modal.js diff --git a/actions/preferences.js b/actions/preferences.js index edc88ea..cb9eed4 100644 --- a/actions/preferences.js +++ b/actions/preferences.js @@ -6,5 +6,7 @@ module.exports = createActionCreators({ SET: null, TOGGLE: null, RESET_DEFAULTS: null, + SET_ADD: (key, value) => ({ key, value }), + SET_DELETE: (key, value) => ({ key, value }), }, }); diff --git a/actions/pulse.js b/actions/pulse.js index a88b705..635b6ed 100644 --- a/actions/pulse.js +++ b/actions/pulse.js @@ -46,5 +46,8 @@ module.exports = createActionCreators({ SET_DEFAULT_SINK_BY_NAME: name => ({ name }), SET_DEFAULT_SOURCE_BY_NAME: name => ({ name }), + + REMOTE_SERVER_CONNECT: null, + REMOTE_SERVER_DISCONNECT: null, }, }); diff --git a/components/graph/base.js b/components/graph/base.js index 7595e3b..e42f0c3 100644 --- a/components/graph/base.js +++ b/components/graph/base.js @@ -290,6 +290,10 @@ class Node extends NodeBase { } EdgeBase.calculateOffset = function (nodeSize, source, target) { + // if (!source || !target) { + // return this.getDefaultIntersectResponse(); + // } + const arrowVector = math.matrix([ target.x - source.x, target.y - source.y ]); const offsetLength = Math.max(0, Math.min((0.75 * size), (math.norm(arrowVector) / 2) - 40)); const offsetVector = math.dotMultiply(arrowVector, (offsetLength / math.norm(arrowVector)) || 0); diff --git a/components/modals/add-remote-server-modal.js b/components/modals/add-remote-server-modal.js new file mode 100644 index 0000000..01b3d87 --- /dev/null +++ b/components/modals/add-remote-server-modal.js @@ -0,0 +1,83 @@ + +const r = require('r-dom'); + +const React = require('react'); + +const { connect } = require('react-redux'); +const { bindActionCreators } = require('redux'); + +const Modal = require('react-modal'); + +const Button = require('../button'); +const Label = require('../label'); +const Input = require('../input'); + +const { + preferences: preferencesActions, +} = require('../../actions'); + +class AddRemoteServerModal extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + address: 'tcp:remote-computer.lan', + }; + + this.handleSubmit = this.handleSubmit.bind(this); + } + + handleSubmit(e) { + e.preventDefault(); + + const { address } = this.state; + this.props.setAdd('remoteServerAddresses', address); + this.props.onRequestClose(); + } + + render() { + const { isOpen, onRequestClose } = this.props; + + return r(Modal, { + isOpen, + onRequestClose, + }, [ + r.h3('Add remote server'), + + r.form({ + onSubmit: this.handleSubmit, + }, [ + r(Label, { + title: 'PULSE_SERVER syntax', + }, [ + r.div('Server address:'), + r.p([ + r(Input, { + style: { width: '100%' }, + autoFocus: true, + value: this.state.address, + onChange: e => this.setState({ address: e.target.value }), + }), + ]), + ]), + + r.div({ + className: 'button-group', + }, [ + r(Button, { + onClick: onRequestClose, + }, 'Cancel'), + + r(Button, { + type: 'submit', + }, 'Confirm'), + ]), + ]), + ]); + } +} + +module.exports = connect( + null, + dispatch => bindActionCreators(preferencesActions, dispatch), +)(AddRemoteServerModal); diff --git a/components/modals/index.js b/components/modals/index.js index 83987f2..8b56c44 100644 --- a/components/modals/index.js +++ b/components/modals/index.js @@ -30,6 +30,7 @@ const ConnectToServerModal = require('./connect-to-server'); const ConfirmationModal = require('./confirmation'); const NewGraphObjectModal = require('./new-graph-object'); const LoadModuleModal = require('./load-module'); +const AddRemoteServerModal = require('./add-remote-server-modal'); Modal.setAppElement('#root'); @@ -50,6 +51,7 @@ class Modals extends React.PureComponent { connectToServerModalOpen: false, newGraphObjectModalOpen: false, loadModuleModalOpen: false, + addRemoteServerModalOpen: false, modalDefaults: undefined, @@ -58,6 +60,7 @@ class Modals extends React.PureComponent { openNewGraphObjectModal: this.openNewGraphObjectModal.bind(this), openLoadModuleModal: this.openLoadModuleModal.bind(this), + openAddRemoteServerModal: this.openAddRemoteServerModal.bind(this), }, }; this.state = this.initialState; @@ -117,6 +120,10 @@ class Modals extends React.PureComponent { }); } + openAddRemoteServerModal() { + this.setState({ addRemoteServerModalOpen: true }); + } + handleCancel() { this.setState(this.initialState); } @@ -156,6 +163,11 @@ class Modals extends React.PureComponent { defaults: this.state.modalDefaults, }), + + r(AddRemoteServerModal, { + isOpen: this.state.addRemoteServerModalOpen, + onRequestClose: this.handleCancel, + }), ]); } } diff --git a/components/network/index.js b/components/network/index.js index e9e3c9c..69df813 100644 --- a/components/network/index.js +++ b/components/network/index.js @@ -7,6 +7,8 @@ const { propEq, sortBy, prop, + merge, + keys, } = require('ramda'); const React = require('react'); @@ -16,12 +18,66 @@ const r = require('r-dom'); const { connect } = require('react-redux'); const { bindActionCreators } = require('redux'); -const { pulse: pulseActions } = require('../../actions'); +const { + pulse: pulseActions, + preferences: preferencesActions, +} = require('../../actions'); const { formatModuleArgs } = require('../../utils/module-args'); +const { getRemoteServerByAddress } = require('../../selectors'); + const Button = require('../button'); const Label = require('../label'); +const RemoteServer = connect( + (state, props) => ({ + remoteServer: getRemoteServerByAddress(props.address)(state), + }), + dispatch => ({ + actions: bindActionCreators(merge(pulseActions, preferencesActions), dispatch), + }), +)(({ address, remoteServer = {}, actions }) => { + const { targetState, state } = remoteServer; + const hostname = path([ 'serverInfo', 'hostname' ], remoteServer); + + return r.div([ + r.div({ + style: { display: 'flex', justifyContent: 'space-between' }, + }, [ + r(Label, { + userSelect: true, + }, [ + hostname || address, + ]), + + targetState === 'ready' ? r(Button, { + onClick: () => { + actions.remoteServerDisconnect(address); + }, + }, 'Disconnect') : r(React.Fragment, [ + r(Button, { + onClick: () => { + actions.remoteServerDisconnect(address); + actions.setDelete('remoteServerAddresses', address); + }, + }, 'Forget'), + + r(Button, { + onClick: () => { + actions.remoteServerConnect(address); + }, + }, 'Connect'), + ]), + ]), + + state === 'ready' ? r(React.Fragment, [ + // TODO + ]) : targetState === 'ready' ? r(Label, [ + 'Connecting...', + ]) : null, + ]); +}); + class Cards extends React.Component { constructor(props) { super(props); @@ -52,6 +108,8 @@ class Cards extends React.Component { values(this.props.modules), )); + const remoteServerAddresses = keys(this.props.preferences.remoteServerAddresses); + return r.div({ classSet: { panel: true, @@ -123,6 +181,24 @@ class Cards extends React.Component { }, }, 'Allow incoming connections...'), + r.hr(), + + remoteServerAddresses.length > 0 ? r(React.Fragment, [ + r(Label, [ + 'Remote servers:', + ]), + + ...map(address => r(RemoteServer, { address }), remoteServerAddresses), + ]) : r(Label, [ + 'No known servers', + ]), + + r(Button, { + onClick: () => { + this.props.openAddRemoteServerModal(); + }, + }, 'Add a server...'), + this.props.preferences.showDebugInfo && r.pre({ style: { fontSize: '0.75em', diff --git a/index.css b/index.css index c60c31b..9980614 100644 --- a/index.css +++ b/index.css @@ -20,6 +20,8 @@ div[tabindex="-1"]:focus { user-select: none; padding: 8px; + + cursor: pointer; } .button:hover { @@ -37,6 +39,11 @@ div[tabindex="-1"]:focus { top: 1px; } +.button:disabled { + border-color: var(--unfocusedBorders); + cursor: not-allowed; +} + .button-group { display: flex; justify-content: space-between; diff --git a/reducers/preferences.js b/reducers/preferences.js index be49b21..af84cdf 100644 --- a/reducers/preferences.js +++ b/reducers/preferences.js @@ -1,6 +1,10 @@ const { merge, + over, + lensProp, + not, + omit, } = require('ramda'); const { handleActions } = require('redux-actions'); @@ -27,11 +31,17 @@ const initialState = { doNotAskForConfirmations: false, showDebugInfo: false, + + remoteServerAddresses: {}, }; const reducer = handleActions({ [preferences.set]: (state, { payload }) => merge(state, payload), - [preferences.toggle]: (state, { payload }) => merge(state, { [payload]: !state[payload] }), + [preferences.toggle]: (state, { payload }) => over(lensProp(payload), not, state), + + [preferences.setAdd]: (state, { payload: { key, value } }) => over(lensProp(key), merge({ [value]: true }), state), + [preferences.setDelete]: (state, { payload: { key, value } }) => over(lensProp(key), omit([ value ]), state), + [preferences.resetDefaults]: () => initialState, }, initialState); diff --git a/reducers/pulse.js b/reducers/pulse.js index 0b6fbfe..bcb5c6f 100644 --- a/reducers/pulse.js +++ b/reducers/pulse.js @@ -8,6 +8,8 @@ const { pick, equals, takeLast, + over, + lensPath, } = require('ramda'); const { combineReducers } = require('redux'); @@ -27,6 +29,8 @@ const initialState = { infos: fromPairs(map(({ key }) => [ key, {} ], things)), log: { items: [] }, + + remoteServers: {}, }; const logMaxItems = 3; @@ -127,6 +131,11 @@ const reducer = combineReducers({ })), }, initialState.log.items), }), + + remoteServers: handleActions({ + [pulse.remoteServerConnect]: (state, { payload }) => over(lensPath([ payload, 'targetState' ]), always('ready'), state), + [pulse.remoteServerDisconnect]: (state, { payload }) => over(lensPath([ payload, 'targetState' ]), always('closed'), state), + }, initialState.remoteServers), }); module.exports = { diff --git a/selectors/index.js b/selectors/index.js index 0a00846..acebf4f 100644 --- a/selectors/index.js +++ b/selectors/index.js @@ -66,6 +66,8 @@ const getDefaultSinkPai = createSelector( (sinks, defaultSinkName) => find(propEq('name', defaultSinkName), values(sinks)), ); +const getRemoteServerByAddress = address => state => state.pulse.remoteServers[address]; + module.exports = { getPaiByTypeAndIndex, getDerivedMonitorSources, @@ -80,4 +82,6 @@ module.exports = { getDefaultSinkPai, getDefaultSourcePai, + + getRemoteServerByAddress, };