Refactoring store
This commit is contained in:
parent
1136b693fd
commit
a2f0a03671
|
@ -126,6 +126,7 @@ html, body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit .item-form {
|
.edit .item-form {
|
||||||
|
@ -141,7 +142,6 @@ html, body {
|
||||||
.edit .apps-list ul.desktop-apps {
|
.edit .apps-list ul.desktop-apps {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow-y: auto;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 10px 0 0 0;
|
margin: 10px 0 0 0;
|
||||||
padding: 0 10px 0 0;
|
padding: 0 10px 0 0;
|
||||||
|
|
|
@ -11,7 +11,7 @@ var DesktopAppList = React.createClass({
|
||||||
var items = this.props.desktopApps.map(function(desktopApp, i) {
|
var items = this.props.desktopApps.map(function(desktopApp, i) {
|
||||||
var desktopEntry = desktopApp.content['Desktop Entry'];
|
var desktopEntry = desktopApp.content['Desktop Entry'];
|
||||||
return (
|
return (
|
||||||
<DesktopAppItem theme={this.props.selectedTheme}
|
<DesktopAppItem theme={this.props.theme}
|
||||||
key={desktopApp.path}
|
key={desktopApp.path}
|
||||||
desktopEntry={desktopEntry}
|
desktopEntry={desktopEntry}
|
||||||
onItemDropped={this.props.onItemDropped} />
|
onItemDropped={this.props.onItemDropped} />
|
||||||
|
|
|
@ -24,21 +24,21 @@ var EditView = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
<div className="workspace">
|
<div className="workspace">
|
||||||
<div className="left-menu">
|
<div className="left-menu">
|
||||||
<IconThemeSelector onThemeSelected={this.onThemeSelected} />
|
<IconThemeSelector onThemeSelected={this.handleThemeSelect} />
|
||||||
<DesktopAppList
|
<DesktopAppList
|
||||||
theme={this.props.theme}
|
theme={this.props.theme}
|
||||||
desktopApps={this.props.desktopApps}
|
desktopApps={this.props.desktopApps}
|
||||||
onItemDropped={this.onItemDropped} />
|
onItemDropped={this.handleItemDrop} />
|
||||||
</div>
|
</div>
|
||||||
<ProfileTree />
|
<ProfileTree />
|
||||||
<ItemForm />
|
<ItemForm item={this.props.selectedItem} onItemChange={this.handleItemChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onItemDropped: function(desktopEntry, targetItem) {
|
handleItemDrop: function(desktopEntry, targetItem) {
|
||||||
|
|
||||||
var newProfileItem = {
|
var newProfileItem = {
|
||||||
label: desktopEntry.Name,
|
label: desktopEntry.Name,
|
||||||
|
@ -50,8 +50,12 @@ var EditView = React.createClass({
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onThemeSelected: function(theme) {
|
handleThemeSelect: function(theme) {
|
||||||
this.props.dispatch(actions.edit.selectTheme(theme));
|
this.props.dispatch(actions.edit.useIconTheme(theme));
|
||||||
|
},
|
||||||
|
|
||||||
|
handleItemChange: function(item, key, value) {
|
||||||
|
this.props.dispatch(actions.edit.updateProfileItem(item, key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -60,7 +64,8 @@ function select(state) {
|
||||||
return {
|
return {
|
||||||
desktopApps: state.desktopApps,
|
desktopApps: state.desktopApps,
|
||||||
profile: state.profile,
|
profile: state.profile,
|
||||||
theme: state.theme
|
theme: state.theme,
|
||||||
|
selectedItem: state.selectedItem
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,74 @@ var React = require('react');
|
||||||
|
|
||||||
var ItemForm = React.createClass({
|
var ItemForm = React.createClass({
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
label: '',
|
||||||
|
icon: '',
|
||||||
|
exec: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(props) {
|
||||||
|
|
||||||
|
if(props.item) {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
label: props.item.label,
|
||||||
|
icon: props.item.icon,
|
||||||
|
exec: props.item.exec
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
|
var state = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="item-form">
|
<div className="item-form">
|
||||||
|
<form>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Label</label>
|
||||||
|
<input type="text" className="form-control"
|
||||||
|
placeholder="Label"
|
||||||
|
value={state.label}
|
||||||
|
onChange={this.handleChange.bind(this, 'label')} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Icon</label>
|
||||||
|
<input type="text" className="form-control"
|
||||||
|
placeholder="Icon"
|
||||||
|
value={state.icon}
|
||||||
|
onChange={this.handleChange.bind(this, 'icon')} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Exec</label>
|
||||||
|
<input type="text" className="form-control"
|
||||||
|
placeholder="Exec" value={state.exec}
|
||||||
|
onChange={this.handleChange.bind(this, 'exec')} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
handleChange: function(key, evt) {
|
||||||
|
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
|
var newState = {};
|
||||||
|
var value = evt.currentTarget.value;
|
||||||
|
|
||||||
|
newState[key] = value;
|
||||||
|
this.setState(newState);
|
||||||
|
|
||||||
|
if(typeof this.props.onItemChange === 'function') {
|
||||||
|
this.props.onItemChange(this.props.item, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,13 +13,17 @@ var TreeNode = React.createClass({
|
||||||
var listElements = subItems.map(function(subItem, i) {
|
var listElements = subItems.map(function(subItem, i) {
|
||||||
return (
|
return (
|
||||||
<li key={i} >
|
<li key={i} >
|
||||||
<TreeNode data={subItem} onItemMoved={this.props.onItemMoved} />
|
<TreeNode data={subItem}
|
||||||
|
selectedItem={this.props.selectedItem}
|
||||||
|
onItemClicked={this.props.onItemClicked}
|
||||||
|
onItemMoved={this.props.onItemMoved}
|
||||||
|
theme={this.props.theme} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
var appEntry = data.icon || data.label ?
|
var appEntry = data.icon || data.label ?
|
||||||
<TreeItem data={data} onItemMoved={this.props.onItemMoved} /> :
|
this.renderTreeItem(data):
|
||||||
null
|
null
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -32,6 +36,14 @@ var TreeNode = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTreeItem: function(data) {
|
||||||
|
return (
|
||||||
|
<TreeItem data={data}
|
||||||
|
selected={data.selected}
|
||||||
|
{...this.props} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -46,21 +58,36 @@ var ProfileTree = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="profile-tree">
|
<div className="profile-tree">
|
||||||
<TreeNode data={this.props.profile} onItemMoved={this.onItemMoved} />
|
{this.renderTreeNode(this.props.profile)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renderTreeNode: function(data) {
|
||||||
|
return (
|
||||||
|
<TreeNode data={data}
|
||||||
|
selectedItem={this.props.selectedItem}
|
||||||
|
onItemClicked={this.onItemSelected}
|
||||||
|
onItemMoved={this.onItemMoved}
|
||||||
|
theme={this.props.theme} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
onItemMoved: function(movedItem, targetItem) {
|
onItemMoved: function(movedItem, targetItem) {
|
||||||
this.props.dispatch(actions.edit.moveProfileItem(movedItem, targetItem));
|
this.props.dispatch(actions.edit.moveProfileItem(movedItem, targetItem));
|
||||||
|
},
|
||||||
|
|
||||||
|
onItemSelected: function(selectedItem) {
|
||||||
|
this.props.dispatch(actions.edit.selectProfileItem(selectedItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function select(state) {
|
function select(state) {
|
||||||
return {
|
return {
|
||||||
profile: state.profile
|
profile: state.profile,
|
||||||
|
theme: state.theme
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,24 @@ var TreeItem = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
|
|
||||||
var data = this.props.data;
|
var data = this.props.data;
|
||||||
var appIcon = data.icon ? <AppIcon icon={data.icon} /> : null;
|
var appIcon = data.icon ? <AppIcon icon={data.icon} theme={this.props.theme} /> : null;
|
||||||
|
|
||||||
var connectDragSource = this.props.connectDragSource;
|
var connectDragSource = this.props.connectDragSource;
|
||||||
var connectDropTarget = this.props.connectDropTarget;
|
var connectDropTarget = this.props.connectDropTarget;
|
||||||
|
|
||||||
var classes = classNames({
|
var classes = classNames({
|
||||||
'alert': true,
|
'alert': true,
|
||||||
'alert-default': !this.props.isDragging && !this.props.isOver,
|
'alert-default': !this.props.isOver,
|
||||||
'alert-info': this.props.isDragging,
|
'alert-info': this.props.isOver && this.props.canDrop,
|
||||||
'alert-success': this.props.isOver
|
'alert-success': this.props.selected
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var style = {
|
||||||
|
opacity: this.props.isDragging ? 0.5 : 1
|
||||||
|
};
|
||||||
|
|
||||||
return connectDropTarget(connectDragSource(
|
return connectDropTarget(connectDragSource(
|
||||||
<div className={classes}>
|
<div className={classes} style={style} onClick={this.handleClick}>
|
||||||
{appIcon}
|
{appIcon}
|
||||||
<span className="app-label">{data.label}</span>
|
<span className="app-label">{data.label}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,6 +35,11 @@ var TreeItem = React.createClass({
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleClick: function(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
this.props.onItemClicked(this.props.data);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var dragSourceSpec = {
|
var dragSourceSpec = {
|
||||||
|
@ -76,7 +85,8 @@ function dragSourceCollect(connect, monitor) {
|
||||||
function dropTargetCollect(connect, monitor) {
|
function dropTargetCollect(connect, monitor) {
|
||||||
return {
|
return {
|
||||||
connectDropTarget: connect.dropTarget(),
|
connectDropTarget: connect.dropTarget(),
|
||||||
isOver: monitor.isOver()
|
isOver: monitor.isOver(),
|
||||||
|
canDrop: monitor.canDrop()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ var LOAD_DESKTOP_APPS_SUCCESS = exports.LOAD_DESKTOP_APPS_SUCCESS = 'LOAD_DESKTO
|
||||||
var LOAD_DESKTOP_APPS_FAILED = exports.LOAD_DESKTOP_APPS_FAILED = 'LOAD_DESKTOP_APPS_FAILED';
|
var LOAD_DESKTOP_APPS_FAILED = exports.LOAD_DESKTOP_APPS_FAILED = 'LOAD_DESKTOP_APPS_FAILED';
|
||||||
var MOVE_PROFILE_ITEM = exports.MOVE_PROFILE_ITEM = 'MOVE_PROFILE_ITEM';
|
var MOVE_PROFILE_ITEM = exports.MOVE_PROFILE_ITEM = 'MOVE_PROFILE_ITEM';
|
||||||
var ADD_PROFILE_ITEM = exports.ADD_PROFILE_ITEM = 'ADD_PROFILE_ITEM';
|
var ADD_PROFILE_ITEM = exports.ADD_PROFILE_ITEM = 'ADD_PROFILE_ITEM';
|
||||||
|
var USE_ICON_THEME = exports.USE_ICON_THEME = 'USE_ICON_THEME';
|
||||||
|
var SELECT_PROFILE_ITEM = exports.SELECT_PROFILE_ITEM = 'SELECT_PROFILE_ITEM';
|
||||||
|
var UPDATE_PROFILE_ITEM = exports.UPDATE_PROFILE_ITEM = 'UPDATE_PROFILE_ITEM';
|
||||||
|
|
||||||
// Actions creators
|
// Actions creators
|
||||||
|
|
||||||
|
@ -31,10 +34,16 @@ exports.loadDesktopApps = function() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.useIconTheme = function(theme) {
|
||||||
|
return {
|
||||||
|
type: USE_ICON_THEME,
|
||||||
|
theme: theme
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
exports.moveProfileItem = function(movedItem, targetItem) {
|
exports.moveProfileItem = function(movedItem, targetItem) {
|
||||||
return {
|
return {
|
||||||
type: 'MOVE_PROFILE_ITEM',
|
type: MOVE_PROFILE_ITEM,
|
||||||
movedItem: movedItem,
|
movedItem: movedItem,
|
||||||
targetItem: targetItem
|
targetItem: targetItem
|
||||||
};
|
};
|
||||||
|
@ -42,8 +51,24 @@ exports.moveProfileItem = function(movedItem, targetItem) {
|
||||||
|
|
||||||
exports.addProfileItem = function(newItem, targetItem) {
|
exports.addProfileItem = function(newItem, targetItem) {
|
||||||
return {
|
return {
|
||||||
type: 'ADD_PROFILE_ITEM',
|
type: ADD_PROFILE_ITEM,
|
||||||
newItem: newItem,
|
newItem: newItem,
|
||||||
targetItem: targetItem
|
targetItem: targetItem
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.selectProfileItem = function(item) {
|
||||||
|
return {
|
||||||
|
type: SELECT_PROFILE_ITEM,
|
||||||
|
item: item
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.updateProfileItem = function(item, key, value) {
|
||||||
|
return {
|
||||||
|
type: UPDATE_PROFILE_ITEM,
|
||||||
|
item: item,
|
||||||
|
key: key,
|
||||||
|
value: value
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -12,7 +12,8 @@ var createStore = redux.applyMiddleware(
|
||||||
var appReducer = redux.combineReducers({
|
var appReducer = redux.combineReducers({
|
||||||
profile: reducers.profile,
|
profile: reducers.profile,
|
||||||
processOpts: reducers.processOpts,
|
processOpts: reducers.processOpts,
|
||||||
desktopApps: reducers.desktopApps
|
desktopApps: reducers.desktopApps,
|
||||||
|
theme: reducers.theme
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = createStore(appReducer);
|
module.exports = createStore(appReducer);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
exports.desktopApps = require('./desktop-apps');
|
exports.desktopApps = require('./desktop-apps');
|
||||||
exports.profile = require('./profile');
|
exports.profile = require('./profile');
|
||||||
exports.processOpts = require('./process-opts');
|
exports.processOpts = require('./process-opts');
|
||||||
|
exports.theme = require('./theme');
|
||||||
|
|
|
@ -14,6 +14,12 @@ module.exports = function(oldProfile, action) {
|
||||||
case actions.edit.ADD_PROFILE_ITEM:
|
case actions.edit.ADD_PROFILE_ITEM:
|
||||||
return addProfileItem(oldProfile, action.newItem, action.targetItem);
|
return addProfileItem(oldProfile, action.newItem, action.targetItem);
|
||||||
|
|
||||||
|
case actions.edit.UPDATE_PROFILE_ITEM:
|
||||||
|
return updateProfileItem(oldProfile, action.item, action.key, action.value);
|
||||||
|
|
||||||
|
case actions.edit.SELECT_PROFILE_ITEM:
|
||||||
|
return selectProfileItem(oldProfile, action.item);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return oldProfile || null;
|
return oldProfile || null;
|
||||||
|
|
||||||
|
@ -21,6 +27,19 @@ module.exports = function(oldProfile, action) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function selectProfileItem(oldProfile, item) {
|
||||||
|
var newProfile = _.cloneDeep(oldProfile);
|
||||||
|
|
||||||
|
return newProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProfileItem(oldProfile, targetItem, key, value) {
|
||||||
|
var newProfile = _.cloneDeep(oldProfile);
|
||||||
|
var result = treeFind(newProfile, targetItem);
|
||||||
|
result.item[key] = value;
|
||||||
|
return newProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function moveProfileItem(oldProfile, movedItem, targetItem) {
|
function moveProfileItem(oldProfile, movedItem, targetItem) {
|
||||||
|
|
||||||
|
@ -50,6 +69,29 @@ function addProfileItem(oldProfile, newItem, targetItem) {
|
||||||
return newProfile;
|
return newProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tree manipulation helpers
|
||||||
|
|
||||||
|
function treeWalk(branch, func) {
|
||||||
|
|
||||||
|
var items = branch.items;
|
||||||
|
|
||||||
|
if(!items) return;
|
||||||
|
|
||||||
|
for( var i = 0, item = items[i]; (item = items[i]); i++ ) {
|
||||||
|
|
||||||
|
var breakHere = func(item, parent);
|
||||||
|
|
||||||
|
if(breakHere) return breakHere;
|
||||||
|
|
||||||
|
if(item.items) {
|
||||||
|
breakHere = treeWalk(item, func);
|
||||||
|
if(breakHere) return breakHere;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function treeFind(branch, obj) {
|
function treeFind(branch, obj) {
|
||||||
|
|
||||||
var items = branch.items;
|
var items = branch.items;
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
var actions = require('../actions');
|
||||||
|
|
||||||
|
module.exports = function(currentTheme, action) {
|
||||||
|
|
||||||
|
switch(action.type) {
|
||||||
|
|
||||||
|
case actions.edit.USE_ICON_THEME:
|
||||||
|
return action.theme;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return currentTheme || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in New Issue