Sortable commands

This commit is contained in:
James Barnsley
2019-04-16 20:06:56 +12:00
parent da23ce0868
commit 63d453670f
8 changed files with 360 additions and 177 deletions

View File

@ -0,0 +1,74 @@
import React from 'react'
import Sortable from 'react-sortablejs';
import Icon from '../Icon';
import Link from '../Link';
import * as helpers from '../../helpers';
export default class Commands extends React.Component{
constructor(props){
super(props);
}
onChange(order){
let commands = {};
for (let i = 0; i <= order.length; i++){
let command = this.props.commands[order[i]];
if (command){
commands[command.id] = {...command, ...{sort_order: i}};
}
}
this.props.onChange(commands);
}
commands(){
let commands = [];
if (this.props.commands){
for (let key of Object.keys(this.props.commands)){
commands.push({...this.props.commands[key]});
}
}
commands = helpers.sortItems(commands, 'sort_order');
return commands;
}
render(){
const commands = this.commands();
if (!commands){
return null;
}
return (
<Sortable className="list commands-setup" onChange={(order, sortable, e) => {this.onChange(order)}}>
{
commands.map(command => {
return (
<div className="list__item commands-setup__item list__item--no-interaction" key={command.id} data-id={command.id}>
<div className="col col--w90">
<div className="commands__item commands__item--interactive" onClick={e => this.props.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.name ? command.name : <span className="grey-text">{command.url}</span>}
</div>
</div>
<div className="commands-setup__item__actions">
<Link className="commands-setup__item__edit-button action" to={'/edit-command/'+command.id}>
<Icon name="edit" />
</Link>
</div>
</div>
);
})
}
</Sortable>
);
}
}

View File

@ -6,6 +6,7 @@ import { bindActionCreators } from 'redux';
import VolumeControl from './VolumeControl';
import MuteControl from './MuteControl';
import Icon from '../Icon';
import * as helpers from '../../helpers';
import * as coreActions from '../../services/core/actions';
import * as pusherActions from '../../services/pusher/actions';
@ -136,6 +137,8 @@ class OutputControl extends React.Component{
commands_items.push(this.props.pusher_commands[key]);
}
}
commands_items = helpers.sortItems(commands_items, 'sort_order');
if (commands_items.length > 0){
has_outputs = true;

View File

@ -216,6 +216,13 @@ export function setCommand(command){
}
}
export function setCommands(commands){
return {
type: 'PUSHER_SET_COMMANDS',
commands: commands
}
}
export function removeCommand(id){
return {
type: 'PUSHER_REMOVE_COMMAND',

View File

@ -459,19 +459,23 @@ const PusherMiddleware = (function(){
break
case 'PUSHER_SET_COMMAND':
var commands_index = Object.assign({}, pusher.commands);
var commands = Object.assign({}, pusher.commands);
if (commands_index[action.command.id]){
var command = Object.assign({}, commands_index[action.command.id], action.command);
if (commands[action.command.id]){
var command = Object.assign({}, commands[action.command.id], action.command);
} else {
var command = action.command;
}
commands_index[action.command.id] = command;
commands[action.command.id] = command;
request(store, 'set_commands', {commands: commands_index})
store.dispatch(pusherActions.setCommands(commands));
break
case 'PUSHER_SET_COMMANDS':
request(store, 'set_commands', {commands: action.commands})
.then(
response => {
// No action required, the change will be broadcast
// No action required, the change will be broadcast
},
error => {
store.dispatch(coreActions.handleException(

View File

@ -4,22 +4,21 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Route, Link } from 'react-router-dom';
import ConfirmationButton from '../components/Fields/ConfirmationButton'
import PusherConnectionList from '../components/PusherConnectionList'
import SourcesPriority from '../components/Fields/SourcesPriority'
import Header from '../components/Header'
import Icon from '../components/Icon'
import Thumbnail from '../components/Thumbnail'
import URILink from '../components/URILink'
import Services from '../components/Services'
import ConfirmationButton from '../components/Fields/ConfirmationButton';
import PusherConnectionList from '../components/PusherConnectionList';
import SourcesPriority from '../components/Fields/SourcesPriority';
import Commands from '../components/Fields/Commands';
import Header from '../components/Header';
import Icon from '../components/Icon';
import Services from '../components/Services';
import * as helpers from '../helpers'
import * as coreActions from '../services/core/actions'
import * as uiActions from '../services/ui/actions'
import * as pusherActions from '../services/pusher/actions'
import * as mopidyActions from '../services/mopidy/actions'
import * as lastfmActions from '../services/lastfm/actions'
import * as spotifyActions from '../services/spotify/actions'
import * as helpers from '../helpers';
import * as coreActions from '../services/core/actions';
import * as uiActions from '../services/ui/actions';
import * as pusherActions from '../services/pusher/actions';
import * as mopidyActions from '../services/mopidy/actions';
import * as lastfmActions from '../services/lastfm/actions';
import * as spotifyActions from '../services/spotify/actions';
class Settings extends React.Component {
@ -142,54 +141,6 @@ class Settings extends React.Component {
);
}
renderCommands(){
var commands = [];
if (this.props.pusher.commands){
for (var id in this.props.pusher.commands){
if (this.props.pusher.commands.hasOwnProperty(id)){
var command = Object.assign({}, this.props.pusher.commands[id]);
try {
command.command = JSON.parse(command.command);
} catch(error){
command.command = null;
}
commands.push(command);
}
}
}
if (commands.length <= 0){
return null;
}
return (
<div className="list commands-setup">
{
commands.map(command => {
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.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.name ? command.name : <span className="grey-text">{command.url}</span>}
</div>
</div>
<div className="commands-setup__item__actions">
<Link className="commands-setup__item__edit-button action" to={'/edit-command/'+command.id}>
<Icon name="edit" />
</Link>
</div>
</div>
);
})
}
</div>
);
}
render(){
var options = (
@ -371,7 +322,11 @@ class Settings extends React.Component {
Commands
</div>
<div className="input">
{this.renderCommands()}
<Commands
commands={this.props.pusher.commands}
runCommand={(id, notify) => this.props.pusherActions.runCommand(id, notify)}
onChange={commands => this.props.pusherActions.setCommands(commands)}
/>
<Link to={'/edit-command'} className="button button--default">Add new</Link>
</div>
</div>