mirror of
https://github.com/yldio/copilot.git
synced 2024-12-29 05:10:05 +02:00
feat(cp-gql-mock-server, cp-frontend): Add missing dg and service error messaging
This commit is contained in:
parent
0917d67b07
commit
2eb7f4197f
@ -1,3 +1,4 @@
|
||||
export { default as Loader } from './loader';
|
||||
export { default as ErrorMessage } from './error';
|
||||
export { default as WarningMessage } from './warning';
|
||||
export { default as ModalErrorMessage } from './modal-error';
|
||||
|
24
packages/cp-frontend/src/components/messaging/modal-error.js
Normal file
24
packages/cp-frontend/src/components/messaging/modal-error.js
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { ModalHeading, ModalText, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
const StyledHeading = styled(ModalHeading)`
|
||||
color: ${props => props.theme.red};
|
||||
`;
|
||||
|
||||
const ModalErrorMessage = ({ title, message, onCloseClick }) =>
|
||||
<div>
|
||||
<StyledHeading>{title}</StyledHeading>
|
||||
<ModalText marginBottom="3">{message}
|
||||
</ModalText>
|
||||
<Button onClick={onCloseClick} secondary>Close </Button>
|
||||
</div>;
|
||||
|
||||
ModalErrorMessage.propTypes = {
|
||||
title: PropTypes.string,
|
||||
message: PropTypes.string.isRequired,
|
||||
onCloseClick: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default ModalErrorMessage;
|
@ -2,3 +2,4 @@ export { default as Breadcrumb } from './breadcrumb';
|
||||
export { default as Menu } from './menu';
|
||||
export { default as Header } from './header';
|
||||
export { default as Title } from './title';
|
||||
export { default as NotFound } from './not-found';
|
||||
|
44
packages/cp-frontend/src/components/navigation/not-found.js
Normal file
44
packages/cp-frontend/src/components/navigation/not-found.js
Normal file
@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import { H1, H2, P, Button } from 'joyent-ui-toolkit';
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
margin-top: ${remcalc(60)};
|
||||
`;
|
||||
|
||||
const StyledTitle = styled(H1)`
|
||||
font-weight: normal;
|
||||
font-size: ${remcalc(32)};
|
||||
`;
|
||||
|
||||
const StyledP = styled(P)`
|
||||
margin-bottom: ${remcalc(30)};
|
||||
max-width: ${remcalc(490)};
|
||||
`;
|
||||
|
||||
const NotFound = ({
|
||||
title = 'I have no memory of this place',
|
||||
message = 'HTTP 404: We can’t find what you are looking for. Next time, always follow your nose.',
|
||||
link = 'Back to dashboard',
|
||||
to = '/deployment-groups'
|
||||
}) => (
|
||||
<LayoutContainer>
|
||||
<StyledContainer>
|
||||
<StyledTitle>{title}</StyledTitle>
|
||||
<StyledP>{message}</StyledP>
|
||||
<Button to={to}>{link}</Button>
|
||||
</StyledContainer>
|
||||
</LayoutContainer>
|
||||
);
|
||||
|
||||
NotFound.propTypes = {
|
||||
title: PropTypes.string,
|
||||
message: PropTypes.string,
|
||||
link: PropTypes.string,
|
||||
to: PropTypes.string
|
||||
}
|
||||
|
||||
export default NotFound;
|
@ -3,9 +3,10 @@ import PropTypes from 'prop-types';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import DeploymentGroupDeleteMutation from '@graphql/DeploymentGroupDeleteMutation.gql';
|
||||
import DeploymentGroupQuery from '@graphql/DeploymentGroup.gql';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { Loader, ModalErrorMessage } from '@components/messaging';
|
||||
import { DeploymentGroupDelete as DeploymentGroupDeleteComponent } from '@components/deployment-group';
|
||||
import { Modal, ModalHeading, Button } from 'joyent-ui-toolkit';
|
||||
import { Modal, ModalHeading, Button } from 'joyent-ui-toolkit'
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
class DeploymentGroupDelete extends Component {
|
||||
|
||||
@ -18,7 +19,7 @@ class DeploymentGroupDelete extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, error } = this.props;
|
||||
const { location, history, match, loading, error } = this.props;
|
||||
|
||||
const handleCloseClick = evt => {
|
||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
||||
@ -36,32 +37,26 @@ class DeploymentGroupDelete extends Component {
|
||||
if (error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occurred while loading your deployment group.' />
|
||||
message='An error occurred while loading your deployment group.'
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
deploymentGroup,
|
||||
deleteDeploymentGroup,
|
||||
history,
|
||||
match
|
||||
deleteDeploymentGroup
|
||||
} = this.props;
|
||||
|
||||
if (this.state.error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ModalHeading>
|
||||
Deleting a deployment group: <br /> {deploymentGroup.name}
|
||||
</ModalHeading>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occurred while attempting to delete your deployment group.' />
|
||||
<Button onClick={handleCloseClick} secondary>
|
||||
Ok
|
||||
</Button>
|
||||
message={`An error occured while attempting to delete the ${deploymentGroup.name} deployment group.`}
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -70,6 +65,7 @@ class DeploymentGroupDelete extends Component {
|
||||
deleteDeploymentGroup(deploymentGroup.id)
|
||||
.then(() => handleCloseClick())
|
||||
.catch((err) => {
|
||||
console.log('err = ', err);
|
||||
this.setState({ error: err });
|
||||
});
|
||||
};
|
||||
@ -120,7 +116,8 @@ const DeploymentGroupGql = graphql(DeploymentGroupQuery, {
|
||||
|
||||
const DeploymentGroupDeleteWithData = compose(
|
||||
DeleteDeploymentGroupGql,
|
||||
DeploymentGroupGql
|
||||
DeploymentGroupGql,
|
||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
||||
)(DeploymentGroupDelete);
|
||||
|
||||
export default DeploymentGroupDeleteWithData;
|
||||
|
@ -13,6 +13,7 @@ import { ErrorMessage, Loader } from '@components/messaging';
|
||||
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
||||
import DeploymentGroupsImportableQuery from '@graphql/DeploymentGroupsImportable.gql';
|
||||
import { H2, H3, Small, IconButton, BinIcon } from 'joyent-ui-toolkit';
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
const DGsRows = Row.extend`
|
||||
margin-top: ${remcalc(-7)};
|
||||
@ -216,5 +217,6 @@ export default compose(
|
||||
props: ({ data: { importableDeploymentGroups } }) => ({
|
||||
importable: importableDeploymentGroups
|
||||
})
|
||||
})
|
||||
}),
|
||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
||||
)(DeploymentGroupList);
|
||||
|
@ -11,6 +11,8 @@ import { Title } from '@components/navigation';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { InstanceListItem, EmptyInstances } from '@components/instances';
|
||||
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
const InstanceList = ({ deploymentGroup, instances = [], loading, error }) => {
|
||||
const _title = <Title>Instances</Title>;
|
||||
|
||||
@ -75,7 +77,7 @@ const InstanceListGql = graphql(InstancesQuery, {
|
||||
}
|
||||
};
|
||||
},
|
||||
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
||||
deploymentGroup,
|
||||
instances: sortBy(
|
||||
forceArray(
|
||||
@ -92,4 +94,10 @@ const InstanceListGql = graphql(InstancesQuery, {
|
||||
})
|
||||
});
|
||||
|
||||
export default compose(InstanceListGql)(InstanceList);
|
||||
export default compose(
|
||||
InstanceListGql,
|
||||
withNotFound([
|
||||
GqlPaths.DEPLOYMENT_GROUP,
|
||||
GqlPaths.SERVICES
|
||||
])
|
||||
)(InstanceList);
|
||||
|
@ -1,12 +1,15 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose } from 'react-apollo';
|
||||
import { Breadcrumb as BreadcrumbComponent } from '@components/navigation';
|
||||
import withNotFound from './not-found-hoc';
|
||||
import {
|
||||
deploymentGroupBySlugSelector,
|
||||
serviceBySlugSelector
|
||||
} from '@root/state/selectors';
|
||||
|
||||
const Breadcrumb = ({ deploymentGroup, service, location }) => {
|
||||
|
||||
const path = location.pathname.split('/');
|
||||
|
||||
const links = [
|
||||
@ -33,7 +36,7 @@ const Breadcrumb = ({ deploymentGroup, service, location }) => {
|
||||
return <BreadcrumbComponent links={links} />;
|
||||
};
|
||||
|
||||
const ConnectedBreadcrumb = connect(
|
||||
const connectBreadcrumb = connect(
|
||||
(state, ownProps) => {
|
||||
const params = ownProps.match.params;
|
||||
const deploymentGroupSlug = params.deploymentGroup;
|
||||
@ -47,6 +50,9 @@ const ConnectedBreadcrumb = connect(
|
||||
};
|
||||
},
|
||||
dispatch => ({})
|
||||
)(Breadcrumb);
|
||||
);
|
||||
|
||||
export default ConnectedBreadcrumb;
|
||||
export default compose(
|
||||
connectBreadcrumb,
|
||||
withNotFound()
|
||||
)(Breadcrumb);
|
||||
|
@ -1,3 +1,4 @@
|
||||
export { default as Header } from './header';
|
||||
export { default as Breadcrumb } from './breadcrumb';
|
||||
export { default as Menu } from './menu';
|
||||
export { default as withNotFound, GqlPaths } from './not-found-hoc';
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { compose } from 'react-apollo';
|
||||
import withNotFound from './not-found-hoc';
|
||||
import { Menu as MenuComponent } from '@components/navigation';
|
||||
|
||||
const Menu = ({ match, sections }) => {
|
||||
const Menu = ({ location, match, sections }) => {
|
||||
|
||||
if (!sections || !sections.length) {
|
||||
return null;
|
||||
}
|
||||
@ -16,7 +19,7 @@ const Menu = ({ match, sections }) => {
|
||||
return <MenuComponent links={sectionsWithPathnames} />;
|
||||
};
|
||||
|
||||
const ConnectedMenu = connect(
|
||||
const connectMenu = connect(
|
||||
(state, ownProps) => {
|
||||
const params = ownProps.match.params;
|
||||
const deploymentGroupSlug = params.deploymentGroup;
|
||||
@ -35,6 +38,9 @@ const ConnectedMenu = connect(
|
||||
};
|
||||
},
|
||||
dispatch => ({})
|
||||
)(Menu);
|
||||
);
|
||||
|
||||
export default ConnectedMenu;
|
||||
export default compose(
|
||||
connectMenu,
|
||||
withNotFound()
|
||||
)(Menu);
|
||||
|
@ -0,0 +1,81 @@
|
||||
import React, { Component } from 'react';
|
||||
import { NotFound } from '@components/navigation';
|
||||
|
||||
export const GqlPaths = {
|
||||
DEPLOYMENT_GROUP: 'deploymentGroup',
|
||||
SERVICES: 'services'
|
||||
}
|
||||
|
||||
export default (paths) => {
|
||||
return (WrappedComponent) => {
|
||||
|
||||
return class extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(paths) {
|
||||
const {
|
||||
error,
|
||||
location,
|
||||
history,
|
||||
match
|
||||
} = nextProps;
|
||||
|
||||
if (error && (!location.state || !location.state.notFound)) {
|
||||
if(error.graphQLErrors && error.graphQLErrors.length) {
|
||||
const graphQLError = error.graphQLErrors[0];
|
||||
if(graphQLError.message === 'Not Found') {
|
||||
const notFound = graphQLError.path.pop();
|
||||
if(paths.indexOf(notFound) > -1) {
|
||||
history.replace(location.pathname, { notFound });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const {
|
||||
error,
|
||||
location,
|
||||
match
|
||||
} = this.props;
|
||||
|
||||
if(location.state && location.state.notFound) {
|
||||
const notFound = location.state.notFound;
|
||||
if(paths && paths.indexOf(notFound) > -1) {
|
||||
let title;
|
||||
let to;
|
||||
let link;
|
||||
if(notFound === 'services' || notFound === 'service') {
|
||||
title = 'This service doesn’t exist';
|
||||
to = match.url.split('/').slice(0, 3).join('/');
|
||||
link = 'Back to services';
|
||||
}
|
||||
else if(notFound === 'deploymentGroup') {
|
||||
title = 'This deployment group doesn’t exist';
|
||||
to = '/deployment-group';
|
||||
link = 'Back to dashboard';
|
||||
}
|
||||
return (
|
||||
<NotFound
|
||||
title={title}
|
||||
message='Sorry, but our princess is in another castle.'
|
||||
to={to}
|
||||
link={link}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return <WrappedComponent {...this.props} />
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,11 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import ServicesDeleteMutation from '@graphql/ServicesDeleteMutation.gql';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { Loader, ModalErrorMessage } from '@components/messaging';
|
||||
import { ServiceDelete as ServiceDeleteComponent } from '@components/service';
|
||||
import { Modal, ModalHeading, Button } from 'joyent-ui-toolkit';
|
||||
import ServiceGql from './service-gql';
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
class ServiceDelete extends Component {
|
||||
|
||||
@ -18,7 +19,7 @@ class ServiceDelete extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, error } = this.props;
|
||||
const { loading, error, match, history, location } = this.props;
|
||||
|
||||
const handleCloseClick = evt => {
|
||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
||||
@ -36,27 +37,23 @@ class ServiceDelete extends Component {
|
||||
if (error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occured while loading your service.' />
|
||||
message='An error occured while loading your service.'
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const { service, deleteServices, history, match } = this.props;
|
||||
const { service, deleteServices } = this.props;
|
||||
|
||||
if(this.state.error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ModalHeading>
|
||||
Deleting a service: <br /> {service.name}
|
||||
</ModalHeading>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occurred while attempting to delete your service.' />
|
||||
<Button onClick={handleCloseClick} secondary>
|
||||
Ok
|
||||
</Button>
|
||||
message={`An error occured while attempting to delete the ${service.name} service.`}
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -96,4 +93,8 @@ const DeleteServicesGql = graphql(ServicesDeleteMutation, {
|
||||
})
|
||||
});
|
||||
|
||||
export default compose(DeleteServicesGql, ServiceGql)(ServiceDelete);
|
||||
export default compose(
|
||||
DeleteServicesGql,
|
||||
ServiceGql,
|
||||
withNotFound([ GqlPaths.SERVICES ])
|
||||
)(ServiceDelete);
|
||||
|
@ -3,10 +3,11 @@ import PropTypes from 'prop-types';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { reduxForm } from 'redux-form';
|
||||
import ServiceScaleMutation from '@graphql/ServiceScale.gql';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { Loader, ModalErrorMessage } from '@components/messaging';
|
||||
import { ServiceScale as ServiceScaleComponent } from '@components/service';
|
||||
import { Modal, ModalHeading, Button } from 'joyent-ui-toolkit';
|
||||
import ServiceGql from './service-gql';
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
class ServiceScale extends Component {
|
||||
|
||||
@ -19,7 +20,7 @@ class ServiceScale extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading, error } = this.props;
|
||||
const { loading, error, match, history, location } = this.props;
|
||||
|
||||
const handleCloseClick = evt => {
|
||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
||||
@ -37,27 +38,23 @@ class ServiceScale extends Component {
|
||||
if (error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occured while loading your service.' />
|
||||
message='An error occured while loading your service.'
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const { service, scale, history, match } = this.props;
|
||||
const { service, scale } = this.props;
|
||||
|
||||
if(this.state.error) {
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<ModalHeading>
|
||||
Scaling a service: <br /> {service.name}
|
||||
</ModalHeading>
|
||||
<ErrorMessage
|
||||
<ModalErrorMessage
|
||||
title='Ooops!'
|
||||
message='An error occurred while attempting to scale your service.' />
|
||||
<Button onClick={handleCloseClick} secondary>
|
||||
Ok
|
||||
</Button>
|
||||
message={`An error occured while attempting to scale the ${service.name} service.`}
|
||||
onCloseClick={handleCloseClick} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@ -124,4 +121,8 @@ const ServiceScaleGql = graphql(ServiceScaleMutation, {
|
||||
})
|
||||
});
|
||||
|
||||
export default compose(ServiceScaleGql, ServiceGql)(ServiceScale);
|
||||
export default compose(
|
||||
ServiceScaleGql,
|
||||
ServiceGql,
|
||||
withNotFound([ GqlPaths.SERVICES ])
|
||||
)(ServiceScale);
|
||||
|
@ -21,6 +21,8 @@ import { ServicesQuickActions } from '@components/services';
|
||||
|
||||
import { Message } from 'joyent-ui-toolkit';
|
||||
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
position: relative;
|
||||
`;
|
||||
@ -55,7 +57,8 @@ class ServiceList extends Component {
|
||||
push,
|
||||
restartServices,
|
||||
stopServices,
|
||||
startServices
|
||||
startServices,
|
||||
location
|
||||
} = this.props;
|
||||
|
||||
if (loading && !forceArray(services).length) {
|
||||
@ -77,6 +80,7 @@ class ServiceList extends Component {
|
||||
}
|
||||
|
||||
if (
|
||||
deploymentGroup &&
|
||||
deploymentGroup.status === 'PROVISIONING' &&
|
||||
!forceArray(services).length
|
||||
) {
|
||||
@ -222,7 +226,7 @@ const ServicesGql = graphql(ServicesQuery, {
|
||||
}
|
||||
};
|
||||
},
|
||||
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
||||
deploymentGroup,
|
||||
services: deploymentGroup
|
||||
? processServices(deploymentGroup.services, null)
|
||||
@ -256,7 +260,8 @@ const ServiceListWithData = compose(
|
||||
ServicesStopGql,
|
||||
ServicesStartGql,
|
||||
ServicesGql,
|
||||
UiConnect
|
||||
UiConnect,
|
||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
||||
)(ServiceList);
|
||||
|
||||
export default ServiceListWithData;
|
||||
|
@ -1,10 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { compose } from 'react-apollo';
|
||||
import { Col, Row } from 'react-styled-flexboxgrid';
|
||||
import remcalc from 'remcalc';
|
||||
import unitcalc from 'unitcalc';
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
import { Title } from '@components/navigation';
|
||||
import { withNotFound } from '@containers/navigation';
|
||||
|
||||
import { H2, FormGroup, Toggle, ToggleList, Legend } from 'joyent-ui-toolkit';
|
||||
|
||||
@ -19,6 +21,11 @@ const PaddedRow = Row.extend`
|
||||
`;
|
||||
|
||||
const ServicesMenu = ({ location, history: { push } }) => {
|
||||
|
||||
if(location.state && location.state.notFound) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const toggleValue = location.pathname.split('-').pop();
|
||||
|
||||
const handleToggle = evt => {
|
||||
@ -57,4 +64,4 @@ ServicesMenu.propTypes = {
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default ServicesMenu;
|
||||
export default compose(withNotFound())(ServicesMenu);
|
||||
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
import forceArray from 'force-array';
|
||||
import ServicesQuery from '@graphql/Services.gql';
|
||||
import ServicesRestartMutation from '@graphql/ServicesRestartMutation.gql';
|
||||
import ServicesStopMutation from '@graphql/ServicesStopMutation.gql';
|
||||
@ -17,6 +18,8 @@ import { ServicesQuickActions } from '@components/services';
|
||||
|
||||
import { Topology } from 'joyent-ui-toolkit';
|
||||
|
||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||
|
||||
const StyledBackground = styled.div`
|
||||
padding: ${unitcalc(4)};
|
||||
background-color: ${props => props.theme.whiteActive};
|
||||
@ -50,10 +53,11 @@ class ServicesTopology extends Component {
|
||||
toggleServicesQuickActions,
|
||||
restartServices,
|
||||
stopServices,
|
||||
startServices
|
||||
startServices,
|
||||
location
|
||||
} = this.props;
|
||||
|
||||
if (loading) {
|
||||
if (loading && !forceArray(services).length) {
|
||||
return (
|
||||
<LayoutContainer center>
|
||||
<Loader />
|
||||
@ -62,7 +66,6 @@ class ServicesTopology extends Component {
|
||||
}
|
||||
|
||||
if (error) {
|
||||
|
||||
return (
|
||||
<LayoutContainer>
|
||||
<ErrorMessage
|
||||
@ -73,6 +76,7 @@ class ServicesTopology extends Component {
|
||||
}
|
||||
|
||||
if (
|
||||
deploymentGroup &&
|
||||
deploymentGroup.status === 'PROVISIONING' &&
|
||||
!forceArray(services).length
|
||||
) {
|
||||
@ -232,7 +236,8 @@ const ServicesTopologyWithData = compose(
|
||||
ServicesStopGql,
|
||||
ServicesStartGql,
|
||||
ServicesGql,
|
||||
UiConnect
|
||||
UiConnect,
|
||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
||||
)(ServicesTopology);
|
||||
|
||||
export default ServicesTopologyWithData;
|
||||
|
@ -21,6 +21,8 @@ import {
|
||||
|
||||
import { DeploymentGroupDelete } from '@containers/deployment-group';
|
||||
|
||||
import { NotFound } from '@components/navigation';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
@ -30,25 +32,23 @@ const Container = styled.div`
|
||||
|
||||
const rootRedirect = p => <Redirect to="/deployment-groups" />;
|
||||
|
||||
const deploymentGroupRedirect = p =>
|
||||
const servicesListRedirect = p =>
|
||||
<Redirect
|
||||
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`}
|
||||
/>;
|
||||
|
||||
const servicesTopologyRedirect = p =>
|
||||
<Redirect
|
||||
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-topology`}
|
||||
/>;
|
||||
|
||||
const serviceRedirect = p =>
|
||||
<Redirect
|
||||
to={`/deployment-groups/${p.match.params.deploymentGroup}/services/${p.match
|
||||
.params.service}/instances`}
|
||||
/>;
|
||||
|
||||
// TODO component to be designed
|
||||
const notFound = p => {
|
||||
return <p>
|
||||
NOT FOUND
|
||||
</p>;
|
||||
}
|
||||
|
||||
const APP = p => (
|
||||
const App = p => (
|
||||
<div>
|
||||
|
||||
<Switch>
|
||||
@ -141,7 +141,7 @@ const APP = p => (
|
||||
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup"
|
||||
component={deploymentGroupRedirect}
|
||||
component={servicesListRedirect}
|
||||
/>
|
||||
</Switch>
|
||||
|
||||
@ -171,11 +171,11 @@ const APP = p => (
|
||||
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup/services-list"
|
||||
component={deploymentGroupRedirect}
|
||||
component={servicesListRedirect}
|
||||
/>
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup/services-topology"
|
||||
component={deploymentGroupRedirect}
|
||||
component={servicesTopologyRedirect}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
@ -186,9 +186,9 @@ const Router = (
|
||||
<Container>
|
||||
<Route path="/" component={Header} />
|
||||
<Switch>
|
||||
<Route path="/deployment-groups" component={APP} />
|
||||
<Route path="/deployment-groups" component={App} />
|
||||
<Route path="/" exact component={rootRedirect} />
|
||||
<Route path="/*" component={notFound} />
|
||||
<Route path="/*" component={NotFound} />
|
||||
</Switch>
|
||||
</Container>
|
||||
</BrowserRouter>
|
||||
|
@ -9,6 +9,7 @@ const random = require('lodash.random');
|
||||
const uniq = require('lodash.uniq');
|
||||
const yaml = require('js-yaml');
|
||||
const hasha = require('hasha');
|
||||
const Boom = require('boom');
|
||||
|
||||
const wpData = require('./wp-data.json');
|
||||
const cpData = require('./cp-data.json');
|
||||
@ -96,7 +97,13 @@ const getServices = query => {
|
||||
).map(serviceId => lfind(services, ['id', serviceId]));
|
||||
});
|
||||
|
||||
return Promise.resolve(services);
|
||||
return Promise.resolve(services)
|
||||
.then((services) => {
|
||||
if(!services || !services.length) {
|
||||
throw Boom.notFound();
|
||||
}
|
||||
return services;
|
||||
});
|
||||
};
|
||||
|
||||
const getDeploymentGroups = query => {
|
||||
@ -114,7 +121,12 @@ const getDeploymentGroups = query => {
|
||||
|
||||
return Promise.resolve(
|
||||
deploymentGroups.filter(find(cleanQuery(query))).map(addNestedResolvers)
|
||||
);
|
||||
).then((deploymentGroups) => {
|
||||
if(!deploymentGroups || !deploymentGroups.length) {
|
||||
throw Boom.notFound();
|
||||
}
|
||||
return deploymentGroups;
|
||||
});
|
||||
};
|
||||
|
||||
const getPortal = () =>
|
||||
|
Loading…
Reference in New Issue
Block a user