diff --git a/packages/cp-frontend/src/components/instances/list-item.js b/packages/cp-frontend/src/components/instances/list-item.js
index 3a711528..41d3cf77 100644
--- a/packages/cp-frontend/src/components/instances/list-item.js
+++ b/packages/cp-frontend/src/components/instances/list-item.js
@@ -85,6 +85,8 @@ const StatusBadge = ({ status }) => {
};
const StyledCard = Card.extend`
+ flex-direction: row;
+
&:not(:last-child) {
margin-bottom: 0;
box-shadow: none;
diff --git a/packages/cp-frontend/src/components/services/instance-statuses.js b/packages/cp-frontend/src/components/services/instance-statuses.js
new file mode 100644
index 00000000..412f316e
--- /dev/null
+++ b/packages/cp-frontend/src/components/services/instance-statuses.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styled from 'styled-components';
+import remcalc from 'remcalc';
+import { P } from 'joyent-ui-toolkit';
+
+const StyledStatus = P.extend`
+ margin: 0;
+ font-size: ${remcalc(13)};
+ line-height: ${remcalc(13)};
+`;
+
+const StyledStatusContainer = styled.div`
+ margin: ${remcalc(6)} 0 ${remcalc(12)} 0;
+ height: ${remcalc(54)}
+`;
+
+const InstanceStatuses = ({ instances }) => {
+ const statuses = instances.reduce((statuses, instance) => {
+ if (instance.status !== 'RUNNING') {
+ if (statuses[instance.status]) {
+ statuses[instance.status]++;
+ } else {
+ statuses[instance.status] = 1;
+ }
+ }
+ return statuses;
+ }, {});
+
+ const instanceStatuses = Object.keys(statuses).map(status => {
+ const instances = statuses[status];
+ return (
+
+ {`${instances}
+ ${instances > 1 ? 'instances' : 'instance'}
+ ${status.toLowerCase()}`}
+
+ );
+ });
+
+ return (
+
+ {instanceStatuses}
+
+ );
+};
+
+InstanceStatuses.propTypes = {
+ instances: PropTypes.array.isRequired
+};
+
+export default InstanceStatuses;
diff --git a/packages/cp-frontend/src/components/services/list-item.js b/packages/cp-frontend/src/components/services/list-item.js
index ca2a91a0..414668f8 100644
--- a/packages/cp-frontend/src/components/services/list-item.js
+++ b/packages/cp-frontend/src/components/services/list-item.js
@@ -1,9 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
-// Import forceArray from 'force-array';
-// import ItemMetricGroup from '@components/item-metric-group';
import {
Card,
CardView,
@@ -14,13 +12,14 @@ import {
CardGroupView,
CardOptions,
CardHeader,
- // CardInfo,
+ CardInfo,
Anchor
- // DataCentersIcon,
- // HealthyIcon,
- // InstancesMultipleIcon
} from 'joyent-ui-toolkit';
+import { InstancesIcon, HealthyIcon, P } from 'joyent-ui-toolkit';
+
+import InstanceStatuses from './instance-statuses';
+
const StyledCardHeader = styled(CardHeader)`
position: relative;
`;
@@ -64,34 +63,37 @@ const ServiceListItem = ({
;
const subtitle = (
- {service.instances.length} instances
+
+ {service.instances.length}{' '}
+ {service.instances.length > 1 ? 'instances' : 'instance'}
+
);
const handleCardOptionsClick = evt => {
onQuickActionsClick(evt, service);
};
- const statuses = service.instances.map(instance =>
-
1 instance {instance.status}
- );
+ const instancesCount = service.children
+ ? service.children.reduce(
+ (count, child) => count + child.instances.length,
+ 0
+ )
+ : service.instances.length;
const header = isChild
? null
:
-
- {title}
-
- {/* }
- iconPosition="top"
- label={`${service.instances} ${service.instances > 1 ? 'instances' : 'instance'}`}
- /> */}
- {/* }
- label={service.datacenters[0].id}
- /> */}
-
-
+ {title}
+
+ }
+ iconPosition="left"
+ label={`${instancesCount} ${instancesCount > 1
+ ? 'instances'
+ : 'instance'}`}
+ color="light"
+ />
+
;
@@ -100,17 +102,17 @@ const ServiceListItem = ({
{children}
:
-
- {isChild && title}
- {isChild && subtitle}
-
- {/* } label="Healthy" /> */}
- {statuses}
-
-
- {/* */}
+ {isChild && title}
+ {isChild && subtitle}
+
+
+ }
+ iconPosition="left"
+ label="Healthy"
+ color="dark"
+ />
+
;
return (
diff --git a/packages/cp-frontend/src/components/services/quick-actions.js b/packages/cp-frontend/src/components/services/quick-actions.js
index 4c341201..23f1efd9 100644
--- a/packages/cp-frontend/src/components/services/quick-actions.js
+++ b/packages/cp-frontend/src/components/services/quick-actions.js
@@ -10,7 +10,9 @@ const ServicesQuickActions = ({
onBlur,
onRestartClick,
onStopClick,
- onStartClick
+ onStartClick,
+ onScaleClick,
+ onDeleteClick
}) => {
if (!show) {
return null;
@@ -25,9 +27,6 @@ const ServicesQuickActions = ({
return p;
}, {});
- const scaleUrl = `${url}/${service.slug}/scale`;
- const deleteUrl = `${url}/${service.slug}/delete`;
-
const handleRestartClick = evt => {
onRestartClick(evt, service);
};
@@ -40,6 +39,14 @@ const ServicesQuickActions = ({
onStopClick(evt, service);
};
+ const handleScaleClick = evt => {
+ onScaleClick(evt, service);
+ };
+
+ const handleDeleteClick = evt => {
+ onDeleteClick(evt, service);
+ };
+
const status = service.instances.reduce((status, instance) => {
return status
? instance.status === status ? status : 'MIXED'
@@ -56,25 +63,26 @@ const ServicesQuickActions = ({
return (
- Scale
+ Scale
Restart
{startService}
{stopService}
- Delete
+ Delete
);
};
ServicesQuickActions.propTypes = {
service: PropTypes.object.isRequired,
- url: PropTypes.string.isRequired,
position: PropTypes.object,
show: PropTypes.bool,
onBlur: PropTypes.func,
onRestartClick: PropTypes.func,
onStopClick: PropTypes.func,
- onStartClick: PropTypes.func
+ onStartClick: PropTypes.func,
+ onScaleClick: PropTypes.func,
+ onDeleteClick: PropTypes.func
};
export default ServicesQuickActions;
diff --git a/packages/cp-frontend/src/containers/services/list.js b/packages/cp-frontend/src/containers/services/list.js
index 690a6974..270d5b4d 100644
--- a/packages/cp-frontend/src/containers/services/list.js
+++ b/packages/cp-frontend/src/containers/services/list.js
@@ -38,6 +38,7 @@ class ServiceList extends Component {
servicesQuickActions,
toggleServicesQuickActions,
url,
+ push,
restartServices,
stopServices,
startServices
@@ -89,6 +90,16 @@ class ServiceList extends Component {
startServices(service.id);
};
+ const handleScaleClick = (evt, service) => {
+ toggleServicesQuickActions({ show: false });
+ push(`${url}/${service.slug}/delete`);
+ };
+
+ const handleDeleteClick = (evt, service) => {
+ toggleServicesQuickActions({ show: false });
+ push(`${url}/${service.slug}/scale`);
+ };
+
const handleQuickActionsBlur = o => {
toggleServicesQuickActions({ show: false });
};
@@ -113,11 +124,12 @@ class ServiceList extends Component {
position={servicesQuickActions.position}
service={servicesQuickActions.service}
show={servicesQuickActions.show}
- url={url}
onBlur={handleQuickActionsBlur}
onRestartClick={handleRestartClick}
onStopClick={handleStopClick}
onStartClick={handleStartClick}
+ onScaleClick={handleScaleClick}
+ onDeleteClick={handleDeleteClick}
/>
@@ -128,7 +140,8 @@ class ServiceList extends Component {
const mapStateToProps = (state, ownProps) => ({
servicesQuickActions: state.ui.services.quickActions,
- url: ownProps.match.url.replace(/\/$/, '')
+ url: ownProps.match.url.replace(/\/$/, ''),
+ push: ownProps.history.push
});
const mapDispatchToProps = dispatch => ({
diff --git a/packages/cp-frontend/src/router.js b/packages/cp-frontend/src/router.js
index 41458742..5676e7b6 100644
--- a/packages/cp-frontend/src/router.js
+++ b/packages/cp-frontend/src/router.js
@@ -67,11 +67,28 @@ const Router = (
+
+
+
+
+
+
-
+
+
-
-
-
-
);
diff --git a/packages/ui-toolkit/src/card/card.js b/packages/ui-toolkit/src/card/card.js
index 6b13cc29..14a98963 100644
--- a/packages/ui-toolkit/src/card/card.js
+++ b/packages/ui-toolkit/src/card/card.js
@@ -16,6 +16,7 @@ const StyledCard = Row.extend`
border: ${remcalc(1)} solid ${props => props.theme.grey};
background-color: ${props => props.theme.white};
box-shadow: ${bottomShaddow};
+ flex-direction: column;
${is('collapsed')`
min-height: auto;
diff --git a/packages/ui-toolkit/src/card/description.js b/packages/ui-toolkit/src/card/description.js
index 0db7b155..bf3161e3 100644
--- a/packages/ui-toolkit/src/card/description.js
+++ b/packages/ui-toolkit/src/card/description.js
@@ -15,10 +15,7 @@ const StyledTitle = Title.extend`
flex-grow: 2;
${isNot('collapsed')`
- position: absolute;
- bottom: 0;
padding-bottom: ${remcalc(12)};
- padding-top: 0;
`};
`;
diff --git a/packages/ui-toolkit/src/card/group-view.js b/packages/ui-toolkit/src/card/group-view.js
index 8fe287a3..a7ede584 100644
--- a/packages/ui-toolkit/src/card/group-view.js
+++ b/packages/ui-toolkit/src/card/group-view.js
@@ -5,7 +5,7 @@ import React from 'react';
const StyledView = View.extend`
display: block;
- padding: ${remcalc(62, 23, 5, 23)};
+ padding: ${remcalc(12, 24, 6, 24)};
background-color: ${props => props.grey};
`;
diff --git a/packages/ui-toolkit/src/card/header.js b/packages/ui-toolkit/src/card/header.js
index 21065c8a..ea0c8d6b 100644
--- a/packages/ui-toolkit/src/card/header.js
+++ b/packages/ui-toolkit/src/card/header.js
@@ -7,6 +7,7 @@ import Card from './card';
const StyledCard = Card.extend`
position: absolute;
+ flex-direction: row;
background-color: ${props => props.theme.primary};
border: solid ${remcalc(1)} ${props => props.theme.primaryDesaturatedActive};
diff --git a/packages/ui-toolkit/src/card/index.js b/packages/ui-toolkit/src/card/index.js
index 8b4b0709..2ddc34b4 100644
--- a/packages/ui-toolkit/src/card/index.js
+++ b/packages/ui-toolkit/src/card/index.js
@@ -8,4 +8,4 @@ export { default as CardOutlet } from './outlet.js';
export { default as CardSubTitle } from './subtitle.js';
export { default as CardTitle } from './title.js';
export { default as CardView } from './view.js';
-// Export { default as CardInfo } from './info.js';
+export { default as CardInfo } from './info.js';
diff --git a/packages/ui-toolkit/src/card/info.js b/packages/ui-toolkit/src/card/info.js
new file mode 100644
index 00000000..b6abcdc0
--- /dev/null
+++ b/packages/ui-toolkit/src/card/info.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styled from 'styled-components';
+import remcalc from 'remcalc';
+import Label from '../label';
+
+const StyledLabel = Label.extend`
+ ${props => (props.color === 'light' ? `color: ${props.theme.white};` : '')};
+ margin-left: ${props => (props.iconPosition === 'left' ? remcalc(24) : 0)}
+`;
+
+const StyledIconContainer = styled.div`
+ position: absolute;
+
+ > svg {
+ ${props => (props.color === 'light' ? `fill: ${props.theme.white};` : '')};
+ }
+`;
+
+const CardInfo = ({ label, icon, iconPosition = 'left', color = 'light' }) => {
+ return (
+
+
+ {icon}
+
+
+ {label}
+
+
+ );
+};
+
+CardInfo.propTypes = {
+ label: PropTypes.string.isRequired,
+ icon: PropTypes.node.isRequired,
+ iconPosition: PropTypes.string,
+ color: PropTypes.oneOf(['dark', 'light'])
+};
+
+export default CardInfo;
diff --git a/packages/ui-toolkit/src/card/view.js b/packages/ui-toolkit/src/card/view.js
index 67acf644..566dc247 100644
--- a/packages/ui-toolkit/src/card/view.js
+++ b/packages/ui-toolkit/src/card/view.js
@@ -12,8 +12,9 @@ const StyledView = Row.extend`
height: auto;
padding-top: 0;
min-width: auto;
+ flex-direction: row;
- ${is('headed')`
+ /*${is('headed')`
padding-top: ${remcalc(47)};
`};
@@ -23,7 +24,7 @@ const StyledView = Row.extend`
${is('fromHeader')`
padding-top: 0;
- `};
+ `};*/
`;
const View = ({ children, ...rest }) => {
diff --git a/packages/ui-toolkit/src/icons/healthy.js b/packages/ui-toolkit/src/icons/healthy.js
new file mode 100644
index 00000000..c8124e89
--- /dev/null
+++ b/packages/ui-toolkit/src/icons/healthy.js
@@ -0,0 +1,7 @@
+import Baseline from '../baseline';
+// eslint-disable-next-line no-unused-vars
+import React from 'react';
+
+import HealthyIcon from './svg/icon_healthy.svg';
+
+export default Baseline(HealthyIcon);
diff --git a/packages/ui-toolkit/src/icons/index.js b/packages/ui-toolkit/src/icons/index.js
index 4a0a5a90..b11b14f8 100644
--- a/packages/ui-toolkit/src/icons/index.js
+++ b/packages/ui-toolkit/src/icons/index.js
@@ -3,3 +3,5 @@ export { default as PlusIcon } from './plus';
export { default as MinusIcon } from './minus';
export { default as ArrowIcon } from './arrow';
export { default as TickIcon } from './tick';
+export { default as InstancesIcon } from './instances';
+export { default as HealthyIcon } from './healthy';
diff --git a/packages/ui-toolkit/src/icons/instances.js b/packages/ui-toolkit/src/icons/instances.js
new file mode 100644
index 00000000..b184a672
--- /dev/null
+++ b/packages/ui-toolkit/src/icons/instances.js
@@ -0,0 +1,7 @@
+import Baseline from '../baseline';
+// eslint-disable-next-line no-unused-vars
+import React from 'react';
+
+import InstancesIcon from './svg/icon_instances.svg';
+
+export default Baseline(InstancesIcon);
diff --git a/packages/ui-toolkit/src/icons/svg/icon_instances.svg b/packages/ui-toolkit/src/icons/svg/icon_instances.svg
index fe15312e..642dd9e3 100755
--- a/packages/ui-toolkit/src/icons/svg/icon_instances.svg
+++ b/packages/ui-toolkit/src/icons/svg/icon_instances.svg
@@ -4,8 +4,8 @@
icon: instances
Created with Sketch.
-
-
+
+
@@ -17,4 +17,4 @@
-
\ No newline at end of file
+
diff --git a/packages/ui-toolkit/src/index.js b/packages/ui-toolkit/src/index.js
index 375a2ab3..33aeab97 100644
--- a/packages/ui-toolkit/src/index.js
+++ b/packages/ui-toolkit/src/index.js
@@ -58,7 +58,8 @@ export {
CardOutlet,
CardSubTitle,
CardTitle,
- CardView
+ CardView,
+ CardInfo
} from './card';
export {
@@ -91,3 +92,12 @@ export {
Link as SectionListLink,
NavLink as SectionListNavLink
} from './section-list';
+
+export {
+ CloseIcon,
+ PlusIcon,
+ MinusIcon,
+ ArrowIcon,
+ InstancesIcon,
+ HealthyIcon
+} from './icons';