Skip to content

Commit

Permalink
Merge pull request #343 from mekanix/feature/add-service-to-cluster
Browse files Browse the repository at this point in the history
Drag and drop service onto cluster
  • Loading branch information
mekanix authored Jul 23, 2016
2 parents bf15772 + ed1d8c6 commit 9cac6d2
Show file tree
Hide file tree
Showing 27 changed files with 422 additions and 147 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"extends": "airbnb",
"parser": "babel-eslint",
"rules": {
"react/prefer-es6-class": [0]
"react/prefer-es6-class": 0
}
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"homepage": "https://github.com/one-love/",
"devDependencies": {
"autoprefixer": "^6.3.7",
"babel-cli": "^6.10.1",
"babel-core": "^6.10.4",
"babel-eslint": "^6.1.2",
Expand All @@ -44,9 +45,13 @@
"mocha": "^2.5.3",
"node-libs-browser": "^0.5.3",
"node-sass": "^3.8.0",
"postcss-loader": "^0.9.1",
"precss": "^1.4.0",
"react": "^15.2.1",
"react-addons-css-transition-group": "^15.2.1",
"react-css-modules": "^3.7.7",
"react-dnd": "^2.1.4",
"react-dnd-html5-backend": "^2.1.2",
"react-dom": "^15.2.1",
"react-edit-inline": "^1.0.7",
"react-file-reader-input": "^1.0.1",
Expand Down
50 changes: 50 additions & 0 deletions src/components/molecules/dragable-service/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { DragSource } from 'react-dnd';
import ItemTypes from './item-types';
import store from '../../../store';


const serviceSource = {
beginDrag(props) {
return {
id: props.id,
};
},

endDrag(props, monitor) {
const item = monitor.getItem();
const dropResult = monitor.getDropResult();
const cluster = store.getState().clusterDetail.cluster;
if (dropResult) {
console.log(`You dropped ${item.id} into ${dropResult.name} with id ${cluster.id}!`);
}
},
};


const DragableService = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
id: React.PropTypes.string.isRequired,
connectDragSource: React.PropTypes.func.isRequired,
isDragging: React.PropTypes.bool.isRequired,
},

render() {
const { connectDragSource } = this.props;
const { name, id } = this.props;
return (
connectDragSource(
<div>{name}: {id}</div>
)
);
},
});


/* eslint-disable new-cap */
export default DragSource(ItemTypes.SERVICE, serviceSource, (connect, monitor) => ({
/* eslint-enable */
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}))(DragableService);
3 changes: 3 additions & 0 deletions src/components/molecules/dragable-service/item-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
SERVICE: 'service',
};
4 changes: 2 additions & 2 deletions src/components/molecules/service/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import svg from './service.svg';
import Icon from '../../atoms/icon';
import svg from './service.svg';


export default function Service(props) {
Expand All @@ -10,7 +10,7 @@ export default function Service(props) {
}
return (
<Icon
alt="cluster"
alt="service"
img={svg}
name={name}
iconId={props.iconId}
Expand Down
62 changes: 62 additions & 0 deletions src/components/organisms/cluster-service-list/actions/remove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { createAction } from 'redux-actions';
import { fetch } from '../../../../utils';
import { API_URL } from '../../../../backend_url';
import { CLUSTER_SERVICE_REMOVE } from '../constants';


export const reset = createAction(CLUSTER_SERVICE_REMOVE, () => ({
status: 'initial',
}));

export const begin = createAction(CLUSTER_SERVICE_REMOVE, () => ({
status: 'pending',
}));

export const success = createAction(CLUSTER_SERVICE_REMOVE, service => ({
service,
status: 'success',
}));

export const fail = createAction(CLUSTER_SERVICE_REMOVE, error => ({
status: 'error',
error,
}));

export const confirm = createAction(CLUSTER_SERVICE_REMOVE, id => ({
status: 'confirm',
service: {
id,
},
}));


export const remove = id =>
dispatch => {
dispatch(begin());
fetch({
url: `${API_URL}/${id}`,
method: 'DELETE',
body: {
id,
},
})
.then(service => {
dispatch(success(service));
return service;
})
.catch(error => {
dispatch(fail(error.message));
});
};


const actions = {
reset,
begin,
success,
fail,
confirm,
remove,
};

export default actions;
1 change: 1 addition & 0 deletions src/components/organisms/cluster-service-list/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const CLUSTER_SERVICE_REMOVE = 'CLUSTER_SERVICE_REMOVE';
81 changes: 81 additions & 0 deletions src/components/organisms/cluster-service-list/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react';
import { Link } from 'react-router';
import { DropTarget } from 'react-dnd';
import Service from '../../molecules/service';
import List from '../../molecules/transition-appear';
import removeActions from './actions/remove';
import ItemTypes from '../../molecules/dragable-service/item-types';


const clusterTarget = {
drop() {
return {
name: 'Cluster',
};
},
};


const ClusterServiceList = React.createClass({
propTypes: {
services: React.PropTypes.array,
children: React.PropTypes.node,
clusterId: React.PropTypes.string.isRequired,
connectDropTarget: React.PropTypes.func.isRequired,
isOver: React.PropTypes.bool.isRequired,
canDrop: React.PropTypes.bool.isRequired,
},

getDefaultProps() {
return {
services: [],
};
},

render() {
const clusterUrl = `clusters/${this.props.clusterId}`;
const serviceContent = this.props.services.map(service => {
const url = `${clusterUrl}/services/${service.id}/provision`;
const iconId = `${clusterUrl}/services/${service.id}`;
return (
<Link to={url} key={service.id}>
<Service
name={service.name}
iconId={iconId}
close={removeActions.confirm}
/>
</Link>
);
});
const content = this.props.services ? serviceContent : this.props.children;
const { canDrop, isOver, connectDropTarget } = this.props;
const isActive = canDrop && isOver;

let backgroundColor = 'white';
if (isActive) {
backgroundColor = 'darkgreen';
} else if (canDrop) {
backgroundColor = 'darkkhaki';
}

return (
connectDropTarget(
<div style={{ backgroundColor }}>
<h3>Services</h3>
<List>
{content}
</List>
</div>
)
);
},
});


/* eslint-disable new-cap */
export default DropTarget(ItemTypes.SERVICE, clusterTarget, (connect, monitor) => ({
/* eslint-enable */
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}))(ClusterServiceList);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import clusterServiceRemove from './remove';


const reducers = [
clusterServiceRemove,
];


export default reducers;
17 changes: 17 additions & 0 deletions src/components/organisms/cluster-service-list/reducers/remove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { CLUSTER_SERVICE_REMOVE } from '../constants';


export default function clusterServiceRemove(
state = { status: 'initial', service: {} },
action
) {
switch (action.type) {
case CLUSTER_SERVICE_REMOVE:
return {
service: action.payload.service,
status: action.payload.status,
};
default:
return state;
}
}
47 changes: 47 additions & 0 deletions src/components/organisms/service-list/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { connect } from 'react-redux';
import DragableService from '../../molecules/dragable-service';
import actions from '../../pages/service-list/actions';
import store from '../../../store';


const mapStateToProps = state => {
const data = {
services: state.serviceList.services,
status: state.serviceList.status,
};
return data;
};


const ServiceList = React.createClass({
propTypes: {
services: React.PropTypes.array,
},

getDefaultProps() {
return {
services: [],
};
},

componentWillMount() {
store.dispatch(actions.get());
},

render() {
return (
<div>
<h1>Services</h1>
{
this.props.services.map(service => (
<DragableService key={service.id} id={service.id} name={service.name} />
))
}
</div>
);
},
});


export default connect(mapStateToProps, actions)(ServiceList);
1 change: 1 addition & 0 deletions src/components/pages/cluster-list/reducers/remove.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CLUSTER_REMOVE } from '../constants';


export default function clusterRemove(
state = { status: 'initial', cluster: {} },
action
Expand Down
Loading

0 comments on commit 9cac6d2

Please sign in to comment.