1
0
mirror of https://github.com/yldio/copilot.git synced 2024-12-29 05:10:05 +02:00

style: format

This commit is contained in:
Sérgio Ramos 2017-08-28 20:21:08 +01:00
parent d1af5eec1a
commit cac9453154
153 changed files with 995 additions and 1225 deletions

View File

@ -16,11 +16,13 @@ module.exports = {
const { list, get } = api.users;
return args.id
? get(args).then(user => [user]).then(user =>
Object.assign(user, {
isUser: true
})
)
? get(args)
.then(user => [user])
.then(user =>
Object.assign(user, {
isUser: true
})
)
: list();
}
};

View File

@ -17,9 +17,7 @@ class App extends Component {
render() {
return (
<ApolloProvider client={client} store={store}>
<ThemeProvider theme={theme}>
{Router}
</ThemeProvider>
<ThemeProvider theme={theme}>{Router}</ThemeProvider>
</ApolloProvider>
);
}

View File

@ -6,7 +6,7 @@ const DeploymentGroupDelete = ({
deploymentGroup,
onCancelClick = () => {},
onConfirmClick = () => {}
}) =>
}) => (
<div>
<ModalHeading>
Deleting a deployment group: <br /> {deploymentGroup.name}
@ -20,7 +20,8 @@ const DeploymentGroupDelete = ({
Cancel
</Button>
<Button onClick={onConfirmClick}>Delete deployment group</Button>
</div>;
</div>
);
DeploymentGroupDelete.propTypes = {
deploymentGroup: PropTypes.object.isRequired,

View File

@ -3,9 +3,10 @@ import React from 'react';
import { Col, Row } from 'react-styled-flexboxgrid';
import { P } from 'joyent-ui-toolkit';
export default () =>
export default () => (
<Row>
<Col xs={12}>
<P>You don't have any instances</P>
</Col>
</Row>;
</Row>
);

View File

@ -65,7 +65,16 @@ const StyledCard = Card.extend`
background-color: ${props => props.theme.white};
${isOr('stopping', 'stopped', 'offline', 'destroyed', 'failed', 'deleted', 'incomplete', 'unknown')`
${isOr(
'stopping',
'stopped',
'offline',
'destroyed',
'failed',
'deleted',
'incomplete',
'unknown'
)`
background-color: ${props => props.theme.background};
& [name="card-options"] > button {
@ -80,7 +89,6 @@ const InstanceCard = ({
onStatusMouseOver = () => {},
onMouseOut = () => {}
}) => {
const statusProps = STATUSES.reduce(
(acc, name) =>
Object.assign(acc, {
@ -92,42 +100,34 @@ const InstanceCard = ({
const label = (instance.healthy || 'UNKNOWN').toLowerCase();
const icon = <HealthyIcon healthy={instance.healthy} />;
const handleHealthMouseOver = (evt) => {
const handleHealthMouseOver = evt => {
onHealthMouseOver(evt, instance);
}
};
const handleStatusMouseOver = (evt) => {
const handleStatusMouseOver = evt => {
onStatusMouseOver(evt, instance);
}
};
const handleMouseOut = (evt) => {
const handleMouseOut = evt => {
onMouseOut(evt);
}
};
return (
<StyledCard collapsed={true} key={instance.uuid} {...statusProps}>
<CardView>
<CardTitle>
{instance.name}
</CardTitle>
<CardTitle>{instance.name}</CardTitle>
<CardDescription>
<div
onMouseOver={handleHealthMouseOver}
onMouseOut={handleMouseOut}
>
<div onMouseOver={handleHealthMouseOver} onMouseOut={handleMouseOut}>
<CardInfo
icon={icon}
iconPosition='left'
iconPosition="left"
label={label}
color='dark'
color="dark"
/>
</div>
</CardDescription>
<CardDescription>
<div
onMouseOver={handleStatusMouseOver}
onMouseOut={handleMouseOut}
>
<div onMouseOver={handleStatusMouseOver} onMouseOut={handleMouseOut}>
<Label>
<Dot {...statusProps} />
{titleCase(instance.status)}
@ -136,7 +136,7 @@ const InstanceCard = ({
</CardDescription>
</CardView>
</StyledCard>
)
);
};
InstanceCard.propTypes = {

View File

@ -143,31 +143,29 @@ class ManifestEditorBundle extends Component {
const { ManifestEditor } = this.state;
const { children, ...rest } = this.props;
return (
<ManifestEditor {...rest}>
{children}
</ManifestEditor>
);
return <ManifestEditor {...rest}>{children}</ManifestEditor>;
}
}
const MEditor = ({ input, defaultValue, readOnly }) =>
const MEditor = ({ input, defaultValue, readOnly }) => (
<ManifestEditorBundle
mode="yaml"
{...input}
value={input.value || defaultValue}
readOnly={readOnly}
/>;
/>
);
const EEditor = ({ input, defaultValue, readOnly }) =>
const EEditor = ({ input, defaultValue, readOnly }) => (
<ManifestEditorBundle
mode="ini"
{...input}
value={input.value || defaultValue}
readOnly={readOnly}
/>;
/>
);
export const Name = ({ handleSubmit, onCancel, dirty }) =>
export const Name = ({ handleSubmit, onCancel, dirty }) => (
<form onSubmit={handleSubmit}>
<Row>
<Col xs={12} md={3} lg={3}>
@ -185,7 +183,8 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
Next
</Button>
</ButtonsRow>
</form>;
</form>
);
export const Manifest = ({
handleSubmit,
@ -193,7 +192,7 @@ export const Manifest = ({
dirty,
defaultValue = '',
loading
}) =>
}) => (
<form onSubmit={handleSubmit}>
<Field name="manifest" defaultValue={defaultValue} component={MEditor} />
<ButtonsRow>
@ -208,30 +207,31 @@ export const Manifest = ({
Environment
</Button>
</ButtonsRow>
</form>;
</form>
);
const File = ({ id, name, value, onRemoveFile, readOnly }) => {
const removeButton = !readOnly
? <FilenameRemove type="button" onClick={onRemoveFile} secondary>
Remove
</FilenameRemove>
: null;
const removeButton = !readOnly ? (
<FilenameRemove type="button" onClick={onRemoveFile} secondary>
Remove
</FilenameRemove>
) : null;
const fileEditor = !readOnly
? <Field
name={`file-value-${id}`}
defaultValue={value}
component={EEditor}
/>
: <EEditor input={{ value }} readOnly />;
const fileEditor = !readOnly ? (
<Field name={`file-value-${id}`} defaultValue={value} component={EEditor} />
) : (
<EEditor input={{ value }} readOnly />
);
const input = !readOnly
? <FilenameInput type="text" placeholder="Filename including extension…" />
: <FilenameInput
type="text"
placeholder="Filename including extension…"
value={name}
/>;
const input = !readOnly ? (
<FilenameInput type="text" placeholder="Filename including extension…" />
) : (
<FilenameInput
type="text"
placeholder="Filename including extension…"
value={name}
/>
);
return (
<FileCard>
@ -247,15 +247,15 @@ const File = ({ id, name, value, onRemoveFile, readOnly }) => {
};
const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
const footer = !readOnly
? <Button type="button" onClick={onAddFile} secondary>
Create new .env file
</Button>
: null;
const footer = !readOnly ? (
<Button type="button" onClick={onAddFile} secondary>
Create new .env file
</Button>
) : null;
return (
<div>
{files.map(({ id, ...rest }) =>
{files.map(({ id, ...rest }) => (
<File
key={id}
id={id}
@ -263,7 +263,7 @@ const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
readOnly={readOnly}
{...rest}
/>
)}
))}
{footer}
</div>
);
@ -280,30 +280,28 @@ export const Environment = ({
readOnly = false,
loading
}) => {
const envEditor = !readOnly
? <Field
name="environment"
defaultValue={defaultValue}
component={EEditor}
/>
: <EEditor input={{ value: defaultValue }} readOnly />;
const envEditor = !readOnly ? (
<Field name="environment" defaultValue={defaultValue} component={EEditor} />
) : (
<EEditor input={{ value: defaultValue }} readOnly />
);
const footerDivider = !readOnly ? <EnvironmentDivider /> : null;
const footer = !readOnly
? <ButtonsRow>
<Button type="button" onClick={onCancel} secondary>
Cancel
</Button>
<Button
disabled={!(dirty || !loading || defaultValue.length)}
loading={loading}
type="submit"
>
Continue
</Button>
</ButtonsRow>
: null;
const footer = !readOnly ? (
<ButtonsRow>
<Button type="button" onClick={onCancel} secondary>
Cancel
</Button>
<Button
disabled={!(dirty || !loading || defaultValue.length)}
loading={loading}
type="submit"
>
Continue
</Button>
</ButtonsRow>
) : null;
return (
<form onSubmit={handleSubmit}>
@ -348,18 +346,18 @@ export const Review = ({
environmentToggles,
...state
}) => {
const serviceList = forceArray(state.services).map(({ name, config }) =>
const serviceList = forceArray(state.services).map(({ name, config }) => (
<ServiceCard key={name}>
<ServiceName>
{name}
</ServiceName>
<ServiceName>{name}</ServiceName>
<Dl>
<dt>
<ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image>
</dt>
</Dl>
{config.environment && config.environment.length ? <ServiceDivider /> : null}
{config.environment && config.environment.length ?
{config.environment && config.environment.length ? (
<ServiceDivider />
) : null}
{config.environment && config.environment.length ? (
<ServiceEnvironmentTitle
expanded={environmentToggles[name]}
onClick={() => onEnvironmentToggle(name)}
@ -370,12 +368,14 @@ export const Review = ({
up={environmentToggles[name]}
/>
</ServiceEnvironmentTitle>
: null}
{config.environment && config.environment.length && environmentToggles[name]
? <EnvironmentReview environment={config.environment} />
: null}
) : null}
{config.environment &&
config.environment.length &&
environmentToggles[name] ? (
<EnvironmentReview environment={config.environment} />
) : null}
</ServiceCard>
);
));
return (
<form onSubmit={handleSubmit}>
@ -396,18 +396,18 @@ export const Progress = ({ stage, create, edit }) => {
const _nameCompleted = stage !== 'name';
const _nameActive = stage === 'name';
const _name = !create
? null
: <ProgressbarItem>
<ProgressbarButton
zIndex="10"
completed={_nameCompleted}
active={_nameActive}
first
>
Name the group
</ProgressbarButton>
</ProgressbarItem>;
const _name = !create ? null : (
<ProgressbarItem>
<ProgressbarButton
zIndex="10"
completed={_nameCompleted}
active={_nameActive}
first
>
Name the group
</ProgressbarButton>
</ProgressbarItem>
);
const _manifestCompleted = ['environment', 'review'].indexOf(stage) >= 0;
const _manifestActive = create ? stage === 'manifest' : stage === 'edit';

View File

@ -2,8 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Message } from 'joyent-ui-toolkit';
const ErrorMessage = ({ title, message = "Ooops, there's been an error" }) =>
<Message title={title} message={message} type="ERROR" />;
const ErrorMessage = ({ title, message = "Ooops, there's been an error" }) => (
<Message title={title} message={message} type="ERROR" />
);
ErrorMessage.propTypes = {
title: PropTypes.string,

View File

@ -27,10 +27,9 @@ const Msg = P.extend`
margin-bottom: 0;
`;
export default ({ msg }) =>
export default ({ msg }) => (
<Container>
<Loader />
<Msg>
{msg || 'Loading...'}
</Msg>
</Container>;
<Msg>{msg || 'Loading...'}</Msg>
</Container>
);

View File

@ -7,13 +7,15 @@ const StyledHeading = styled(ModalHeading)`
color: ${props => props.theme.red};
`;
const ModalErrorMessage = ({ title, message, onCloseClick }) =>
const ModalErrorMessage = ({ title, message, onCloseClick }) => (
<div>
<StyledHeading>{title}</StyledHeading>
<ModalText marginBottom="3">{message}
</ModalText>
<Button onClick={onCloseClick} secondary>Close </Button>
</div>;
<ModalText marginBottom="3">{message}</ModalText>
<Button onClick={onCloseClick} secondary>
Close{' '}
</Button>
</div>
);
ModalErrorMessage.propTypes = {
title: PropTypes.string,

View File

@ -2,8 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Message } from 'joyent-ui-toolkit';
const WarningMessage = ({ title, message }) =>
<Message title={title} message={message} type="WARNING" />;
const WarningMessage = ({ title, message }) => (
<Message title={title} message={message} type="WARNING" />
);
WarningMessage.propTypes = {
title: PropTypes.string,

View File

@ -24,27 +24,22 @@ const BreadcrumbContainer = styled.div`
const getBreadcrumbItems = (...links) =>
forceArray(links).map(({ pathname, name }, i) => {
const item =
i + 1 >= links.length
? name
: <BreadcrumbLink to={pathname}>
{name}
</BreadcrumbLink>;
i + 1 >= links.length ? (
name
) : (
<BreadcrumbLink to={pathname}>{name}</BreadcrumbLink>
);
return (
<BreadcrumbItem key={name}>
{item}
</BreadcrumbItem>
);
return <BreadcrumbItem key={name}>{item}</BreadcrumbItem>;
});
const NavBreadcrumb = ({ links = [] }) =>
const NavBreadcrumb = ({ links = [] }) => (
<BreadcrumbContainer>
<Grid>
<Breadcrumb>
{getBreadcrumbItems(...links)}
</Breadcrumb>
<Breadcrumb>{getBreadcrumbItems(...links)}</Breadcrumb>
</Grid>
</BreadcrumbContainer>;
</BreadcrumbContainer>
);
NavBreadcrumb.propTypes = {
links: PropTypes.arrayOf(

View File

@ -12,20 +12,17 @@ const StyledLogo = Img.extend`
height: ${remcalc(25)};
`;
const NavHeader = ({ datacenter, username }) =>
const NavHeader = ({ datacenter, username }) => (
<Header>
<HeaderBrand>
<Link to="/">
<StyledLogo src={Logo} />
</Link>
</HeaderBrand>
<HeaderItem>
{datacenter}
</HeaderItem>
<HeaderItem>
{username}
</HeaderItem>
</Header>;
<HeaderItem>{datacenter}</HeaderItem>
<HeaderItem>{username}</HeaderItem>
</Header>
);
NavHeader.propTypes = {
datacenter: PropTypes.string,

View File

@ -11,20 +11,19 @@ import {
} from 'joyent-ui-toolkit';
const getMenuItems = (...links) =>
forceArray(links).map(({ pathname, name }) =>
forceArray(links).map(({ pathname, name }) => (
<SectionListItem key={pathname}>
<SectionListNavLink activeClassName="active" to={pathname}>
{name}
</SectionListNavLink>
</SectionListItem>
);
));
const Menu = ({ links = [] }) =>
const Menu = ({ links = [] }) => (
<LayoutContainer plain>
<SectionList>
{getMenuItems(...links)}
</SectionList>
</LayoutContainer>;
<SectionList>{getMenuItems(...links)}</SectionList>
</LayoutContainer>
);
Menu.propTypes = {
links: PropTypes.arrayOf(

View File

@ -39,6 +39,6 @@ NotFound.propTypes = {
message: PropTypes.string,
link: PropTypes.string,
to: PropTypes.string
}
};
export default NotFound;

View File

@ -6,7 +6,7 @@ const ServiceDelete = ({
service,
onCancelClick = () => {},
onConfirmClick = () => {}
}) =>
}) => (
<div>
<ModalHeading>
Deleting a service: <br /> {service.name}
@ -19,7 +19,8 @@ const ServiceDelete = ({
Cancel
</Button>
<Button onClick={onConfirmClick}>Delete service</Button>
</div>;
</div>
);
ServiceDelete.propTypes = {
service: PropTypes.object.isRequired,

View File

@ -1,3 +1,3 @@
export { default as ServiceScale } from './scale';
export { default as ServiceDelete } from './delete';
export { default as ServiceMetrics} from './metrics';
export { default as ServiceMetrics } from './metrics';

View File

@ -2,13 +2,9 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { MetricGraph } from 'joyent-ui-toolkit';
const ServiceMetrics = ({
metricsData,
graphDurationSeconds
}) => {
const ServiceMetrics = ({ metricsData, graphDurationSeconds }) => {
// metricsData should prob be an array rather than an object
const metricGraphs = Object.keys(metricsData).map((key) => (
const metricGraphs = Object.keys(metricsData).map(key => (
// should also have a header, w metric name and number of instances (omit everything else from design for copilot)
<MetricGraph
key={key}
@ -17,19 +13,15 @@ const ServiceMetrics = ({
height={292}
graphDurationSeconds={graphDurationSeconds}
/>
))
));
// This needs layout!!!
return (
<div>
{metricGraphs}
</div>
)
}
return <div>{metricGraphs}</div>;
};
ServiceMetrics.propTypes = {
// metricsData should prob be an array rather than an object
metricsData: PropTypes.object.isRequired,
graphDurationSeconds: PropTypes.number.isRequired
}
};
export default ServiceMetrics;

View File

@ -15,7 +15,7 @@ const ServiceScale = ({
onCancelClick = () => {},
invalid,
pristine
}) =>
}) => (
<form onSubmit={handleSubmit}>
<ModalHeading>
Scaling a service: <br />
@ -38,7 +38,8 @@ const ServiceScale = ({
<Button type="submit" disabled={pristine || invalid} secondary>
Scale
</Button>
</form>;
</form>
);
ServiceScale.propTypes = {
service: PropTypes.object.isRequired,

View File

@ -16,7 +16,7 @@ const StyledBox = styled.div`
}
`;
export default () =>
export default () => (
<LayoutContainer>
<Row>
<Col>
@ -56,4 +56,5 @@ export default () =>
</Row>
</Col>
</Row>
</LayoutContainer>;
</LayoutContainer>
);

View File

@ -57,27 +57,27 @@ const ServiceListItem = ({
: service.instances.length;
const childrenItems = children.length
? children.map(service =>
<ServiceListItem
key={service.id}
deploymentGroup={deploymentGroup}
service={service}
isChild
/>
) : null;
? children.map(service => (
<ServiceListItem
key={service.id}
deploymentGroup={deploymentGroup}
service={service}
isChild
/>
))
: null;
const title = isChild
? <CardTitle>
{service.name}
</CardTitle>
: <CardTitle>
<TitleInnerContainer>
<StyledAnchor to={to} secondary active={service.instancesActive}>
{service.name}
</StyledAnchor>
</TitleInnerContainer>
</CardTitle>;
const title = isChild ? (
<CardTitle>{service.name}</CardTitle>
) : (
<CardTitle>
<TitleInnerContainer>
<StyledAnchor to={to} secondary active={service.instancesActive}>
{service.name}
</StyledAnchor>
</TitleInnerContainer>
</CardTitle>
);
const subtitle = (
<CardSubTitle>
@ -86,52 +86,47 @@ const ServiceListItem = ({
</CardSubTitle>
);
const header = !isChild
? <StyledCardHeader>
{title}
<CardDescription>
<CardInfo
icon={<InstancesIcon />}
iconPosition="left"
label={`${instancesCount} ${instancesCount > 1
? 'instances'
: 'instance'}`}
color={!service.instancesActive ? 'disabled' : 'light'}
/>
</CardDescription>
<CardOptions onClick={handleCardOptionsClick} />
</StyledCardHeader>
: null;
const header = !isChild ? (
<StyledCardHeader>
{title}
<CardDescription>
<CardInfo
icon={<InstancesIcon />}
iconPosition="left"
label={`${instancesCount} ${instancesCount > 1
? 'instances'
: 'instance'}`}
color={!service.instancesActive ? 'disabled' : 'light'}
/>
</CardDescription>
<CardOptions onClick={handleCardOptionsClick} />
</StyledCardHeader>
) : null;
let healthyInfo = null;
if(service.instancesActive) {
if (service.instancesActive) {
const { total, healthy } = service.instancesHealthy;
const iconHealthy = total === healthy ? 'HEALTHY' : 'NOT HEALTHY';
const icon = <HealthyIcon healthy={iconHealthy} />;
const label = `${healthy} of ${total} healthy`;
healthyInfo = (
<CardInfo
icon={icon}
iconPosition='left'
label={label}
color='dark'
/>
)
<CardInfo icon={icon} iconPosition="left" label={label} color="dark" />
);
}
const view = children.length
? <CardGroupView>
{childrenItems}
</CardGroupView>
: <CardView>
{isChild && title}
{isChild && subtitle}
<CardDescription>
<Status service={service} />
{healthyInfo}
</CardDescription>
</CardView>;
const view = children.length ? (
<CardGroupView>{childrenItems}</CardGroupView>
) : (
<CardView>
{isChild && title}
{isChild && subtitle}
<CardDescription>
<Status service={service} />
{healthyInfo}
</CardDescription>
</CardView>
);
return (
<Card

View File

@ -1,6 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tooltip, TooltipButton, TooltipDivider, TooltipList } from 'joyent-ui-toolkit';
import {
Tooltip,
TooltipButton,
TooltipDivider,
TooltipList
} from 'joyent-ui-toolkit';
const ServicesQuickActions = ({
show,
@ -11,7 +16,7 @@ const ServicesQuickActions = ({
onStopClick = () => {},
onStartClick = () => {},
onScaleClick = () => {},
onDeleteClick = () => {},
onDeleteClick = () => {}
}) => {
if (!show) {
return null;
@ -46,22 +51,22 @@ const ServicesQuickActions = ({
}, null);
const startService =
status === 'RUNNING'
? null
: <li>
<TooltipButton onClick={handleStartClick} disabled={disabled}>
Start
</TooltipButton>
</li>;
status === 'RUNNING' ? null : (
<li>
<TooltipButton onClick={handleStartClick} disabled={disabled}>
Start
</TooltipButton>
</li>
);
const stopService =
status === 'STOPPED'
? null
: <li>
<TooltipButton onClick={handleStopClick} disabled={disabled}>
Stop
</TooltipButton>
</li>;
status === 'STOPPED' ? null : (
<li>
<TooltipButton onClick={handleStopClick} disabled={disabled}>
Stop
</TooltipButton>
</li>
);
return (
<Tooltip {...position} onBlur={onBlur}>

View File

@ -37,16 +37,18 @@ const ServiceStatus = ({ service }) => {
);
});
return service.transitionalStatus
? <StyledStatusContainer>
<StatusLoader />
<StyledTransitionalStatus>
{service.status ? service.status.toLowerCase() : ''}
</StyledTransitionalStatus>
</StyledStatusContainer>
: <StyledStatusContainer>
{getInstanceStatuses(service.instanceStatuses)}
</StyledStatusContainer>;
return service.transitionalStatus ? (
<StyledStatusContainer>
<StatusLoader />
<StyledTransitionalStatus>
{service.status ? service.status.toLowerCase() : ''}
</StyledTransitionalStatus>
</StyledStatusContainer>
) : (
<StyledStatusContainer>
{getInstanceStatuses(service.instanceStatuses)}
</StyledStatusContainer>
);
};
ServiceStatus.propTypes = {

View File

@ -5,7 +5,7 @@ import DeploymentGroupDeleteMutation from '@graphql/DeploymentGroupDeleteMutatio
import DeploymentGroupQuery from '@graphql/DeploymentGroup.gql';
import { Loader, ModalErrorMessage } from '@components/messaging';
import { DeploymentGroupDelete as DeploymentGroupDeleteComponent } from '@components/deployment-group';
import { Modal } from 'joyent-ui-toolkit'
import { Modal } from 'joyent-ui-toolkit';
import { withNotFound, GqlPaths } from '@containers/navigation';
export class DeploymentGroupDelete extends Component {
@ -21,7 +21,10 @@ export class DeploymentGroupDelete extends Component {
const { history, match, loading, error } = this.props;
const handleCloseClick = evt => {
const closeUrl = match.url.split('/').slice(0, -2).join('/');
const closeUrl = match.url
.split('/')
.slice(0, -2)
.join('/');
history.replace(closeUrl);
};
@ -37,24 +40,21 @@ export class DeploymentGroupDelete extends Component {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
message='An error occurred while loading your deployment group.'
title="Ooops!"
message="An error occurred while loading your deployment group."
onCloseClick={handleCloseClick}
/>
</Modal>
);
}
const {
deploymentGroup,
deleteDeploymentGroup
} = this.props;
const { deploymentGroup, deleteDeploymentGroup } = this.props;
if (this.state.error) {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
title="Ooops!"
message={`An error occurred while attempting to delete the ${deploymentGroup.name} deployment group.`}
onCloseClick={handleCloseClick}
/>
@ -117,7 +117,7 @@ const DeploymentGroupGql = graphql(DeploymentGroupQuery, {
const DeploymentGroupDeleteWithData = compose(
DeleteDeploymentGroupGql,
DeploymentGroupGql,
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
)(DeploymentGroupDelete);
export default DeploymentGroupDeleteWithData;

View File

@ -5,9 +5,10 @@ import { Progress } from '@components/manifest/edit-or-create';
import { LayoutContainer } from '@components/layout';
import { Title } from '@components/navigation';
export default ({ match }) =>
export default ({ match }) => (
<LayoutContainer>
<Title>Creating deployment group</Title>
<Progress stage={match.params.stage} create />
<ManifestEditOrCreate create />
</LayoutContainer>;
</LayoutContainer>
);

View File

@ -140,20 +140,18 @@ export const DeploymentGroupList = ({
);
}
const groups = forceArray(deploymentGroups).map(({ slug, name }) =>
const groups = forceArray(deploymentGroups).map(({ slug, name }) => (
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
<Box>
<StyledLink to={`${match.path}/${slug}`}>
<ServiceTitle>
{name}
</ServiceTitle>
<ServiceTitle>{name}</ServiceTitle>
</StyledLink>
<StyledIconButton to={`${match.url}/${slug}/delete`}>
<BinIcon />
</StyledIconButton>
</Box>
</Col>
);
));
const create = [
<Col xs={12} sm={4} md={3} lg={3} key="~create">
@ -165,18 +163,16 @@ export const DeploymentGroupList = ({
</BoxCreate>
</Col>
].concat(
forceArray(importable).map(({ slug, name }) =>
forceArray(importable).map(({ slug, name }) => (
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
<BoxCreate>
<StyledCreateLink to={`${match.path}/~import/${slug}`}>
<Oval>&#10549;</Oval>
<CreateTitle>
{name}
</CreateTitle>
<CreateTitle>{name}</CreateTitle>
</StyledCreateLink>
</BoxCreate>
</Col>
)
))
);
return (
@ -218,5 +214,5 @@ export default compose(
importable: importableDeploymentGroups
})
}),
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
)(DeploymentGroupList);

View File

@ -20,7 +20,6 @@ export const InstanceList = ({
instancesTooltip,
toggleInstancesTooltip
}) => {
const _title = <Title>Instances</Title>;
if (loading && !forceArray(instances).length) {
@ -62,15 +61,12 @@ export const InstanceList = ({
};
const handleMouseOver = (evt, instance, type) => {
const label = evt.currentTarget;
const labelRect = label.getBoundingClientRect();
const offset = type === 'healthy'
? 48 : type === 'status' ? 36 : 0;
const offset = type === 'healthy' ? 48 : type === 'status' ? 36 : 0;
const position = {
left:
`${window.scrollX + labelRect.left + offset}px`,
left: `${window.scrollX + labelRect.left + offset}px`,
top: `${window.scrollY + labelRect.bottom}px`
};
@ -78,16 +74,16 @@ export const InstanceList = ({
instance,
position,
type
}
};
toggleInstancesTooltip(tooltipData);
};
const handleMouseOut = (evt) => {
const handleMouseOut = evt => {
toggleInstancesTooltip({ show: false });
};
const instanceList = instances.map((instance, index) =>
const instanceList = instances.map((instance, index) => (
<InstanceListItem
instance={instance}
key={instance.id}
@ -95,7 +91,7 @@ export const InstanceList = ({
onStatusMouseOver={handleStatusMouseOver}
onMouseOut={handleMouseOut}
/>
);
));
const _instances = !instanceList.length ? <EmptyInstances /> : instanceList;
@ -105,7 +101,7 @@ export const InstanceList = ({
{_instances}
</LayoutContainer>
);
}
};
const mapStateToProps = (state, ownProps) => ({
instancesTooltip: state.ui.instances.tooltip
@ -131,7 +127,7 @@ const InstanceListGql = graphql(InstancesQuery, {
}
};
},
props: ({ data: { deploymentGroup, loading, error }}) => ({
props: ({ data: { deploymentGroup, loading, error } }) => ({
deploymentGroup,
instances: sortBy(
forceArray(
@ -151,8 +147,5 @@ const InstanceListGql = graphql(InstancesQuery, {
export default compose(
UiConnect,
InstanceListGql,
withNotFound([
GqlPaths.DEPLOYMENT_GROUP,
GqlPaths.SERVICES
])
withNotFound([GqlPaths.DEPLOYMENT_GROUP, GqlPaths.SERVICES])
)(InstanceList);

View File

@ -12,37 +12,34 @@ const StyledContainer = styled.div`
const healthMessages = {
healthy: 'Your instance is operating as expected',
unhealthy: 'Your instance is not operating as expected',
maintenance: 'You\'ve set your instance to this manually, use the Container Pilot CLI to change',
unknown: 'We\'ve connected to your instance but we have no health information',
unavailable: 'We cannot connect to your instance',
maintenance:
"You've set your instance to this manually, use the Container Pilot CLI to change",
unknown: "We've connected to your instance but we have no health information",
unavailable: 'We cannot connect to your instance'
};
const statusMessages = {
running: 'Your instance is operating',
provisioning: 'Your instance is downloading dependencies and compiling',
ready: 'Your instance finished provisioning and is ready to be run, it\'ll be running soon',
ready:
"Your instance finished provisioning and is ready to be run, it'll be running soon",
stopping: 'Your instance is going to be stopped soon',
stopped: 'Your instance isn\'t doing anything, you can start it',
stopped: "Your instance isn't doing anything, you can start it",
offline: 'We have no idea what this means, do you??????',
failed: 'Your instance has crashed',
unknown: 'We cannot work out what status your instance is in',
unknown: 'We cannot work out what status your instance is in'
};
export const InstancesTooltip = ({
instancesTooltip
}) => {
export const InstancesTooltip = ({ instancesTooltip }) => {
if (instancesTooltip.show) {
const { type, instance } = instancesTooltip;
if(instancesTooltip.show) {
const {
type,
instance
} = instancesTooltip;
const message = type === 'healthy'
? healthMessages[instance.healthy.toLowerCase()]
: type === 'status'
? statusMessages[instance.status.toLowerCase()]
: '';
const message =
type === 'healthy'
? healthMessages[instance.healthy.toLowerCase()]
: type === 'status'
? statusMessages[instance.status.toLowerCase()]
: '';
return (
<StyledContainer>
@ -50,7 +47,7 @@ export const InstancesTooltip = ({
<TooltipLabel>{message}</TooltipLabel>
</Tooltip>
</StyledContainer>
)
);
}
return null;

View File

@ -175,7 +175,9 @@ class DeploymentGroupEditOrCreate extends Component {
name.replace(/^\$/, '')
);
const vars = uniq(names).map(name => `\n${name}=`).join('');
const vars = uniq(names)
.map(name => `\n${name}=`)
.join('');
return `# define your interpolatable variables here\n${vars}`;
}

View File

@ -47,12 +47,12 @@ const Manifest = ({
}
const _notice =
deploymentGroup && deploymentGroup.imported && !manifest
? <WarningMessage
title="Be aware"
message="Since this Deployment Group was imported, it doesn&#x27;t have the initial manifest."
/>
: null;
deploymentGroup && deploymentGroup.imported && !manifest ? (
<WarningMessage
title="Be aware"
message="Since this Deployment Group was imported, it doesn&#x27;t have the initial manifest."
/>
) : null;
return (
<LayoutContainer>

View File

@ -11,25 +11,16 @@ export const MetricNames = [
export const withServiceMetricsPolling = ({
pollingInterval = 1000 // in milliseconds
}) => {
return (WrappedComponent) => {
return WrappedComponent => {
return class extends Component {
componentDidMount() {
this._poll = setInterval(() => {
const {
loading,
error,
service,
fetchMoreMetrics
} = this.props;
const { loading, error, service, fetchMoreMetrics } = this.props;
if(!loading && !error && service) {
if (!loading && !error && service) {
const previousEnd = service.instances[0].metrics[0].end;
fetchMoreMetrics(previousEnd);
}
}, pollingInterval); // TODO this is the polling interval - think about amount is the todo I guess...
}
@ -38,24 +29,28 @@ export const withServiceMetricsPolling = ({
}
render() {
return <WrappedComponent {...this.props} />
return <WrappedComponent {...this.props} />;
}
}
}
}
};
};
};
export const withServiceMetricsGql = ({
gqlQuery,
graphDurationSeconds,
updateIntervalSeconds
}) => {
const getPreviousMetrics = (previousResult, serviceId, instanceId, metricName) => {
const getPreviousMetrics = (
previousResult,
serviceId,
instanceId,
metricName
) => {
return previousResult.deploymentGroup.services
.find(s => s.id === serviceId).instances
.find(i => i.id === instanceId).metrics
.find(m => m.name === metricName).metrics;
}
.find(s => s.id === serviceId)
.instances.find(i => i.id === instanceId)
.metrics.find(m => m.name === metricName).metrics;
};
const getNextResult = (previousResult, fetchNextResult) => {
const deploymentGroup = fetchNextResult.deploymentGroup;
@ -69,18 +64,18 @@ export const withServiceMetricsGql = ({
metrics: instance.metrics.map(metric => ({
...metric,
metrics: getPreviousMetrics(
previousResult,
service.id,
instance.id,
metric.name
).concat(metric.metrics)
previousResult,
service.id,
instance.id,
metric.name
).concat(metric.metrics)
}))
}))
}))
}
}
};
return nextResult;
}
};
return graphql(gqlQuery, {
options(props) {
@ -90,7 +85,10 @@ export const withServiceMetricsGql = ({
// this is potentially prone to overfetching if we already have data within timeframe and we leave the page then come back to it
const end = moment();
const start = moment(end).subtract(graphDurationSeconds + updateIntervalSeconds, 'seconds'); // TODO initial amount of data we wanna get - should be the same as what we display + 15 secs
const start = moment(end).subtract(
graphDurationSeconds + updateIntervalSeconds,
'seconds'
); // TODO initial amount of data we wanna get - should be the same as what we display + 15 secs
return {
variables: {
@ -102,27 +100,34 @@ export const withServiceMetricsGql = ({
}
};
},
props: ({ data: { deploymentGroup, loading, error, variables, fetchMore }}) => {
const fetchMoreMetrics = (previousEnd) => {
props: ({
data: { deploymentGroup, loading, error, variables, fetchMore }
}) => {
const fetchMoreMetrics = previousEnd => {
fetchMore({
variables: {
...variables,
start: previousEnd,
end: moment().utc().format()
end: moment()
.utc()
.format()
},
updateQuery: (previousResult, { fetchMoreResult, queryVariables }) => {
updateQuery: (
previousResult,
{ fetchMoreResult, queryVariables }
) => {
return getNextResult(previousResult, fetchMoreResult);
}
});
}
return ({
};
return {
deploymentGroup,
service: !loading && deploymentGroup ? deploymentGroup.services[0] : null,
service:
!loading && deploymentGroup ? deploymentGroup.services[0] : null,
loading,
error,
fetchMoreMetrics
})
};
}
});
}
};

View File

@ -9,8 +9,11 @@ import {
serviceBySlugSelector
} from '@root/state/selectors';
export const Breadcrumb = ({ deploymentGroup, service, location: { pathname }}) => {
export const Breadcrumb = ({
deploymentGroup,
service,
location: { pathname }
}) => {
const path = pathname.split('/');
const links = [
@ -41,7 +44,7 @@ Breadcrumb.propTypes = {
deploymentGroup: PropTypes.object,
service: PropTypes.object,
location: PropTypes.object
}
};
const connectBreadcrumb = connect(
(state, ownProps) => {
@ -59,7 +62,4 @@ const connectBreadcrumb = connect(
dispatch => ({})
);
export default compose(
connectBreadcrumb,
withNotFound()
)(Breadcrumb);
export default compose(connectBreadcrumb, withNotFound())(Breadcrumb);

View File

@ -5,8 +5,9 @@ import get from 'lodash.get';
import PortalQuery from '@graphql/Portal.gql';
import { Header as HeaderComponent } from '@components/navigation';
export const Header = ({ datacenter, username }) =>
<HeaderComponent datacenter={datacenter} username={username} />;
export const Header = ({ datacenter, username }) => (
<HeaderComponent datacenter={datacenter} username={username} />
);
const HeaderWithData = graphql(PortalQuery, {
props: ({ data: { portal = {} } }) => ({

View File

@ -5,7 +5,6 @@ import withNotFound from './not-found-hoc';
import { Menu as MenuComponent } from '@components/navigation';
export const Menu = ({ location, match, sections }) => {
if (!sections || !sections.length) {
return null;
}
@ -40,7 +39,4 @@ const connectMenu = connect(
dispatch => ({})
);
export default compose(
connectMenu,
withNotFound()
)(Menu);
export default compose(connectMenu, withNotFound())(Menu);

View File

@ -4,31 +4,24 @@ import { NotFound } from '@components/navigation';
export const GqlPaths = {
DEPLOYMENT_GROUP: 'deploymentGroup',
SERVICES: 'services'
}
export default (paths) => {
return (WrappedComponent) => {
};
export default paths => {
return WrappedComponent => {
return class extends Component {
componentWillReceiveProps(nextProps) {
if(paths) {
const {
error,
location,
history
} = nextProps;
if (paths) {
const { error, location, history } = nextProps;
if (
error
&& (!location.state || !location.state.notFound)
&& (error.graphQLErrors && error.graphQLErrors.length)
error &&
(!location.state || !location.state.notFound) &&
(error.graphQLErrors && error.graphQLErrors.length)
) {
const graphQLError = error.graphQLErrors[0];
if(graphQLError.message === 'Not Found') {
if (graphQLError.message === 'Not Found') {
const notFound = graphQLError.path.pop();
if(paths.indexOf(notFound) > -1) {
if (paths.indexOf(notFound) > -1) {
history.replace(location.pathname, { notFound });
}
}
@ -37,25 +30,22 @@ export default (paths) => {
}
render() {
const { error, location, match } = this.props;
const {
error,
location,
match
} = this.props;
if(location.state && location.state.notFound) {
if (location.state && location.state.notFound) {
const notFound = location.state.notFound;
if(paths && paths.indexOf(notFound) > -1) {
if (paths && paths.indexOf(notFound) > -1) {
let title;
let to;
let link;
if(notFound === 'services' || notFound === 'service') {
if (notFound === 'services' || notFound === 'service') {
title = 'This service doesnt exist';
to = match.url.split('/').slice(0, 3).join('/');
to = match.url
.split('/')
.slice(0, 3)
.join('/');
link = 'Back to services';
}
else if(notFound === 'deploymentGroup') {
} else if (notFound === 'deploymentGroup') {
title = 'This deployment group doesnt exist';
to = '/deployment-group';
link = 'Back to dashboard';
@ -63,17 +53,17 @@ export default (paths) => {
return (
<NotFound
title={title}
message='Sorry, but our princess is in another castle.'
message="Sorry, but our princess is in another castle."
to={to}
link={link}
/>
)
);
}
return null;
}
return <WrappedComponent {...this.props} />
return <WrappedComponent {...this.props} />;
}
}
}
}
};
};
};

View File

@ -21,7 +21,10 @@ export class ServiceDelete extends Component {
const { loading, error, match, history } = this.props;
const handleCloseClick = evt => {
const closeUrl = match.url.split('/').slice(0, -2).join('/');
const closeUrl = match.url
.split('/')
.slice(0, -2)
.join('/');
history.replace(closeUrl);
};
@ -37,8 +40,8 @@ export class ServiceDelete extends Component {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
message='An error occurred while loading your service.'
title="Ooops!"
message="An error occurred while loading your service."
onCloseClick={handleCloseClick}
/>
</Modal>
@ -51,7 +54,7 @@ export class ServiceDelete extends Component {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
title="Ooops!"
message={`An error occurred while attempting to delete your ${service.name} service.`}
onCloseClick={handleCloseClick}
/>
@ -60,9 +63,11 @@ export class ServiceDelete extends Component {
}
const handleConfirmClick = evt => {
deleteServices(service.id).then(() => handleCloseClick()).catch(err => {
this.setState({ error: err });
});
deleteServices(service.id)
.then(() => handleCloseClick())
.catch(err => {
this.setState({ error: err });
});
};
return (
@ -98,5 +103,5 @@ const DeleteServicesGql = graphql(ServicesDeleteMutation, {
export default compose(
DeleteServicesGql,
ServiceGql,
withNotFound([ GqlPaths.SERVICES ])
withNotFound([GqlPaths.SERVICES])
)(ServiceDelete);

View File

@ -10,17 +10,16 @@ import { ServiceMetrics as ServiceMetricsComponent } from '@components/service';
import { Button } from 'joyent-ui-toolkit';
import { Loader, ErrorMessage } from '@components/messaging';
import { withServiceMetricsPolling, withServiceMetricsGql } from '@containers/metrics';
import {
withServiceMetricsPolling,
withServiceMetricsGql
} from '@containers/metrics';
// 'width' of graph, i.e. total duration of time it'll display and truncate data to
// amount of data we'll need to initially fetch
const GraphDurationSeconds = 90;
const ServiceMetrics = ({
service,
loading,
error
}) => {
const ServiceMetrics = ({ service, loading, error }) => {
if (loading || !service) {
return (
<LayoutContainer center>
@ -43,8 +42,8 @@ const ServiceMetrics = ({
// metricsData should prob be an array rather than an object
const metricsData = service.instances.reduce((metrics, instance) => {
// gather metrics of instances according to type
instance.metrics.forEach((instanceMetrics) => {
if(!metrics[instanceMetrics.name]) {
instance.metrics.forEach(instanceMetrics => {
if (!metrics[instanceMetrics.name]) {
metrics[instanceMetrics.name] = [];
}
metrics[instanceMetrics.name].push(instanceMetrics);
@ -69,10 +68,7 @@ export default compose(
updateIntervalSeconds: 15
}),
withServiceMetricsPolling({ pollingInterval: 1000 }),
withNotFound([
GqlPaths.DEPLOYMENT_GROUP,
GqlPaths.SERVICES
])
withNotFound([GqlPaths.DEPLOYMENT_GROUP, GqlPaths.SERVICES])
)(ServiceMetrics);
/*

View File

@ -22,7 +22,10 @@ export class ServiceScale extends Component {
const { loading, error, match, history } = this.props;
const handleCloseClick = evt => {
const closeUrl = match.url.split('/').slice(0, -2).join('/');
const closeUrl = match.url
.split('/')
.slice(0, -2)
.join('/');
history.replace(closeUrl);
};
@ -38,8 +41,8 @@ export class ServiceScale extends Component {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
message='An error occurred while loading your service.'
title="Ooops!"
message="An error occurred while loading your service."
onCloseClick={handleCloseClick}
/>
</Modal>
@ -52,7 +55,7 @@ export class ServiceScale extends Component {
return (
<Modal width={460} onCloseClick={handleCloseClick}>
<ModalErrorMessage
title='Ooops!'
title="Ooops!"
message={`An error occurred while attempting to scale your ${service.name} service.`}
onCloseClick={handleCloseClick}
/>
@ -70,9 +73,11 @@ export class ServiceScale extends Component {
};
const handleSubmitClick = values => {
scale(service.id, values.replicas).then(handleCloseClick).catch(err => {
this.setState({ error: err });
});
scale(service.id, values.replicas)
.then(handleCloseClick)
.catch(err => {
this.setState({ error: err });
});
};
if (!service) {
@ -126,5 +131,5 @@ const ServiceScaleGql = graphql(ServiceScaleMutation, {
export default compose(
ServiceScaleGql,
ServiceGql,
withNotFound([ GqlPaths.SERVICES ])
withNotFound([GqlPaths.SERVICES])
)(ServiceScale);

View File

@ -34,7 +34,7 @@ export class ServiceList extends Component {
services,
loading,
error,
toggleServicesQuickActions,
toggleServicesQuickActions
} = this.props;
if (loading && !forceArray(services).length) {
@ -73,8 +73,9 @@ export class ServiceList extends Component {
const buttonRect = button.getBoundingClientRect();
const position = {
left:
`${buttonRect.left + window.scrollX + (buttonRect.right - buttonRect.left) / 2}px`,
left: `${buttonRect.left +
window.scrollX +
(buttonRect.right - buttonRect.left) / 2}px`,
top: `${buttonRect.bottom + window.scrollY}px`
};
@ -120,9 +121,7 @@ export class ServiceList extends Component {
return (
<LayoutContainer>
{renderedError}
<StyledContainer>
{serviceList}
</StyledContainer>
<StyledContainer>{serviceList}</StyledContainer>
</LayoutContainer>
);
}
@ -134,7 +133,7 @@ ServiceList.propTypes = {
loading: PropTypes.bool,
error: PropTypes.bool,
toggleServicesQuickActions: PropTypes.func
}
};
const mapStateToProps = (state, ownProps) => ({});
@ -153,7 +152,7 @@ const ServicesGql = graphql(ServicesQuery, {
}
};
},
props: ({ data: { deploymentGroup, loading, error }}) => ({
props: ({ data: { deploymentGroup, loading, error } }) => ({
deploymentGroup,
services: deploymentGroup
? processServices(deploymentGroup.services, null)
@ -166,7 +165,7 @@ const ServicesGql = graphql(ServicesQuery, {
const ServiceListWithData = compose(
ServicesGql,
UiConnect,
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
)(ServiceList);
export default ServiceListWithData;

View File

@ -20,11 +20,8 @@ const PaddedRow = Row.extend`
margin-bottom: ${remcalc(18)}
`;
export const ServicesMenu = ({
location: { pathname },
history: { push }
}) => {
export const ServicesMenu = ({ location: { pathname }, history: { push } }) => {
const toggleValue = pathname.split('-').pop();
const handleToggle = evt => {

View File

@ -17,13 +17,12 @@ const StyledContainer = styled.div`
`;
export class ServicesQuickActions extends Component {
constructor(props) {
super(props);
this.state = {
errors: {}
}
};
}
render() {
@ -53,20 +52,20 @@ export class ServicesQuickActions extends Component {
? 'An error occurred while attempting to restart your service.'
: '';
errorMessage = (
errorMessage = (
<LayoutContainer>
<ErrorMessage title="Ooops!" message={message} />
</LayoutContainer>
);
}
if(servicesQuickActions.show) {
if (servicesQuickActions.show) {
const handleTooltipBlur = evt => {
toggleServicesQuickActions({ show: false });
};
const handleRestartClick = (evt, service) => {
this.setState({errors: {}});
this.setState({ errors: {} });
toggleServicesQuickActions({ show: false });
restartServices(service.id).catch(err => {
this.setState({ errors: { restart: err } });
@ -74,7 +73,7 @@ export class ServicesQuickActions extends Component {
};
const handleStopClick = (evt, service) => {
this.setState({errors: {}});
this.setState({ errors: {} });
toggleServicesQuickActions({ show: false });
stopServices(service.id).catch(err => {
this.setState({ errors: { stop: err } });
@ -82,7 +81,7 @@ export class ServicesQuickActions extends Component {
};
const handleStartClick = (evt, service) => {
this.setState({errors: {}});
this.setState({ errors: {} });
toggleServicesQuickActions({ show: false });
startServices(service.id).catch(err => {
this.setState({ errors: { start: err } });
@ -90,13 +89,13 @@ export class ServicesQuickActions extends Component {
};
const handleScaleClick = (evt, service) => {
this.setState({errors: {}});
this.setState({ errors: {} });
toggleServicesQuickActions({ show: false });
push(`${url}/${service.slug}/scale`);
};
const handleDeleteClick = (evt, service) => {
this.setState({errors: {}});
this.setState({ errors: {} });
toggleServicesQuickActions({ show: false });
push(`${url}/${service.slug}/delete`);
};
@ -115,16 +114,16 @@ export class ServicesQuickActions extends Component {
onDeleteClick={handleDeleteClick}
/>
</StyledContainer>
)
);
}
if(quickActions || errorMessage) {
if (quickActions || errorMessage) {
return (
<div>
{errorMessage}
{quickActions}
</div>
)
);
}
return null;

View File

@ -47,7 +47,7 @@ export class ServicesTopology extends Component {
services,
loading,
error,
toggleServicesQuickActions,
toggleServicesQuickActions
} = this.props;
if (loading && !forceArray(services).length) {
@ -85,18 +85,27 @@ export class ServicesTopology extends Component {
const container = this._refs.container;
const containerRect = container.getBoundingClientRect();
const position = {
top: `${containerRect.top + window.scrollY + tooltipData.position.top}px`,
left: `${containerRect.left + window.scrollX + tooltipData.position.left}px`
}
top: `${containerRect.top +
window.scrollY +
tooltipData.position.top}px`,
left: `${containerRect.left +
window.scrollX +
tooltipData.position.left}px`
};
const data = {
...tooltipData,
position
}
};
toggleServicesQuickActions(data);
};
const handleNodeTitleClick = (evt, { service }) => {
push(`${url.split('/').slice(0, 3).join('/')}/services/${service.slug}`);
push(
`${url
.split('/')
.slice(0, 3)
.join('/')}/services/${service.slug}`
);
};
let renderedError = null;
@ -173,7 +182,7 @@ const ServicesGql = graphql(ServicesQuery, {
const ServicesTopologyWithData = compose(
ServicesGql,
UiConnect,
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
)(ServicesTopology);
export default ServicesTopologyWithData;

View File

@ -1,8 +1,8 @@
query Instances(
$deploymentGroupSlug: String!,
$serviceSlug: String!,
$metricNames: [MetricName]!,
$start: String!,
$deploymentGroupSlug: String!
$serviceSlug: String!
$metricNames: [MetricName]!
$start: String!
$end: String!
) {
deploymentGroup(slug: $deploymentGroupSlug) {

View File

@ -25,10 +25,7 @@ import {
ServiceMetrics
} from '@containers/service';
import {
InstanceList,
InstancesTooltip
} from '@containers/instances';
import { InstanceList, InstancesTooltip } from '@containers/instances';
import { DeploymentGroupDelete } from '@containers/deployment-group';
@ -43,23 +40,27 @@ const Container = styled.div`
const rootRedirect = p => <Redirect to="/deployment-groups" />;
const servicesListRedirect = p =>
const servicesListRedirect = p => (
<Redirect
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`}
/>;
/>
);
const servicesTopologyRedirect = p =>
const servicesTopologyRedirect = p => (
<Redirect
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-topology`}
/>;
to={`/deployment-groups/${p.match.params
.deploymentGroup}/services-topology`}
/>
);
const serviceRedirect = p =>
const serviceRedirect = p => (
<Redirect
to={`/deployment-groups/${p.match.params.deploymentGroup}/services/${p.match
.params.service}/instances`}
/>;
/>
);
const App = p =>
const App = p => (
<div>
<Switch>
<Route
@ -222,7 +223,8 @@ const App = p =>
component={servicesTopologyRedirect}
/>
</Switch>
</div>;
</div>
);
const Router = (
<BrowserRouter>

View File

@ -1,5 +1,8 @@
import { handleActions } from 'redux-actions';
import { toggleServicesQuickActions, toggleInstancesTooltip } from '@state/actions';
import {
toggleServicesQuickActions,
toggleInstancesTooltip
} from '@state/actions';
export const _toggleServicesQuickActions = (state, action) => {
const { position, service, show } = action.payload;

View File

@ -104,10 +104,10 @@ const getInstancesHealthy = instances => {
return instances.reduce(
(healthy, instance) => ({
total: healthy.total + 1,
healthy: instance.healthy === 'HEALTHY' ?
healthy.healthy + 1 : healthy.healthy
healthy:
instance.healthy === 'HEALTHY' ? healthy.healthy + 1 : healthy.healthy
}),
{total: 0, healthy: 0}
{ total: 0, healthy: 0 }
);
};
@ -174,6 +174,8 @@ const processServicesForTopology = services => {
}));
};
/* ,
instancesByServiceId */
export {
deploymentGroupBySlug as deploymentGroupBySlugSelector,
serviceBySlug as serviceBySlugSelector,
@ -182,6 +184,5 @@ export {
getInstancesHealthy,
getService,
processServices,
processServicesForTopology /* ,
instancesByServiceId */
processServicesForTopology
};

View File

@ -30,8 +30,11 @@ export const client = new ApolloClient({
? o.timestamp
: o.name && o.instance
? `${o.name}-${o.instance}`
: o.name ? o.name : o.time && o.value
? `${o.time}-${o.value}` : 'apollo-cache-key-not-defined';
: o.name
? o.name
: o.time && o.value
? `${o.time}-${o.value}`
: 'apollo-cache-key-not-defined';
return `${o.__typename}:${id}`;
},
networkInterface: createNetworkInterface({

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -12,9 +11,7 @@ import { deploymentGroup } from '../../mocks';
it('renders <DeploymentGroupDelete /> without throwing', () => {
const tree = renderer
.create(
<DeploymentGroupDelete deploymentGroup={deploymentGroup} />
)
.create(<DeploymentGroupDelete deploymentGroup={deploymentGroup} />)
.toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -10,10 +9,6 @@ import 'jest-styled-components';
import EmtpyInstances from '@components/instances/empty.js';
it('renders <EmtpyInstances /> without throwing', () => {
const tree = renderer
.create(
<EmtpyInstances />
)
.toJSON();
const tree = renderer.create(<EmtpyInstances />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -11,10 +10,6 @@ import InstanceCard from '@components/instances/list-item.js';
import { instance } from '../../mocks';
it('renders <InstanceCard /> without throwing', () => {
const tree = renderer
.create(
<InstanceCard instance={instance} />
)
.toJSON();
const tree = renderer.create(<InstanceCard instance={instance} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -9,10 +9,6 @@ import 'jest-styled-components';
import Container from '@components/layout/container';
it('renders <Container /> without throwing', () => {
const tree = renderer
.create(
<Container />
)
.toJSON();
const tree = renderer.create(<Container />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -9,10 +9,6 @@ import 'jest-styled-components';
import Error from '@components/messaging/error';
it('renders <Error /> without throwing', () => {
const tree = renderer
.create(
<Error />
)
.toJSON();
const tree = renderer.create(<Error />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -9,10 +9,6 @@ import 'jest-styled-components';
import Loader from '@components/messaging/loader';
it('renders <Loader /> without throwing', () => {
const tree = renderer
.create(
<Loader />
)
.toJSON();
const tree = renderer.create(<Loader />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -11,7 +11,7 @@ import ModalError from '@components/messaging/modal-error';
it('renders <ModalError /> without throwing', () => {
const tree = renderer
.create(
<ModalError message='Modal error message' onCloseClick={() => {}}/>
<ModalError message="Modal error message" onCloseClick={() => {}} />
)
.toJSON();
expect(tree).toMatchSnapshot();

View File

@ -9,10 +9,6 @@ import 'jest-styled-components';
import Warning from '@components/messaging/warning';
it('renders <Warning /> without throwing', () => {
const tree = renderer
.create(
<Warning message='Warning message'/>
)
.toJSON();
const tree = renderer.create(<Warning message="Warning message" />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -9,10 +9,6 @@ import 'jest-styled-components';
import Title from '@components/navigation/title';
it('renders <Title /> without throwing', () => {
const tree = renderer
.create(
<Title />
)
.toJSON();
const tree = renderer.create(<Title />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -10,10 +10,6 @@ import { service } from '../../mocks';
import Delete from '@components/service/delete';
it('renders <Delete /> without throwing', () => {
const tree = renderer
.create(
<Delete service={service} />
)
.toJSON();
const tree = renderer.create(<Delete service={service} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -23,9 +22,7 @@ it('renders <ServiceListItem /> without throwing', () => {
it('renders child <ServiceListItem /> without throwing', () => {
const tree = renderer
.create(
<ServiceListItem service={service} isChild />
)
.create(<ServiceListItem service={service} isChild />)
.toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -12,9 +11,7 @@ import { service } from '../../mocks';
xit('renders <ServiceStatus /> without throwing', () => {
const tree = renderer
.create(
<ServiceStatus instanceStatuses={service.instanceStatuses} />
)
.create(<ServiceStatus instanceStatuses={service.instanceStatuses} />)
.toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -17,12 +16,12 @@ it('renders <DeploymentGroupCreate /> without throwing', () => {
stage: ''
}
}
}
};
const tree = renderer
.create(
<Store>
<Router>
<DeploymentGroupCreate { ...props } />
<DeploymentGroupCreate {...props} />
</Router>
</Store>
)

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -15,12 +14,12 @@ it('renders <Breadcrumb /> without throwing', () => {
location: {
pathname: ''
}
}
};
const tree = renderer
.create(
<Store>
<Router>
<Breadcrumb { ...props } />
<Breadcrumb {...props} />
</Router>
</Store>
)

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -15,10 +14,7 @@ it('renders <ServiceList /> without throwing', () => {
.create(
<Store>
<Router>
<ServiceList
deploymentGroup={deploymentGroup}
services={services}
/>
<ServiceList deploymentGroup={deploymentGroup} services={services} />
</Router>
</Store>
)

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -18,12 +17,12 @@ it('renders <ServicesMenu /> without throwing', () => {
history: {
push: () => {}
}
}
};
const tree = renderer
.create(
<Store>
<Router>
<ServicesMenu { ...props } />
<ServicesMenu {...props} />
</Router>
</Store>
)

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/

View File

@ -1,4 +1,3 @@
/**
* @jest-environment jsdom
*/
@ -15,9 +14,7 @@ it('renders <ServicesTopology /> without throwing', () => {
.create(
<Store>
<Router>
<ServicesTopology
services={services}
/>
<ServicesTopology services={services} />
</Router>
</Store>
)

View File

@ -1,37 +1,31 @@
export const instance = {
"id": "309ecd9f-ac03-474b-aff7-4bd2e743296c",
"name": "wordpress_01",
"serviceId": "be227788-74f1-4e5b-a85f-b5c71cbae8d8",
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"machineId": "011f7479-2d45-442d-99bf-7f6216954cc8",
"status": "RUNNING",
"healthy": "HEALTHY"
id: '309ecd9f-ac03-474b-aff7-4bd2e743296c',
name: 'wordpress_01',
serviceId: 'be227788-74f1-4e5b-a85f-b5c71cbae8d8',
deploymentGroupId: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
machineId: '011f7479-2d45-442d-99bf-7f6216954cc8',
status: 'RUNNING',
healthy: 'HEALTHY'
};
export const service = {
"id": "081a792c-47e0-4439-924b-2efa9788ae9e",
"slug": "nginx",
"name": "Nginx",
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"connections": ["be227788-74f1-4e5b-a85f-b5c71cbae8d8"],
"instances": [instance],
"instanceStatuses": [{ status: "RUNNING", count: 1 }]
id: '081a792c-47e0-4439-924b-2efa9788ae9e',
slug: 'nginx',
name: 'Nginx',
deploymentGroupId: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
connections: ['be227788-74f1-4e5b-a85f-b5c71cbae8d8'],
instances: [instance],
instanceStatuses: [{ status: 'RUNNING', count: 1 }]
};
export const deploymentGroup = {
"id": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"slug": "wordpress-blog-example",
"name": "Wordpress Blog Example"
id: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
slug: 'wordpress-blog-example',
name: 'Wordpress Blog Example'
};
export const services = [
service
];
export const services = [service];
export const instances = [
instance
];
export const instances = [instance];
export const deploymentGroups = [
deploymentGroup
]
export const deploymentGroups = [deploymentGroup];

View File

@ -1,7 +1,4 @@
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
export default ({ children }) =>
<MemoryRouter>
{children}
</MemoryRouter>;
export default ({ children }) => <MemoryRouter>{children}</MemoryRouter>;

View File

@ -2,7 +2,8 @@ import React from 'react';
import { client, store } from '@state/store';
import { ApolloProvider } from 'react-apollo';
export default ({ children }) =>
export default ({ children }) => (
<ApolloProvider client={client} store={store}>
{children}
</ApolloProvider>;
</ApolloProvider>
);

View File

@ -2,7 +2,6 @@ import React from 'react';
import { ThemeProvider } from 'styled-components';
import { theme } from 'joyent-ui-toolkit';
export default ({ children }) =>
<ThemeProvider theme={theme}>
{children}
</ThemeProvider>;
export default ({ children }) => (
<ThemeProvider theme={theme}>{children}</ThemeProvider>
);

View File

@ -5,7 +5,6 @@ import {
import state from '@state/state';
describe('ui reducer', () => {
it('toggleServicesQuickActions shows correctly', () => {
const uiState = state.ui;
const expectedUiState = {
@ -23,17 +22,19 @@ describe('ui reducer', () => {
}
}
}
}
const action = { payload: {
show: true,
position: {
top: 10,
left: 10
},
service: {
id: 'service-id'
};
const action = {
payload: {
show: true,
position: {
top: 10,
left: 10
},
service: {
id: 'service-id'
}
}
}};
};
const result = _toggleServicesQuickActions(uiState, action);
expect(result).toEqual(expectedUiState);
});
@ -48,8 +49,8 @@ describe('ui reducer', () => {
show: false
}
}
}
const action = { payload: { show: false }};
};
const action = { payload: { show: false } };
const result = _toggleServicesQuickActions(uiState, action);
expect(result).toEqual(expectedUiState);
});
@ -72,18 +73,20 @@ describe('ui reducer', () => {
type: 'healthy'
}
}
}
const action = { payload: {
show: true,
position: {
top: 10,
left: 10
},
instance: {
id: 'instance-id'
},
type: 'healthy'
}};
};
const action = {
payload: {
show: true,
position: {
top: 10,
left: 10
},
instance: {
id: 'instance-id'
},
type: 'healthy'
}
};
const result = _toggleInstancesTooltip(uiState, action);
expect(result).toEqual(expectedUiState);
});
@ -98,9 +101,9 @@ describe('ui reducer', () => {
show: false
}
}
}
const action = { payload: { show: false }};
};
const action = { payload: { show: false } };
const result = _toggleInstancesTooltip(uiState, action);
expect(result).toEqual(expectedUiState);
});
})
});

View File

@ -10,48 +10,45 @@ import {
} from '@state/selectors';
describe('Redux selectors and Apollo helpers', () => {
describe('getInstanceStatuses', () => {
it('gathers instance statuses correctly', () => {
const service = {
instances: [
{ status: 'RUNNING' },
{ status: 'RUNNING' },
{ status: 'READY' },
{ status: 'RUNNING' },
{ status: 'INCOMPLETE' },
{ status: 'READY' },
{ status: 'OFFLINE' },
{ status: 'STOPPED' },
{ status: 'STOPPED' },
{ status: 'RUNNING' }
]
};
const expectedResult = [
{ status: 'RUNNING', count: 4 },
{ status: 'READY', count: 2 },
{ status: 'INCOMPLETE', count: 1 },
{ status: 'OFFLINE', count: 1 },
{ status: 'STOPPED', count: 2 }
];
const result = getInstanceStatuses(service);
expect(result).toEqual(expectedResult);
const service = {
instances: [
{ status: 'RUNNING' },
{ status: 'RUNNING' },
{ status: 'READY' },
{ status: 'RUNNING' },
{ status: 'INCOMPLETE' },
{ status: 'READY' },
{ status: 'OFFLINE' },
{ status: 'STOPPED' },
{ status: 'STOPPED' },
{ status: 'RUNNING' }
]
};
const expectedResult = [
{ status: 'RUNNING', count: 4 },
{ status: 'READY', count: 2 },
{ status: 'INCOMPLETE', count: 1 },
{ status: 'OFFLINE', count: 1 },
{ status: 'STOPPED', count: 2 }
];
const result = getInstanceStatuses(service);
expect(result).toEqual(expectedResult);
});
it('does not throw a hissy fit if there are no instances', () => {
const service = {
instances: []
};
const expectedResult = [];
const result = getInstanceStatuses(service);
expect(result).toEqual(expectedResult);
const service = {
instances: []
};
const expectedResult = [];
const result = getInstanceStatuses(service);
expect(result).toEqual(expectedResult);
});
});
describe('getInstancesActive', () => {
it('returns true if all instances\' status is active', () => {
it("returns true if all instances' status is active", () => {
const statuses = [
{ status: 'RUNNING' },
{ status: 'READY' },
@ -63,7 +60,7 @@ describe('Redux selectors and Apollo helpers', () => {
expect(result).toEqual(expectedResult);
});
it('returns false if no instances\' status is active', () => {
it("returns false if no instances' status is active", () => {
const statuses = [
{ status: 'STOPPING' },
{ status: 'FAILED' },
@ -75,7 +72,7 @@ describe('Redux selectors and Apollo helpers', () => {
expect(result).toEqual(expectedResult);
});
it('returns true if some instances\' status is active', () => {
it("returns true if some instances' status is active", () => {
const statuses = [
{ status: 'STOPPING' },
{ status: 'FAILED' },
@ -89,7 +86,6 @@ describe('Redux selectors and Apollo helpers', () => {
});
describe('getInstancesHealthy', () => {
it('returns the number of healthy instances correctly', () => {
const instances = [
{ healthy: 'HEALTHY' },
@ -106,39 +102,31 @@ describe('Redux selectors and Apollo helpers', () => {
});
describe('getService', () => {
it('returns the service decorated with details for display correctly', () => {
const result = getService(nginxService, 0);
expect(result).toEqual(nginxExpectedResult);
});
it('returns the consul service decorated with details for display correctly', () => {
const result = getService(consulService, 1);
expect(result).toEqual(consulExpectedResult);
});
});
describe('processServices', () => {
it('returns the services decorated with details for display correctly', () => {
const services = [
nginxService,
consulService
];
const expectedResult = [
nginxExpectedResult,
consulExpectedResult
];
const services = [nginxService, consulService];
const expectedResult = [nginxExpectedResult, consulExpectedResult];
const result = processServices(services);
expect(result).toEqual(expectedResult);
});
it('removes deleted services', () => {
const services = [{
status: 'DELETED'
}];
const services = [
{
status: 'DELETED'
}
];
const expectedResult = [];
const result = processServices(services);
expect(result).toEqual(expectedResult);
@ -146,16 +134,12 @@ describe('Redux selectors and Apollo helpers', () => {
});
describe('processServicesForTopology', () => {
it('returns the services decorated with details for display correctly', () => {
const services = [
{
...nginxService,
id: 'nginx-service-0',
connections: [
'consul-service-0',
'consul-service-1'
]
connections: ['consul-service-0', 'consul-service-1']
},
{
...nginxService,
@ -164,9 +148,7 @@ describe('Redux selectors and Apollo helpers', () => {
{
...consulService,
id: 'consul-service-0',
connections: [
'consul-service-1'
]
connections: ['consul-service-1']
},
{
...consulService,
@ -177,10 +159,7 @@ describe('Redux selectors and Apollo helpers', () => {
{
...nginxExpectedResult,
id: 'nginx-service-0',
connections: [
'consul-service-0',
'consul-service-1'
],
connections: ['consul-service-0', 'consul-service-1'],
connected: true,
index: 0
},
@ -193,9 +172,7 @@ describe('Redux selectors and Apollo helpers', () => {
{
...consulExpectedResult,
id: 'consul-service-0',
connections: [
'consul-service-1'
],
connections: ['consul-service-1'],
connected: true,
index: 2
},

View File

@ -48,12 +48,8 @@
"tap-xunit": "^1.7.0"
},
"ava": {
"files": [
"test/*.js"
],
"source": [
"src/*.js"
],
"files": ["test/*.js"],
"source": ["src/*.js"],
"failFast": true
}
}

View File

@ -268,8 +268,10 @@
},
{
"id": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"slug": "extra service reported by containerpilot: redbaloonservice-https",
"name": "Extra service reported by ContainerPilot: RedBaloonService-HTTPS",
"slug":
"extra service reported by containerpilot: redbaloonservice-https",
"name":
"Extra service reported by ContainerPilot: RedBaloonService-HTTPS",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"status": "ACTIVE"
},
@ -578,7 +580,8 @@
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
"machineId": "c9a49cff-4438-460f-bc46-610bfecbddca",
"name": "instance-Extra service reported by ContainerPilot: CartService-HTTPS-0"
"name":
"instance-Extra service reported by ContainerPilot: CartService-HTTPS-0"
},
{
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-1",
@ -587,7 +590,8 @@
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
"machineId": "4252ddb5-e9b4-4d1e-aa53-6e1bdcdeab30",
"name": "instance-Extra service reported by ContainerPilot: CartService-HTTPS-1"
"name":
"instance-Extra service reported by ContainerPilot: CartService-HTTPS-1"
},
{
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-2",
@ -596,7 +600,8 @@
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
"machineId": "783c5eb2-2145-4fd2-a22f-274bec3b2ffc",
"name": "instance-Extra service reported by ContainerPilot: CartService-HTTPS-2"
"name":
"instance-Extra service reported by ContainerPilot: CartService-HTTPS-2"
},
{
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-3",
@ -605,7 +610,8 @@
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
"machineId": "f8a54a11-93f4-4b0a-9c80-be6542393448",
"name": "instance-Extra service reported by ContainerPilot: CartService-HTTPS-3"
"name":
"instance-Extra service reported by ContainerPilot: CartService-HTTPS-3"
},
{
"id": "instance-3b954132-49fc-405c-9d91-c59b8953d7b8-0",
@ -1747,7 +1753,8 @@
"healthy": "UNKNOWN",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"name": "instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-0",
"name":
"instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-0",
"machineId": "20f5bf63-c7d7-4b80-bbe0-63dd744f1b72"
},
{
@ -1756,7 +1763,8 @@
"healthy": "UNKNOWN",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"name": "instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-1",
"name":
"instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-1",
"machineId": "bf10d972-17e0-4267-908e-4a8184d7c164"
},
{
@ -1765,7 +1773,8 @@
"healthy": "UNKNOWN",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"name": "instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-2",
"name":
"instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-2",
"machineId": "d7204a39-5005-4925-a2d5-02afbb2457db"
},
{
@ -1774,7 +1783,8 @@
"healthy": "UNKNOWN",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"name": "instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-3",
"name":
"instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-3",
"machineId": "80dac6f7-e459-4f42-b824-5abdd6f13d41"
},
{
@ -1783,7 +1793,8 @@
"healthy": "UNKNOWN",
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
"name": "instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-4",
"name":
"instance-Extra service reported by ContainerPilot: RedBaloonService-HTTPS-4",
"machineId": "dbb819d5-9df2-48e1-8412-7cd48ca4c186"
},
{

View File

@ -53,4 +53,4 @@
}
]
}
]
]

View File

@ -34466,4 +34466,4 @@
}
]
}
]
]

View File

@ -34490,4 +34490,4 @@
}
]
}
]
]

View File

@ -22993,4 +22993,4 @@
}
]
}
]
]

View File

@ -48,17 +48,11 @@ const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q));
let metricDataIndex = 0;
const getMetrics = query => {
const {
names,
start,
end,
instanceId
} = query;
const { names, start, end, instanceId } = query;
const metrics = names.reduce((metrics, name) => {
// pick one of the three metric data jsons, so there's variety
const index = metricDataIndex%metricData.length;
const index = metricDataIndex % metricData.length;
metricDataIndex++;
const md = metricData[index].find(md => md.name === name);
@ -69,17 +63,20 @@ const getMetrics = query => {
// how many records do we need?
const duration = e.diff(s); // duration for which we need data
const records = Math.floor(duration/15000); // new metric record every 15 secs
const records = Math.floor(duration / 15000); // new metric record every 15 secs
const requiredMetrics = [];
let i = 0;
const time = moment(s);
// start at a random point within the dataset for variety
const randomIndex = Math.round(Math.random() * m.length);
while(i < records) {
const index = (randomIndex + i)%m.length; // loop if not enough data
while (i < records) {
const index = (randomIndex + i) % m.length; // loop if not enough data
const requiredMetric = m[index];
requiredMetric.time = time.add(15, 'seconds').utc().format(); // we should have a new record every 15 secs
requiredMetric.time = time
.add(15, 'seconds')
.utc()
.format(); // we should have a new record every 15 secs
requiredMetrics.push(requiredMetric);
i++;
}
@ -90,13 +87,13 @@ const getMetrics = query => {
start: s.utc().format(),
end: time.utc().format(), // this will be used by the frontend for the next fetch
metrics: requiredMetrics
}
};
metrics.push(requiredMetricData);
return metrics;
}, []);
}, []);
return Promise.resolve(metrics);
}
};
const getInstances = query => {
const metricsResolver = ({ id }) => query =>
@ -175,13 +172,12 @@ const getServices = query => {
return ret;
});
return Promise.resolve(services)
.then((services) => {
if(!services || !services.length) {
throw Boom.notFound();
}
return services;
});
return Promise.resolve(services).then(services => {
if (!services || !services.length) {
throw Boom.notFound();
}
return services;
});
};
const getDeploymentGroups = query => {
@ -199,8 +195,8 @@ const getDeploymentGroups = query => {
return Promise.resolve(
deploymentGroups.filter(find(cleanQuery(query))).map(addNestedResolvers)
).then((deploymentGroups) => {
if(!deploymentGroups || !deploymentGroups.length) {
).then(deploymentGroups => {
if (!deploymentGroups || !deploymentGroups.length) {
throw Boom.notFound();
}
return deploymentGroups;
@ -406,11 +402,16 @@ const updateServiceAndInstancesStatus = (
instancesStatus
) => {
return Promise.all([
getServices({ id: serviceId })/* ,
getServices({
id: serviceId
}) /* ,
getServices({ parentId: serviceId }) */
])
.then(services => {
return services.reduce((services, service) => services.concat(service), [])
return services.reduce(
(services, service) => services.concat(service),
[]
);
})
.then(services => {
updateServiceStatus(services, serviceStatus);
@ -431,7 +432,9 @@ const updateServiceAndInstancesStatus = (
})
.then(() =>
Promise.all([
getUnfilteredServices({ id: serviceId })/* ,
getUnfilteredServices({
id: serviceId
}) /* ,
getUnfilteredServices({ parentId: serviceId }) */
])
)
@ -536,12 +539,7 @@ const parseEnvVars = (str = '') =>
const findEnvInterpolation = (str = '') =>
uniq(str.match(INTERPOLATE_REGEX).map(name => name.replace(/^\$/, '')));
const config = ({
environment = '',
files = [],
raw = '',
_plain = false
}) => {
const config = ({ environment = '', files = [], raw = '', _plain = false }) => {
const interpolatableNames = findEnvInterpolation(raw);
const interpolatableEnv = parseEnvVars(environment);
@ -588,11 +586,10 @@ const config = ({
config: Object.assign(service.config, {
id: hasha(JSON.stringify(service.config)),
environment: Object.keys(service.config.environment).map(name => ({
name,
id: hasha(JSON.stringify(service.config.environment[name])),
value: service.config.environment[name]
})
)
name,
id: hasha(JSON.stringify(service.config.environment[name])),
value: service.config.environment[name]
}))
})
})
);

View File

@ -203,7 +203,6 @@ type Datacenter {
region: String!
}
# we probably wont use some of these queries or arguments
# but this way we expose the entire db through gql
type Query {
@ -265,7 +264,13 @@ type Query {
): [Service]
importableDeploymentGroups: [DeploymentGroup]
# start and end should be .toISOString() date strings
metrics(deploymentGroupId: ID!, names: [MetricName]!, instances: [ID]!, start: String!, end: String!): [InstanceMetric]
metrics(
deploymentGroupId: ID!
names: [MetricName]!
instances: [ID]!
start: String!
end: String!
): [InstanceMetric]
}
type Mutation {

View File

@ -152,17 +152,17 @@ export const Button = styled.button`
appearance: button;
&::-moz-focus-inner,
&[type="button"]::-moz-focus-inner,
&[type="reset"]::-moz-focus-inner,
&[type="submit"]::-moz-focus-inner {
&[type='button']::-moz-focus-inner,
&[type='reset']::-moz-focus-inner,
&[type='submit']::-moz-focus-inner {
border-style: none;
padding: 0;
}
&:-moz-focusring,
&[type="button"]:-moz-focusring,
&[type="reset"]:-moz-focusring,
&[type="submit"]:-moz-focusring {
&[type='button']:-moz-focusring,
&[type='reset']:-moz-focusring,
&[type='submit']:-moz-focusring {
outline: ${remcalc(1)} dotted ButtonText;
}
`;
@ -174,24 +174,24 @@ export const Input = styled.input`
margin: 0;
overflow: visible;
&[type="checkbox"],
&[type="radio"] {
&[type='checkbox'],
&[type='radio'] {
box-sizing: border-box;
padding: 0;
}
&[type="number"]::-webkit-inner-spin-button,
&[type="number"]::-webkit-outer-spin-button {
&[type='number']::-webkit-inner-spin-button,
&[type='number']::-webkit-outer-spin-button {
height: auto;
}
&[type="search"] {
&[type='search'] {
appearance: textfield;
outline-offset: ${remcalc(-2)};
}
&[type="search"]::-webkit-search-cancel-button,
&[type="search"]::-webkit-search-decoration {
&[type='search']::-webkit-search-cancel-button,
&[type='search']::-webkit-search-decoration {
appearance: none;
}

View File

@ -36,11 +36,7 @@ const Anchor = ({ children, ...rest }) => {
const Views = [() => (to ? StyledLink : null), () => StyledAnchor];
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
return (
<View {...rest}>
{children}
</View>
);
return <View {...rest}>{children}</View>;
};
Anchor.propTypes = {

View File

@ -21,6 +21,6 @@ export default css`
margin: 0;
padding: 0;
background: ${theme.background};
font-family: 'Libre Franklin'
font-family: 'Libre Franklin';
}
`;

View File

@ -18,4 +18,6 @@ export default Component =>
? Component.extend`
${alignsFromProps};
`
: styled(Component)`${alignsFromProps}`;
: styled(Component)`
${alignsFromProps};
`;

View File

@ -33,4 +33,6 @@ export default Component =>
? Component.extend`
${unitsFromProps};
`
: styled(Component)`${unitsFromProps}`;
: styled(Component)`
${unitsFromProps};
`;

View File

@ -11,9 +11,9 @@ export const tooltipShadow = `0 ${remcalc(2)} ${remcalc(6)} ${remcalc(
export const modalShadow = `0 0 ${remcalc(6)} ${remcalc(1)} rgba(0, 0, 0, 0.1)`;
export const border = {
checked: css`${remcalc(1)} solid ${props => props.theme.primary}`,
unchecked: css`${remcalc(1)} solid ${props => props.theme.grey}`,
confirmed: css`${remcalc(1)} solid ${props => props.theme.grey}`,
error: css`${remcalc(1)} solid ${props => props.theme.red}`,
secondary: css`${remcalc(1)} solid ${props => props.theme.secondaryActive}`,
checked: css`${remcalc(1)} solid ${props => props.theme.primary};`,
unchecked: css`${remcalc(1)} solid ${props => props.theme.grey};`,
confirmed: css`${remcalc(1)} solid ${props => props.theme.grey};`,
error: css`${remcalc(1)} solid ${props => props.theme.red};`,
secondary: css`${remcalc(1)} solid ${props => props.theme.secondaryActive};`
};

View File

@ -4,9 +4,10 @@ import { Row } from 'react-styled-flexboxgrid';
/**
* @example ./usage.md
*/
export default ({ children, ...rest }) =>
export default ({ children, ...rest }) => (
<Row name="breadcrum" {...rest}>
{children}
</Row>;
</Row>
);
export { default as Item } from './item';

View File

@ -21,10 +21,11 @@ const Arrow = styled.div`
margin: ${remcalc(3)} ${remcalc(10)} ${remcalc(3)} ${remcalc(10)};
`;
export default ({ children, ...rest }) =>
export default ({ children, ...rest }) => (
<div>
<Name name="breadcrum-item" {...rest}>
{children}
</Name>
<Arrow />
</div>;
</div>
);

Some files were not shown because too many files have changed in this diff Show More