Total overhaul of how commands are executed (server-side), fixes #387

This commit is contained in:
James Barnsley
2019-04-15 09:56:27 +12:00
parent 1eaaadc7ad
commit 53d2725c7e
10 changed files with 285 additions and 106 deletions

View File

@ -147,7 +147,7 @@ class OutputControl extends React.Component{
<div
key={command.id}
className="commands__item commands__item--interactive"
onClick={e => this.props.pusherActions.sendCommand(command.id)}>
onClick={e => this.props.pusherActions.runCommand(command.id)}>
<Icon className="commands__item__icon" name={command.icon} />
<span className={command.colour+'-background commands__item__background'}></span>
</div>

View File

@ -53,6 +53,12 @@ export function startSearch(search_type, query, only_mopidy = false){
}
export function handleException(message, data = {}, description = null, show_notification = true){
if (!message && data.message){
message = data.message;
}
if (!description && data.description){
description = data.description;
}
return {
type: 'HANDLE_EXCEPTION',
message: message,

View File

@ -223,9 +223,9 @@ export function removeCommand(id){
}
}
export function sendCommand(id, notify = false){
export function runCommand(id, notify = false){
return {
type: 'PUSHER_SEND_COMMAND',
type: 'PUSHER_RUN_COMMAND',
id: id,
notify: notify
}

View File

@ -504,38 +504,28 @@ const PusherMiddleware = (function(){
next(action);
break
case 'PUSHER_SEND_COMMAND':
case 'PUSHER_RUN_COMMAND':
var command = Object.assign({}, pusher.commands[action.id]);
var notification_key = 'command_'+action.id;
if (action.notify){
store.dispatch(uiActions.startProcess(notification_key, 'Sending command'));
store.dispatch(uiActions.startProcess(notification_key, 'Running command'));
}
try {
var ajax_settings = JSON.parse(command.command);
} catch(error){
store.dispatch(uiActions.createNotification({key: notification_key, type: 'bad', content: 'Command failed', description: error}));
break;
}
// Handle success and failure
ajax_settings.success = function(response){
console.log("Command sent, response was:",response);
if (action.notify){
request(store, 'run_command', {id: action.id})
.then(response => {
store.dispatch(uiActions.processFinished(notification_key));
store.dispatch(uiActions.createNotification({key: notification_key, type: 'info', content: 'Command sent'}));
}
}
ajax_settings.error = function(xhr, status, error){
console.error("Command failed, response was:",xhr,error);
store.dispatch(uiActions.processFinished(notification_key));
store.dispatch(uiActions.createNotification({key: notification_key, type: 'bad', content: 'Command failed', description: xhr.status+": "+error}));
}
// Actually send the request
$.ajax(ajax_settings);
if (action.notify){
store.dispatch(uiActions.createNotification({key: notification_key, type: 'info', content: 'Command sent'}));
}
},
error => {
store.dispatch(uiActions.processFinished(notification_key));
store.dispatch(coreActions.handleException(
'Could not run command',
error
));
})
break
@ -553,7 +543,7 @@ const PusherMiddleware = (function(){
radio: response.radio
});
},
error => {
error => {
store.dispatch(coreActions.handleException(
'Could not load radio',
error

View File

@ -169,12 +169,12 @@ class Settings extends React.Component {
return (
<div className="list__item commands-setup__item list__item--no-interaction" key={command.id}>
<div className="col col--w90">
<div className="commands__item commands__item--interactive" onClick={e => this.props.pusherActions.sendCommand(command.id, true)}>
<div className="commands__item commands__item--interactive" onClick={e => this.props.pusherActions.runCommand(command.id, true)}>
<Icon className="commands__item__icon" name={command.icon} />
<span className={command.colour+'-background commands__item__background'}></span>
</div>
<div className="commands-setup__item__url commands__item__url">
{command.command && command.command.url ? command.command.url : "-"}
{command.name ? command.name : <span className="grey-text">{command.url}</span>}
</div>
</div>
<div className="commands-setup__item__actions">

View File

@ -9,6 +9,7 @@ import Link from '../../components/Link';
import Icon from '../../components/Icon';
import ColourField from '../../components/Fields/ColourField';
import IconField from '../../components/Fields/IconField';
import TextField from '../../components/Fields/TextField';
import * as pusherActions from '../../services/pusher/actions';
import * as uiActions from '../../services/ui/actions';
@ -21,8 +22,11 @@ class EditCommand extends React.Component{
this.state = {
id: helpers.generateGuid(),
icon: 'power_settings_new',
name: '',
colour: '',
command: '{"url":"https://'+window.location.hostname+'/broadlink/sendCommand/power/"}'
url: "https://"+window.location.hostname+"/broadlink/sendCommand/power/",
method: 'GET',
post_data: ""
}
}
@ -38,12 +42,7 @@ class EditCommand extends React.Component{
handleSubmit(e){
e.preventDefault();
this.props.pusherActions.setCommand({
id: this.state.id,
icon: this.state.icon,
colour: this.state.colour,
command: this.state.command
});
this.props.pusherActions.setCommand(this.state);
window.history.back();
@ -121,6 +120,19 @@ class EditCommand extends React.Component{
<h1>{this.props.command ? "Edit" : "Create"} command</h1>
<form onSubmit={(e) => this.handleSubmit(e)}>
<div className="field textarea white">
<div className="name">
Name
</div>
<div className="input">
<TextField
name="name"
value={this.state.name}
onChange={value => this.setState({ name: value })}
/>
</div>
</div>
<div className="field radio white">
<div className="name">
Colour
@ -148,19 +160,55 @@ class EditCommand extends React.Component{
<div className="field textarea white">
<div className="name">
Command
URL
</div>
<div className="input">
<TextField
name="url"
value={this.state.url}
onChange={value => this.setState({ url: value })}
/>
</div>
</div>
<div className="field radio white">
<div className="name">
Method
</div>
<div className="input">
<label>
<input
type="radio"
name="method"
value="GET"
checked={ this.state.method == 'GET' }
onChange={ e => this.setState({ method: e.target.value })} />
<span className="label">GET</span>
</label>
<label>
<input
type="radio"
name="method"
value="POST"
checked={ this.state.method == 'POST' }
onChange={ e => this.setState({ method: e.target.value })} />
<span className="label">POST</span>
</label>
</div>
</div>
{this.state.method == 'POST' && <div className="field textarea white">
<div className="name">
Data
</div>
<div className="input">
<textarea
name="command"
value={this.state.command}
onChange={ e => this.setState({ command: e.target.value })}>
value={this.state.post_data}
onChange={ e => this.setState({ post_data: e.target.value })}>
</textarea>
<div className="description">
Ajax request settings. See <a href="http://api.jquery.com/jquery.ajax/" target="_blank" noopener="true"><code>jquery.ajax</code> documentation</a>.
</div>
</div>
</div>
</div>}
<div className="actions centered-text">
{this.props.command ? <button type="button" className="button button--destructive button--large" onClick={e => this.handleDelete(e)}>Delete</button> : null}