Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish UI portion of ServiceDetail page #214

Merged
merged 5 commits into from
Feb 17, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions BaragonUI/app/actions/api/services.es6
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { buildApiAction, buildJsonApiAction } from './base';

const buildRequestId = (serviceId) => `${serviceId}-${Date.now()}`;

export const FetchBaragonServices = buildApiAction(
'FETCH_BARAGON_SERVICES',
{url: '/state'}
Expand All @@ -17,8 +19,8 @@ export const FetchService = buildApiAction(
export const DeleteService = buildJsonApiAction(
'DELETE_SERVICE',
'DELETE',
(serviceId) => ({
url: `/state/${serviceId}`,
(serviceId, noValidate = false, noReload = false) => ({
url: `/state/${serviceId}?noValidate=${noValidate}&noReload=${noReload}`,
})
);

Expand All @@ -29,3 +31,20 @@ export const ReloadService = buildJsonApiAction(
url: `/state/${serviceId}/reload`,
})
);

export const RemoveUpstreams = buildJsonApiAction(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should make sure to add this action to the reducers as well, the returned output will be more easily accessible

'REMOVE_UPSTREAMS',
'POST',
(loadBalancerService, upstreams, noValidate, noReload) => ({
url: '/request',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are several different actions that might submit a request. Maybe it makes sense to use the SubmitRequest action in requests.e6 and let each of the submitting processes handle generating the necessary body?

Feel free to disagree, just trying to think how to best organize what might be very similar calls from different places.

body: {
loadBalancerService,
noValidate,
noReload,
loadBalancerRequestId: buildRequestId(loadBalancerService.serviceId),
addUpstreams: [],
removeUpstreams: upstreams,
},
}),
(serviceId) => serviceId,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would make more sense to have this keyed on the requestId. When fetching results for the request we are going to have to look it up by that id, not the serviceId

);
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,40 @@ class DeleteServiceModal extends Component {
action="Delete"
onConfirm={this.props.deleteService}
buttonStyle="danger"
formElements={[]}>
<p>Are you sure you want to reload configs this service?</p>
formElements={[
{
name: 'noValidate',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Validate new configuration after applying changes'
},
{
name: 'noReload',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Reload configuration after applying changes',
},
]}>
<p>Are you sure you sure you want to delete this service?</p>
<pre>{this.props.serviceId}</pre>
<p>
Deleting a service will remove the entry from Baragon's state node as
well as clearing the locks on any associated base paths. It will also
remove the configs from the load balancer (they will be backed up for
reference).
</p>
</FormModal>
);
}
}

const mapDispatchToProps = (dispatch, ownProps) => ({
deleteService: () => dispatch(DeleteService.trigger(ownProps.serviceId)).then(response => (ownProps.then && ownProps.then(response)))
deleteService: (data) => dispatch(DeleteService
.trigger(ownProps.serviceId, data.noValidate, data.noReload))
.then(response => (ownProps.then && ownProps.then(response)))
});

export default connect(
null,
mapDispatchToProps,
null,
{ withRef: true }
)(DeleteServiceModal);
)(DeleteServiceModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { Component, PropTypes } from 'react';

import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import ToolTip from 'react-bootstrap/lib/Tooltip';
import { Glyphicon } from 'react-bootstrap';

import { getClickComponent } from '../modal/ModalWrapper';

import RemoveUpstreamModal from './RemoveUpstreamModal';

const removeTooltip = (
<ToolTip id="removeAll">
Remove this upstream from the service
</ToolTip>
);

export default class RemoveUpstreamButton extends Component {
static propTypes = {
loadBalancerService: PropTypes.object,
upstream: PropTypes.shape({
group: PropTypes.string,
rackId: PropTypes.string,
requestId: PropTypes.string.isRequired,
upstream: PropTypes.string.isRequired,
}),
children: PropTypes.node,
afterRemoveUpstream: PropTypes.func,
};

static defaultProps = {
children: (
<OverlayTrigger placement="top" id="view-delete-overlay" overlay={removeTooltip}>
<Glyphicon glyph="remove" className="inactive" />
</OverlayTrigger>
)
};

render() {
return (
<span>
{getClickComponent(this)}
<RemoveUpstreamModal
ref="modal"
loadBalancerService={this.props.loadBalancerService}
upstream={this.props.upstream}
then={this.props.afterRemoveUpstream}
/>
</span>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

import { RemoveUpstreams } from '../../../actions/api/services';

import FormModal from '../modal/FormModal';

class RemoveUpstreamModal extends Component {
static propTypes = {
loadBalancerService: PropTypes.object.isRequired,
upstream: PropTypes.object.isRequired,
removeUpstream: PropTypes.func.isRequired,
then: PropTypes.func,
};

show() {
this.refs.removeUpstreamModal.show();
}

render() {
return (
<FormModal
name="Remove all Upstreams"
ref="removeUpstreamModal"
action="Remove"
onConfirm={this.props.removeUpstream}
buttonStyle="warning"
formElements={[
{
name: 'noValidate',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Validate new configuration after applying changes',
},
{
name: 'noReload',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Reload configuration after applying changes',
},
]}>
<p>Are you sure you want to remove this upstream?</p>
<pre>{this.props.upstream.upstream}</pre>
<p>
This will post a new request to remove this upstream from the nginx
config. It will not alter any other upstreams or options.
</p>
</FormModal>
);
}
}

const mapDispatchToProps = (dispatch, ownProps) => ({
removeUpstream: (data) => dispatch(RemoveUpstreams
.trigger(ownProps.loadBalancerService, [ownProps.upstream], data.noValidate, data.noReload))
.then(response => (ownProps.then && ownProps.then(response)))
});

export default connect(
null,
mapDispatchToProps,
null,
{ withRef: true }
)(RemoveUpstreamModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { PropTypes } from 'react';

import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import ToolTip from 'react-bootstrap/lib/Tooltip';

import { getClickComponent } from '../modal/ModalWrapper';

import RemoveUpstreamsModal from './RemoveUpstreamsModal';

const removeTooltip = (
<ToolTip id="removeAll">
Remove all upstreams from this service
</ToolTip>
);

export default class RemoveUpstreamsButton extends React.Component {
static propTypes = {
loadBalancerService: PropTypes.object,
upstreams: PropTypes.arrayOf(PropTypes.shape({
group: PropTypes.string,
rackId: PropTypes.string,
requestId: PropTypes.string.isRequired,
upstream: PropTypes.string.isRequired,
})),
children: PropTypes.node,
afterRemoveUpstreams: PropTypes.func,
};

static defaultProps = {
children: (
<OverlayTrigger placement="top" id="view-delete-overlay" overlay={removeTooltip}>
<span>
<a className="btn btn-warning">Remove Upstreams</a>
</span>
</OverlayTrigger>
)
};

render() {
return (
<span>
{getClickComponent(this)}
<RemoveUpstreamsModal
ref="modal"
loadBalancerService={this.props.loadBalancerService}
upstreams={this.props.upstreams}
then={this.props.afterRemoveUpstreams}
/>
</span>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

import { RemoveUpstreams } from '../../../actions/api/services';

import FormModal from '../modal/FormModal';

class RemoveUpstreamsModal extends Component {
static propTypes = {
loadBalancerService: PropTypes.object.isRequired,
upstreams: PropTypes.array.isRequired,
removeUpstreams: PropTypes.func.isRequired,
then: PropTypes.func,
};

show() {
this.refs.removeUpstreamsModal.show();
}

render() {
return (
<FormModal
name="Remove all Upstreams"
ref="removeUpstreamsModal"
action="Remove"
onConfirm={this.props.removeUpstreams}
buttonStyle="warning"
formElements={[
{
name: 'noValidate',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Validate new configuration after applying changes',
},
{
name: 'noReload',
type: FormModal.INPUT_TYPES.BOOLEAN,
label: 'Reload configuration after applying changes',
},
]}>
<p>Are you sure you want to remove all upstreams for this service?</p>
<pre>{this.props.loadBalancerService.serviceId}</pre>
<p>
This will post a new request to remove all the current upstreams
for a service. This will effectively 'undo' the request by creating
empty config files.
</p>
</FormModal>
);
}
}

const mapDispatchToProps = (dispatch, ownProps) => ({
removeUpstreams: (data) => dispatch(RemoveUpstreams
.trigger(ownProps.loadBalancerService, ownProps.upstreams, data.noValidate, data.noReload))
.then(response => (ownProps.then && ownProps.then(response)))
});

export default connect(
null,
mapDispatchToProps,
null,
{ withRef: true }
)(RemoveUpstreamsModal);
Loading