mirror of
https://github.com/yldio/copilot.git
synced 2024-11-14 15:20:06 +02:00
feat(ui-toolkit, cp-frontend): Add ui to delete a deployment group
This commit is contained in:
parent
db378a6f3a
commit
ee5a071bd9
@ -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 DeploymentGroupDelete = ({ deploymentGroup, onCancelClick, onConfirmClick }) =>
|
||||
<div>
|
||||
<ModalHeading>
|
||||
Deleting a deployment group: <br /> {deploymentGroup.name}
|
||||
</ModalHeading>
|
||||
<ModalText marginBottom="3">
|
||||
Deleting a deployment group will also remove all of the services and instances associated with that deployment group. Are you sure you want to continue?
|
||||
</ModalText>
|
||||
<Button onClick={onCancelClick} secondary>Cancel</Button>
|
||||
<Button onClick={onConfirmClick}>Delete deployment group</Button>
|
||||
</div>;
|
||||
|
||||
DeploymentGroupDelete.propTypes = {
|
||||
deploymentGroup: PropTypes.object,
|
||||
onCancelClick: PropTypes.func.isRequired,
|
||||
onConfirmClick: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default DeploymentGroupDelete;
|
@ -0,0 +1 @@
|
||||
export { default as DeploymentGroupDelete } from './delete';
|
@ -1,16 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { H2, Button, P } from 'joyent-ui-toolkit';
|
||||
|
||||
const ModalHeading = styled(H2)`
|
||||
line-height: 1.25;
|
||||
color: ${props => props.theme.secondary};
|
||||
`;
|
||||
|
||||
const ModalText = styled(P)`
|
||||
color: ${props => props.theme.secondary};
|
||||
`;
|
||||
import { ModalHeading, ModalText, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
const propTypes = {
|
||||
service: PropTypes.object,
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import unitcalc from 'unitcalc';
|
||||
|
||||
import { H2, P, Button } from 'joyent-ui-toolkit';
|
||||
import { ModalHeading, ModalText, Button } from 'joyent-ui-toolkit';
|
||||
import {
|
||||
FormGroup,
|
||||
NumberInput,
|
||||
@ -11,10 +11,6 @@ import {
|
||||
FormMeta
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
const StyledH2 = styled(H2)`
|
||||
margin: 0 0 ${unitcalc(2)} 0;
|
||||
`;
|
||||
|
||||
const ServiceScale = ({
|
||||
service,
|
||||
handleSubmit,
|
||||
@ -23,8 +19,8 @@ const ServiceScale = ({
|
||||
pristine
|
||||
}) =>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<StyledH2>Scaling a service: <br />{service.name}</StyledH2>
|
||||
<P>Choose how many instances of a service you want to have running.</P>
|
||||
<ModalHeading>Scaling a service: <br />{service.name}</ModalHeading>
|
||||
<ModalText>Choose how many instances of a service you want to have running.</ModalText>
|
||||
<FormGroup
|
||||
name="replicas"
|
||||
normalize={NumberInputNormalize({ minValue: 1 })}
|
||||
|
@ -0,0 +1,80 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import DeploymentGroupsDeleteMutation from '@graphql/DeploymentGroupsDeleteMutation.gql';
|
||||
import DeploymentGroupQuery from '@graphql/DeploymentGroup.gql';
|
||||
import { Loader, ErrorMessage } from '@components/messaging';
|
||||
import { DeploymentGroupDelete as DeploymentGroupDeleteComponent } from '@components/deployment-group';
|
||||
import { Modal } from 'joyent-ui-toolkit';
|
||||
|
||||
class DeploymentGroupDelete extends Component {
|
||||
render() {
|
||||
if (this.props.loading) {
|
||||
return <Loader />;
|
||||
}
|
||||
if (this.props.error) {
|
||||
return (
|
||||
<ErrorMessage message="Oops, an error occured while loading your service." />
|
||||
);
|
||||
}
|
||||
|
||||
const { deploymentGroup, deleteDeploymentGroups, history, match } = this.props;
|
||||
|
||||
const handleCloseClick = evt => {
|
||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
||||
history.replace(closeUrl);
|
||||
};
|
||||
|
||||
const handleConfirmClick = evt => {
|
||||
deleteDeploymentGroups(deploymentGroup.id).then(() => handleCloseClick());
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||
<DeploymentGroupDeleteComponent
|
||||
deploymentGroup={deploymentGroup}
|
||||
onConfirmClick={handleConfirmClick}
|
||||
onCancelClick={handleCloseClick}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeploymentGroupDelete.propTypes = {
|
||||
deploymentGroup: PropTypes.object,
|
||||
history: PropTypes.object,
|
||||
deleteDeploymentGroups: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const DeleteDeploymentGroupsGql = graphql(DeploymentGroupsDeleteMutation, {
|
||||
props: ({ mutate }) => ({
|
||||
deleteDeploymentGroups: deploymentGroupId =>
|
||||
mutate({
|
||||
variables: { ids: [deploymentGroupId] }
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const DeploymentGroupGql = graphql(DeploymentGroupQuery, {
|
||||
options(props) {
|
||||
const params = props.match.params;
|
||||
const deploymentGroupSlug = params.deploymentGroup;
|
||||
return {
|
||||
variables: {
|
||||
deploymentGroupSlug
|
||||
}
|
||||
};
|
||||
},
|
||||
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||
deploymentGroup,
|
||||
loading,
|
||||
error
|
||||
})
|
||||
});
|
||||
|
||||
const DeploymentGroupDeleteWithData = compose(DeleteDeploymentGroupsGql, DeploymentGroupGql)(
|
||||
DeploymentGroupDelete
|
||||
);
|
||||
|
||||
export default DeploymentGroupDeleteWithData;
|
@ -0,0 +1 @@
|
||||
export { default as DeploymentGroupDelete } from './delete';
|
@ -12,7 +12,7 @@ import { ErrorMessage } from '@components/messaging';
|
||||
import { DeploymentGroupsLoading } from '@components/deployment-groups';
|
||||
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
||||
import DeploymentGroupsImportableQuery from '@graphql/DeploymentGroupsImportable.gql';
|
||||
import { H2, H3, Small } from 'joyent-ui-toolkit';
|
||||
import { H2, H3, Small, IconButton, BinIcon, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
const Title = H2.extend`
|
||||
margin-top: ${remcalc(2)};
|
||||
@ -22,7 +22,9 @@ const DGsRows = Row.extend`
|
||||
margin-top: ${remcalc(-7)};
|
||||
`;
|
||||
|
||||
const Box = Col.withComponent(Link).extend`
|
||||
// const Box = Col.withComponent(Link).extend`
|
||||
const Box = styled.div`
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: ${props => props.theme.secondary};
|
||||
background-color: ${props => props.theme.white};
|
||||
@ -76,6 +78,36 @@ const ServiceTitle = H3.extend`
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
text-decoration: none;
|
||||
color: ${props => props.theme.secondary};
|
||||
`;
|
||||
|
||||
const DeleteButtonContainer = styled.div`
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
`;
|
||||
|
||||
const StyledIconButton = styled(IconButton)`
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background-color: ${props => props.theme.white};
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:active:hover,
|
||||
&:active:focus {
|
||||
background-color: ${props => props.theme.white};
|
||||
}
|
||||
`;
|
||||
|
||||
const DeploymentGroupList = ({
|
||||
location,
|
||||
deploymentGroups,
|
||||
@ -95,8 +127,13 @@ const DeploymentGroupList = ({
|
||||
|
||||
const groups = forceArray(deploymentGroups).map(({ slug, name }) =>
|
||||
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
||||
<Box to={`${match.path}/${slug}`}>
|
||||
<ServiceTitle>{name}</ServiceTitle>
|
||||
<Box>
|
||||
<StyledLink to={`${match.path}/${slug}`}>
|
||||
<ServiceTitle>{name}</ServiceTitle>
|
||||
</StyledLink>
|
||||
<StyledIconButton to={`${match.url}/${slug}/delete`}>
|
||||
<BinIcon />
|
||||
</StyledIconButton>
|
||||
</Box>
|
||||
</Col>
|
||||
);
|
||||
|
7
packages/cp-frontend/src/graphql/DeploymentGroup.gql
Normal file
7
packages/cp-frontend/src/graphql/DeploymentGroup.gql
Normal file
@ -0,0 +1,7 @@
|
||||
#import "./DeploymentGroupInfo.gql"
|
||||
|
||||
query DeploymentGroup($deploymentGroupSlug: String!) {
|
||||
deploymentGroup(slug: $deploymentGroupSlug) {
|
||||
...DeploymentGroupInfo
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#import "./DeploymentGroupInfo.gql"
|
||||
|
||||
mutation DeleteDeploymentGroups($ids: [ID]!) {
|
||||
deleteDeploymentGroups(ids: $ids) {
|
||||
...DeploymentGroupInfo
|
||||
}
|
||||
}
|
@ -19,6 +19,10 @@ import {
|
||||
ServicesMenu
|
||||
} from '@containers/services';
|
||||
|
||||
import {
|
||||
DeploymentGroupDelete
|
||||
} from '@containers/deployment-group';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
@ -57,15 +61,21 @@ const Router = (
|
||||
<Route path="/deployment-groups" component={Breadcrumb} />
|
||||
</Switch>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup/delete"
|
||||
exact
|
||||
component={DeploymentGroupDelete}
|
||||
/>
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup/services/:service"
|
||||
component={Menu}
|
||||
/>
|
||||
<Route path="/deployment-groups/:deploymentGroup" component={Menu} />
|
||||
<Route path="/deployment-groups/:deploymentGroup" component={Menu} />
|
||||
</Switch>
|
||||
|
||||
<Route path="/" exact component={rootRedirect} />
|
||||
<Route path="/deployment-groups" exact component={DeploymentGroupList} />
|
||||
<Route path="/deployment-groups/:deploymentGroup/delete" exact component={DeploymentGroupList} />
|
||||
|
||||
<Route
|
||||
path="/deployment-groups/:deploymentGroup"
|
||||
|
@ -15,6 +15,6 @@ const alignsFromProps = props =>
|
||||
.join(';\n');
|
||||
|
||||
export default Component =>
|
||||
Component.extend
|
||||
/* Component.extend
|
||||
? Component.extend`${alignsFromProps}`
|
||||
: styled(Component)`${alignsFromProps}`;
|
||||
: */ styled(Component)`${alignsFromProps}`;
|
||||
|
@ -14,7 +14,7 @@ const StyledContainer = styled.div`
|
||||
|
||||
const StyledNumberInput = styled(BaseInput(Stylable('input')))`
|
||||
width: ${unitcalc(20)};
|
||||
margin: 0 ${unitcalc(1)} 0 0;
|
||||
margin: 0 ${unitcalc(2)} 0 0;
|
||||
vertical-align: middle;
|
||||
`;
|
||||
|
||||
@ -39,11 +39,11 @@ const NumberInput = BaseInput(props => {
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledNumberInput {...props} />
|
||||
<StyledNumberInput {...props} marginRight={2}/>
|
||||
<IconButton onClick={handleMinusClick}>
|
||||
<MinusIcon verticalAlign="middle" />
|
||||
</IconButton>
|
||||
<IconButton onClick={handlePlusClick}>
|
||||
<IconButton onClick={handlePlusClick} marginLeft={1}>
|
||||
<PlusIcon verticalAlign="middle" />
|
||||
</IconButton>
|
||||
</StyledContainer>
|
||||
|
@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import { borderRadius } from '../boxes';
|
||||
import Baseline from '../baseline';
|
||||
import { A, Button as NButton } from 'normalized-styled-components';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const StyledIconButton = styled.button`
|
||||
const style = css`
|
||||
border-radius: ${borderRadius};
|
||||
border: solid ${remcalc(1)} ${props => props.theme.grey};
|
||||
background-color: ${props => props.theme.white};
|
||||
@ -13,13 +15,13 @@ const StyledIconButton = styled.button`
|
||||
display: inline-block;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: ${remcalc(6)};
|
||||
padding: ${remcalc(15)} ${remcalc(18)};
|
||||
position: relative;
|
||||
text-align: center;
|
||||
line-height: normal;
|
||||
vertical-align: middle;
|
||||
touch-action: manipulation;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
@ -67,6 +69,20 @@ const StyledIconButton = styled.button`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButton = NButton.extend`
|
||||
${style}
|
||||
`;
|
||||
|
||||
const StyledAnchor = A.extend`
|
||||
display: inline-block;
|
||||
${style}
|
||||
`;
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
display: inline-block;
|
||||
${style}
|
||||
`;
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
height: ${remcalc(16)};
|
||||
`;
|
||||
@ -74,12 +90,32 @@ const StyledDiv = styled.div`
|
||||
/**
|
||||
* @example ./usage.md
|
||||
*/
|
||||
const IconButton = ({ children, onClick }) =>
|
||||
<StyledIconButton onClick={onClick}>
|
||||
const IconButton = props => {
|
||||
const { href = '', to = '', children } = props;
|
||||
|
||||
const Views = [
|
||||
() => (to ? StyledLink : null),
|
||||
() => (href ? StyledAnchor : null),
|
||||
() => StyledButton
|
||||
];
|
||||
|
||||
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
||||
|
||||
return (
|
||||
<View {...props}>
|
||||
<StyledDiv>
|
||||
{children}
|
||||
</StyledDiv>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
/* ({ children, ...rest }) =>
|
||||
<StyledIconButton {...rest}>
|
||||
<StyledDiv>
|
||||
{children}
|
||||
</StyledDiv>
|
||||
</StyledIconButton>;
|
||||
</StyledIconButton>; */
|
||||
|
||||
IconButton.propTypes = {
|
||||
children: PropTypes.node,
|
||||
|
7
packages/ui-toolkit/src/icons/bin.js
Normal file
7
packages/ui-toolkit/src/icons/bin.js
Normal file
@ -0,0 +1,7 @@
|
||||
import Baseline from '../baseline';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import React from 'react';
|
||||
|
||||
import BinIcon from './svg/icon_bin.svg';
|
||||
|
||||
export default Baseline(BinIcon);
|
@ -6,3 +6,4 @@ export { default as TickIcon } from './tick';
|
||||
export { default as InstancesIcon } from './instances';
|
||||
export { default as HealthyIcon } from './healthy';
|
||||
export { default as UnhealthyIcon } from './unhealthy';
|
||||
export { default as BinIcon } from './bin';
|
||||
|
12
packages/ui-toolkit/src/icons/svg/icon_bin.svg
Normal file
12
packages/ui-toolkit/src/icons/svg/icon_bin.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="12px" height="17px" viewBox="0 0 12 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 45.2 (43514) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon: delete</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="home" transform="translate(-467.000000, -421.000000)" fill="#646464">
|
||||
<path d="M471,421 L471,422 L467,422 L467,424 L479,424 L479,422 L475.001,422 L475.001,421 L471,421 Z M468,438 L478,438 L478,425 L468,425 L468,438 Z" id="icon:-delete"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 737 B |
@ -12,7 +12,7 @@ export { default as Small } from './text/small';
|
||||
export { default as theme } from './theme';
|
||||
export { default as typography, fonts } from './typography';
|
||||
export { default as Topology } from './topology';
|
||||
export { default as Modal } from './modal';
|
||||
export { default as Modal, ModalHeading, ModalText } from './modal';
|
||||
export { default as CloseButton } from './close-button';
|
||||
export { default as IconButton } from './icon-button';
|
||||
export { Tooltip, TooltipButton, TooltipDivider } from './tooltip';
|
||||
@ -101,5 +101,6 @@ export {
|
||||
ArrowIcon,
|
||||
InstancesIcon,
|
||||
HealthyIcon,
|
||||
UnhealthyIcon
|
||||
UnhealthyIcon,
|
||||
BinIcon
|
||||
} from './icons';
|
||||
|
@ -7,6 +7,8 @@ import theme from '../theme';
|
||||
import { border, borderRadius, modalShadow } from '../boxes';
|
||||
import Button from '../button';
|
||||
import CloseButton from '../close-button';
|
||||
import P from '../text/p';
|
||||
import { H2 } from '../text/headings';
|
||||
|
||||
const StyledBackground = styled.div`
|
||||
position: fixed;
|
||||
@ -15,6 +17,7 @@ const StyledBackground = styled.div`
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(250, 250, 250, 0.5);
|
||||
z-index: 100;
|
||||
`;
|
||||
|
||||
const StyledModal = styled.div`
|
||||
@ -27,6 +30,7 @@ const StyledModal = styled.div`
|
||||
|
||||
width: ${props => remcalc(props.width)};
|
||||
margin: 0 auto 0 -${props => remcalc(props.width / 2)};
|
||||
z-index: 101;
|
||||
`;
|
||||
|
||||
// tmp
|
||||
@ -66,3 +70,14 @@ Modal.propTypes = {
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
|
||||
export const ModalHeading = styled(H2)`
|
||||
line-height: 1.25;
|
||||
color: ${props => props.theme.secondary};
|
||||
margin: 0 0 ${remcalc(12)} 0;
|
||||
`;
|
||||
|
||||
export const ModalText = styled(P)`
|
||||
color: ${props => props.theme.secondary};
|
||||
margin: ${remcalc(12)} 0 ${remcalc(30)} 0;
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user