style: format
This commit is contained in:
parent
d1af5eec1a
commit
cac9453154
@ -16,11 +16,13 @@ module.exports = {
|
|||||||
const { list, get } = api.users;
|
const { list, get } = api.users;
|
||||||
|
|
||||||
return args.id
|
return args.id
|
||||||
? get(args).then(user => [user]).then(user =>
|
? get(args)
|
||||||
Object.assign(user, {
|
.then(user => [user])
|
||||||
isUser: true
|
.then(user =>
|
||||||
})
|
Object.assign(user, {
|
||||||
)
|
isUser: true
|
||||||
|
})
|
||||||
|
)
|
||||||
: list();
|
: list();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,9 +17,7 @@ class App extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ApolloProvider client={client} store={store}>
|
<ApolloProvider client={client} store={store}>
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>{Router}</ThemeProvider>
|
||||||
{Router}
|
|
||||||
</ThemeProvider>
|
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ const DeploymentGroupDelete = ({
|
|||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
onCancelClick = () => {},
|
onCancelClick = () => {},
|
||||||
onConfirmClick = () => {}
|
onConfirmClick = () => {}
|
||||||
}) =>
|
}) => (
|
||||||
<div>
|
<div>
|
||||||
<ModalHeading>
|
<ModalHeading>
|
||||||
Deleting a deployment group: <br /> {deploymentGroup.name}
|
Deleting a deployment group: <br /> {deploymentGroup.name}
|
||||||
@ -20,7 +20,8 @@ const DeploymentGroupDelete = ({
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onConfirmClick}>Delete deployment group</Button>
|
<Button onClick={onConfirmClick}>Delete deployment group</Button>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
DeploymentGroupDelete.propTypes = {
|
DeploymentGroupDelete.propTypes = {
|
||||||
deploymentGroup: PropTypes.object.isRequired,
|
deploymentGroup: PropTypes.object.isRequired,
|
||||||
|
@ -3,9 +3,10 @@ import React from 'react';
|
|||||||
import { Col, Row } from 'react-styled-flexboxgrid';
|
import { Col, Row } from 'react-styled-flexboxgrid';
|
||||||
import { P } from 'joyent-ui-toolkit';
|
import { P } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
export default () =>
|
export default () => (
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={12}>
|
<Col xs={12}>
|
||||||
<P>You don't have any instances</P>
|
<P>You don't have any instances</P>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>;
|
</Row>
|
||||||
|
);
|
||||||
|
@ -65,7 +65,16 @@ const StyledCard = Card.extend`
|
|||||||
|
|
||||||
background-color: ${props => props.theme.white};
|
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};
|
background-color: ${props => props.theme.background};
|
||||||
|
|
||||||
& [name="card-options"] > button {
|
& [name="card-options"] > button {
|
||||||
@ -80,7 +89,6 @@ const InstanceCard = ({
|
|||||||
onStatusMouseOver = () => {},
|
onStatusMouseOver = () => {},
|
||||||
onMouseOut = () => {}
|
onMouseOut = () => {}
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const statusProps = STATUSES.reduce(
|
const statusProps = STATUSES.reduce(
|
||||||
(acc, name) =>
|
(acc, name) =>
|
||||||
Object.assign(acc, {
|
Object.assign(acc, {
|
||||||
@ -92,42 +100,34 @@ const InstanceCard = ({
|
|||||||
const label = (instance.healthy || 'UNKNOWN').toLowerCase();
|
const label = (instance.healthy || 'UNKNOWN').toLowerCase();
|
||||||
const icon = <HealthyIcon healthy={instance.healthy} />;
|
const icon = <HealthyIcon healthy={instance.healthy} />;
|
||||||
|
|
||||||
const handleHealthMouseOver = (evt) => {
|
const handleHealthMouseOver = evt => {
|
||||||
onHealthMouseOver(evt, instance);
|
onHealthMouseOver(evt, instance);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleStatusMouseOver = (evt) => {
|
const handleStatusMouseOver = evt => {
|
||||||
onStatusMouseOver(evt, instance);
|
onStatusMouseOver(evt, instance);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMouseOut = (evt) => {
|
const handleMouseOut = evt => {
|
||||||
onMouseOut(evt);
|
onMouseOut(evt);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledCard collapsed={true} key={instance.uuid} {...statusProps}>
|
<StyledCard collapsed={true} key={instance.uuid} {...statusProps}>
|
||||||
<CardView>
|
<CardView>
|
||||||
<CardTitle>
|
<CardTitle>{instance.name}</CardTitle>
|
||||||
{instance.name}
|
|
||||||
</CardTitle>
|
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
<div
|
<div onMouseOver={handleHealthMouseOver} onMouseOut={handleMouseOut}>
|
||||||
onMouseOver={handleHealthMouseOver}
|
|
||||||
onMouseOut={handleMouseOut}
|
|
||||||
>
|
|
||||||
<CardInfo
|
<CardInfo
|
||||||
icon={icon}
|
icon={icon}
|
||||||
iconPosition='left'
|
iconPosition="left"
|
||||||
label={label}
|
label={label}
|
||||||
color='dark'
|
color="dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
<div
|
<div onMouseOver={handleStatusMouseOver} onMouseOut={handleMouseOut}>
|
||||||
onMouseOver={handleStatusMouseOver}
|
|
||||||
onMouseOut={handleMouseOut}
|
|
||||||
>
|
|
||||||
<Label>
|
<Label>
|
||||||
<Dot {...statusProps} />
|
<Dot {...statusProps} />
|
||||||
{titleCase(instance.status)}
|
{titleCase(instance.status)}
|
||||||
@ -136,7 +136,7 @@ const InstanceCard = ({
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardView>
|
</CardView>
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
InstanceCard.propTypes = {
|
InstanceCard.propTypes = {
|
||||||
|
@ -143,31 +143,29 @@ class ManifestEditorBundle extends Component {
|
|||||||
const { ManifestEditor } = this.state;
|
const { ManifestEditor } = this.state;
|
||||||
const { children, ...rest } = this.props;
|
const { children, ...rest } = this.props;
|
||||||
|
|
||||||
return (
|
return <ManifestEditor {...rest}>{children}</ManifestEditor>;
|
||||||
<ManifestEditor {...rest}>
|
|
||||||
{children}
|
|
||||||
</ManifestEditor>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MEditor = ({ input, defaultValue, readOnly }) =>
|
const MEditor = ({ input, defaultValue, readOnly }) => (
|
||||||
<ManifestEditorBundle
|
<ManifestEditorBundle
|
||||||
mode="yaml"
|
mode="yaml"
|
||||||
{...input}
|
{...input}
|
||||||
value={input.value || defaultValue}
|
value={input.value || defaultValue}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const EEditor = ({ input, defaultValue, readOnly }) =>
|
const EEditor = ({ input, defaultValue, readOnly }) => (
|
||||||
<ManifestEditorBundle
|
<ManifestEditorBundle
|
||||||
mode="ini"
|
mode="ini"
|
||||||
{...input}
|
{...input}
|
||||||
value={input.value || defaultValue}
|
value={input.value || defaultValue}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
export const Name = ({ handleSubmit, onCancel, dirty }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={12} md={3} lg={3}>
|
<Col xs={12} md={3} lg={3}>
|
||||||
@ -185,7 +183,8 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
|||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsRow>
|
</ButtonsRow>
|
||||||
</form>;
|
</form>
|
||||||
|
);
|
||||||
|
|
||||||
export const Manifest = ({
|
export const Manifest = ({
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -193,7 +192,7 @@ export const Manifest = ({
|
|||||||
dirty,
|
dirty,
|
||||||
defaultValue = '',
|
defaultValue = '',
|
||||||
loading
|
loading
|
||||||
}) =>
|
}) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<Field name="manifest" defaultValue={defaultValue} component={MEditor} />
|
<Field name="manifest" defaultValue={defaultValue} component={MEditor} />
|
||||||
<ButtonsRow>
|
<ButtonsRow>
|
||||||
@ -208,30 +207,31 @@ export const Manifest = ({
|
|||||||
Environment
|
Environment
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsRow>
|
</ButtonsRow>
|
||||||
</form>;
|
</form>
|
||||||
|
);
|
||||||
|
|
||||||
const File = ({ id, name, value, onRemoveFile, readOnly }) => {
|
const File = ({ id, name, value, onRemoveFile, readOnly }) => {
|
||||||
const removeButton = !readOnly
|
const removeButton = !readOnly ? (
|
||||||
? <FilenameRemove type="button" onClick={onRemoveFile} secondary>
|
<FilenameRemove type="button" onClick={onRemoveFile} secondary>
|
||||||
Remove
|
Remove
|
||||||
</FilenameRemove>
|
</FilenameRemove>
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
const fileEditor = !readOnly
|
const fileEditor = !readOnly ? (
|
||||||
? <Field
|
<Field name={`file-value-${id}`} defaultValue={value} component={EEditor} />
|
||||||
name={`file-value-${id}`}
|
) : (
|
||||||
defaultValue={value}
|
<EEditor input={{ value }} readOnly />
|
||||||
component={EEditor}
|
);
|
||||||
/>
|
|
||||||
: <EEditor input={{ value }} readOnly />;
|
|
||||||
|
|
||||||
const input = !readOnly
|
const input = !readOnly ? (
|
||||||
? <FilenameInput type="text" placeholder="Filename including extension…" />
|
<FilenameInput type="text" placeholder="Filename including extension…" />
|
||||||
: <FilenameInput
|
) : (
|
||||||
type="text"
|
<FilenameInput
|
||||||
placeholder="Filename including extension…"
|
type="text"
|
||||||
value={name}
|
placeholder="Filename including extension…"
|
||||||
/>;
|
value={name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FileCard>
|
<FileCard>
|
||||||
@ -247,15 +247,15 @@ const File = ({ id, name, value, onRemoveFile, readOnly }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
|
const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
|
||||||
const footer = !readOnly
|
const footer = !readOnly ? (
|
||||||
? <Button type="button" onClick={onAddFile} secondary>
|
<Button type="button" onClick={onAddFile} secondary>
|
||||||
Create new .env file
|
Create new .env file
|
||||||
</Button>
|
</Button>
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{files.map(({ id, ...rest }) =>
|
{files.map(({ id, ...rest }) => (
|
||||||
<File
|
<File
|
||||||
key={id}
|
key={id}
|
||||||
id={id}
|
id={id}
|
||||||
@ -263,7 +263,7 @@ const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
|
|||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
{footer}
|
{footer}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -280,30 +280,28 @@ export const Environment = ({
|
|||||||
readOnly = false,
|
readOnly = false,
|
||||||
loading
|
loading
|
||||||
}) => {
|
}) => {
|
||||||
const envEditor = !readOnly
|
const envEditor = !readOnly ? (
|
||||||
? <Field
|
<Field name="environment" defaultValue={defaultValue} component={EEditor} />
|
||||||
name="environment"
|
) : (
|
||||||
defaultValue={defaultValue}
|
<EEditor input={{ value: defaultValue }} readOnly />
|
||||||
component={EEditor}
|
);
|
||||||
/>
|
|
||||||
: <EEditor input={{ value: defaultValue }} readOnly />;
|
|
||||||
|
|
||||||
const footerDivider = !readOnly ? <EnvironmentDivider /> : null;
|
const footerDivider = !readOnly ? <EnvironmentDivider /> : null;
|
||||||
|
|
||||||
const footer = !readOnly
|
const footer = !readOnly ? (
|
||||||
? <ButtonsRow>
|
<ButtonsRow>
|
||||||
<Button type="button" onClick={onCancel} secondary>
|
<Button type="button" onClick={onCancel} secondary>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={!(dirty || !loading || defaultValue.length)}
|
disabled={!(dirty || !loading || defaultValue.length)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsRow>
|
</ButtonsRow>
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
@ -348,18 +346,18 @@ export const Review = ({
|
|||||||
environmentToggles,
|
environmentToggles,
|
||||||
...state
|
...state
|
||||||
}) => {
|
}) => {
|
||||||
const serviceList = forceArray(state.services).map(({ name, config }) =>
|
const serviceList = forceArray(state.services).map(({ name, config }) => (
|
||||||
<ServiceCard key={name}>
|
<ServiceCard key={name}>
|
||||||
<ServiceName>
|
<ServiceName>{name}</ServiceName>
|
||||||
{name}
|
|
||||||
</ServiceName>
|
|
||||||
<Dl>
|
<Dl>
|
||||||
<dt>
|
<dt>
|
||||||
<ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image>
|
<ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image>
|
||||||
</dt>
|
</dt>
|
||||||
</Dl>
|
</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
|
<ServiceEnvironmentTitle
|
||||||
expanded={environmentToggles[name]}
|
expanded={environmentToggles[name]}
|
||||||
onClick={() => onEnvironmentToggle(name)}
|
onClick={() => onEnvironmentToggle(name)}
|
||||||
@ -370,12 +368,14 @@ export const Review = ({
|
|||||||
up={environmentToggles[name]}
|
up={environmentToggles[name]}
|
||||||
/>
|
/>
|
||||||
</ServiceEnvironmentTitle>
|
</ServiceEnvironmentTitle>
|
||||||
: null}
|
) : null}
|
||||||
{config.environment && config.environment.length && environmentToggles[name]
|
{config.environment &&
|
||||||
? <EnvironmentReview environment={config.environment} />
|
config.environment.length &&
|
||||||
: null}
|
environmentToggles[name] ? (
|
||||||
|
<EnvironmentReview environment={config.environment} />
|
||||||
|
) : null}
|
||||||
</ServiceCard>
|
</ServiceCard>
|
||||||
);
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
@ -396,18 +396,18 @@ export const Progress = ({ stage, create, edit }) => {
|
|||||||
const _nameCompleted = stage !== 'name';
|
const _nameCompleted = stage !== 'name';
|
||||||
const _nameActive = stage === 'name';
|
const _nameActive = stage === 'name';
|
||||||
|
|
||||||
const _name = !create
|
const _name = !create ? null : (
|
||||||
? null
|
<ProgressbarItem>
|
||||||
: <ProgressbarItem>
|
<ProgressbarButton
|
||||||
<ProgressbarButton
|
zIndex="10"
|
||||||
zIndex="10"
|
completed={_nameCompleted}
|
||||||
completed={_nameCompleted}
|
active={_nameActive}
|
||||||
active={_nameActive}
|
first
|
||||||
first
|
>
|
||||||
>
|
Name the group
|
||||||
Name the group
|
</ProgressbarButton>
|
||||||
</ProgressbarButton>
|
</ProgressbarItem>
|
||||||
</ProgressbarItem>;
|
);
|
||||||
|
|
||||||
const _manifestCompleted = ['environment', 'review'].indexOf(stage) >= 0;
|
const _manifestCompleted = ['environment', 'review'].indexOf(stage) >= 0;
|
||||||
const _manifestActive = create ? stage === 'manifest' : stage === 'edit';
|
const _manifestActive = create ? stage === 'manifest' : stage === 'edit';
|
||||||
|
@ -2,8 +2,9 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Message } from 'joyent-ui-toolkit';
|
import { Message } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const ErrorMessage = ({ title, message = "Ooops, there's been an error" }) =>
|
const ErrorMessage = ({ title, message = "Ooops, there's been an error" }) => (
|
||||||
<Message title={title} message={message} type="ERROR" />;
|
<Message title={title} message={message} type="ERROR" />
|
||||||
|
);
|
||||||
|
|
||||||
ErrorMessage.propTypes = {
|
ErrorMessage.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
@ -27,10 +27,9 @@ const Msg = P.extend`
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default ({ msg }) =>
|
export default ({ msg }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Loader />
|
<Loader />
|
||||||
<Msg>
|
<Msg>{msg || 'Loading...'}</Msg>
|
||||||
{msg || 'Loading...'}
|
</Container>
|
||||||
</Msg>
|
);
|
||||||
</Container>;
|
|
||||||
|
@ -7,13 +7,15 @@ const StyledHeading = styled(ModalHeading)`
|
|||||||
color: ${props => props.theme.red};
|
color: ${props => props.theme.red};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ModalErrorMessage = ({ title, message, onCloseClick }) =>
|
const ModalErrorMessage = ({ title, message, onCloseClick }) => (
|
||||||
<div>
|
<div>
|
||||||
<StyledHeading>{title}</StyledHeading>
|
<StyledHeading>{title}</StyledHeading>
|
||||||
<ModalText marginBottom="3">{message}
|
<ModalText marginBottom="3">{message}</ModalText>
|
||||||
</ModalText>
|
<Button onClick={onCloseClick} secondary>
|
||||||
<Button onClick={onCloseClick} secondary>Close </Button>
|
Close{' '}
|
||||||
</div>;
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
ModalErrorMessage.propTypes = {
|
ModalErrorMessage.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
@ -2,8 +2,9 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Message } from 'joyent-ui-toolkit';
|
import { Message } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const WarningMessage = ({ title, message }) =>
|
const WarningMessage = ({ title, message }) => (
|
||||||
<Message title={title} message={message} type="WARNING" />;
|
<Message title={title} message={message} type="WARNING" />
|
||||||
|
);
|
||||||
|
|
||||||
WarningMessage.propTypes = {
|
WarningMessage.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
@ -24,27 +24,22 @@ const BreadcrumbContainer = styled.div`
|
|||||||
const getBreadcrumbItems = (...links) =>
|
const getBreadcrumbItems = (...links) =>
|
||||||
forceArray(links).map(({ pathname, name }, i) => {
|
forceArray(links).map(({ pathname, name }, i) => {
|
||||||
const item =
|
const item =
|
||||||
i + 1 >= links.length
|
i + 1 >= links.length ? (
|
||||||
? name
|
name
|
||||||
: <BreadcrumbLink to={pathname}>
|
) : (
|
||||||
{name}
|
<BreadcrumbLink to={pathname}>{name}</BreadcrumbLink>
|
||||||
</BreadcrumbLink>;
|
);
|
||||||
|
|
||||||
return (
|
return <BreadcrumbItem key={name}>{item}</BreadcrumbItem>;
|
||||||
<BreadcrumbItem key={name}>
|
|
||||||
{item}
|
|
||||||
</BreadcrumbItem>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const NavBreadcrumb = ({ links = [] }) =>
|
const NavBreadcrumb = ({ links = [] }) => (
|
||||||
<BreadcrumbContainer>
|
<BreadcrumbContainer>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Breadcrumb>
|
<Breadcrumb>{getBreadcrumbItems(...links)}</Breadcrumb>
|
||||||
{getBreadcrumbItems(...links)}
|
|
||||||
</Breadcrumb>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</BreadcrumbContainer>;
|
</BreadcrumbContainer>
|
||||||
|
);
|
||||||
|
|
||||||
NavBreadcrumb.propTypes = {
|
NavBreadcrumb.propTypes = {
|
||||||
links: PropTypes.arrayOf(
|
links: PropTypes.arrayOf(
|
||||||
|
@ -12,20 +12,17 @@ const StyledLogo = Img.extend`
|
|||||||
height: ${remcalc(25)};
|
height: ${remcalc(25)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NavHeader = ({ datacenter, username }) =>
|
const NavHeader = ({ datacenter, username }) => (
|
||||||
<Header>
|
<Header>
|
||||||
<HeaderBrand>
|
<HeaderBrand>
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<StyledLogo src={Logo} />
|
<StyledLogo src={Logo} />
|
||||||
</Link>
|
</Link>
|
||||||
</HeaderBrand>
|
</HeaderBrand>
|
||||||
<HeaderItem>
|
<HeaderItem>{datacenter}</HeaderItem>
|
||||||
{datacenter}
|
<HeaderItem>{username}</HeaderItem>
|
||||||
</HeaderItem>
|
</Header>
|
||||||
<HeaderItem>
|
);
|
||||||
{username}
|
|
||||||
</HeaderItem>
|
|
||||||
</Header>;
|
|
||||||
|
|
||||||
NavHeader.propTypes = {
|
NavHeader.propTypes = {
|
||||||
datacenter: PropTypes.string,
|
datacenter: PropTypes.string,
|
||||||
|
@ -11,20 +11,19 @@ import {
|
|||||||
} from 'joyent-ui-toolkit';
|
} from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const getMenuItems = (...links) =>
|
const getMenuItems = (...links) =>
|
||||||
forceArray(links).map(({ pathname, name }) =>
|
forceArray(links).map(({ pathname, name }) => (
|
||||||
<SectionListItem key={pathname}>
|
<SectionListItem key={pathname}>
|
||||||
<SectionListNavLink activeClassName="active" to={pathname}>
|
<SectionListNavLink activeClassName="active" to={pathname}>
|
||||||
{name}
|
{name}
|
||||||
</SectionListNavLink>
|
</SectionListNavLink>
|
||||||
</SectionListItem>
|
</SectionListItem>
|
||||||
);
|
));
|
||||||
|
|
||||||
const Menu = ({ links = [] }) =>
|
const Menu = ({ links = [] }) => (
|
||||||
<LayoutContainer plain>
|
<LayoutContainer plain>
|
||||||
<SectionList>
|
<SectionList>{getMenuItems(...links)}</SectionList>
|
||||||
{getMenuItems(...links)}
|
</LayoutContainer>
|
||||||
</SectionList>
|
);
|
||||||
</LayoutContainer>;
|
|
||||||
|
|
||||||
Menu.propTypes = {
|
Menu.propTypes = {
|
||||||
links: PropTypes.arrayOf(
|
links: PropTypes.arrayOf(
|
||||||
|
@ -39,6 +39,6 @@ NotFound.propTypes = {
|
|||||||
message: PropTypes.string,
|
message: PropTypes.string,
|
||||||
link: PropTypes.string,
|
link: PropTypes.string,
|
||||||
to: PropTypes.string
|
to: PropTypes.string
|
||||||
}
|
};
|
||||||
|
|
||||||
export default NotFound;
|
export default NotFound;
|
||||||
|
@ -6,7 +6,7 @@ const ServiceDelete = ({
|
|||||||
service,
|
service,
|
||||||
onCancelClick = () => {},
|
onCancelClick = () => {},
|
||||||
onConfirmClick = () => {}
|
onConfirmClick = () => {}
|
||||||
}) =>
|
}) => (
|
||||||
<div>
|
<div>
|
||||||
<ModalHeading>
|
<ModalHeading>
|
||||||
Deleting a service: <br /> {service.name}
|
Deleting a service: <br /> {service.name}
|
||||||
@ -19,7 +19,8 @@ const ServiceDelete = ({
|
|||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onConfirmClick}>Delete service</Button>
|
<Button onClick={onConfirmClick}>Delete service</Button>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
ServiceDelete.propTypes = {
|
ServiceDelete.propTypes = {
|
||||||
service: PropTypes.object.isRequired,
|
service: PropTypes.object.isRequired,
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export { default as ServiceScale } from './scale';
|
export { default as ServiceScale } from './scale';
|
||||||
export { default as ServiceDelete } from './delete';
|
export { default as ServiceDelete } from './delete';
|
||||||
export { default as ServiceMetrics} from './metrics';
|
export { default as ServiceMetrics } from './metrics';
|
||||||
|
@ -2,13 +2,9 @@ import React, { Component } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { MetricGraph } from 'joyent-ui-toolkit';
|
import { MetricGraph } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const ServiceMetrics = ({
|
const ServiceMetrics = ({ metricsData, graphDurationSeconds }) => {
|
||||||
metricsData,
|
|
||||||
graphDurationSeconds
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
// metricsData should prob be an array rather than an object
|
// 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)
|
// should also have a header, w metric name and number of instances (omit everything else from design for copilot)
|
||||||
<MetricGraph
|
<MetricGraph
|
||||||
key={key}
|
key={key}
|
||||||
@ -17,19 +13,15 @@ const ServiceMetrics = ({
|
|||||||
height={292}
|
height={292}
|
||||||
graphDurationSeconds={graphDurationSeconds}
|
graphDurationSeconds={graphDurationSeconds}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
// This needs layout!!!
|
// This needs layout!!!
|
||||||
return (
|
return <div>{metricGraphs}</div>;
|
||||||
<div>
|
};
|
||||||
{metricGraphs}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceMetrics.propTypes = {
|
ServiceMetrics.propTypes = {
|
||||||
// metricsData should prob be an array rather than an object
|
// metricsData should prob be an array rather than an object
|
||||||
metricsData: PropTypes.object.isRequired,
|
metricsData: PropTypes.object.isRequired,
|
||||||
graphDurationSeconds: PropTypes.number.isRequired
|
graphDurationSeconds: PropTypes.number.isRequired
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ServiceMetrics;
|
export default ServiceMetrics;
|
||||||
|
@ -15,7 +15,7 @@ const ServiceScale = ({
|
|||||||
onCancelClick = () => {},
|
onCancelClick = () => {},
|
||||||
invalid,
|
invalid,
|
||||||
pristine
|
pristine
|
||||||
}) =>
|
}) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<ModalHeading>
|
<ModalHeading>
|
||||||
Scaling a service: <br />
|
Scaling a service: <br />
|
||||||
@ -38,7 +38,8 @@ const ServiceScale = ({
|
|||||||
<Button type="submit" disabled={pristine || invalid} secondary>
|
<Button type="submit" disabled={pristine || invalid} secondary>
|
||||||
Scale
|
Scale
|
||||||
</Button>
|
</Button>
|
||||||
</form>;
|
</form>
|
||||||
|
);
|
||||||
|
|
||||||
ServiceScale.propTypes = {
|
ServiceScale.propTypes = {
|
||||||
service: PropTypes.object.isRequired,
|
service: PropTypes.object.isRequired,
|
||||||
|
@ -16,7 +16,7 @@ const StyledBox = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default () =>
|
export default () => (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
@ -56,4 +56,5 @@ export default () =>
|
|||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</LayoutContainer>;
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
@ -57,27 +57,27 @@ const ServiceListItem = ({
|
|||||||
: service.instances.length;
|
: service.instances.length;
|
||||||
|
|
||||||
const childrenItems = children.length
|
const childrenItems = children.length
|
||||||
? children.map(service =>
|
? children.map(service => (
|
||||||
<ServiceListItem
|
<ServiceListItem
|
||||||
key={service.id}
|
key={service.id}
|
||||||
deploymentGroup={deploymentGroup}
|
deploymentGroup={deploymentGroup}
|
||||||
service={service}
|
service={service}
|
||||||
isChild
|
isChild
|
||||||
/>
|
/>
|
||||||
) : null;
|
))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const title = isChild ? (
|
||||||
const title = isChild
|
<CardTitle>{service.name}</CardTitle>
|
||||||
? <CardTitle>
|
) : (
|
||||||
{service.name}
|
<CardTitle>
|
||||||
</CardTitle>
|
<TitleInnerContainer>
|
||||||
: <CardTitle>
|
<StyledAnchor to={to} secondary active={service.instancesActive}>
|
||||||
<TitleInnerContainer>
|
{service.name}
|
||||||
<StyledAnchor to={to} secondary active={service.instancesActive}>
|
</StyledAnchor>
|
||||||
{service.name}
|
</TitleInnerContainer>
|
||||||
</StyledAnchor>
|
</CardTitle>
|
||||||
</TitleInnerContainer>
|
);
|
||||||
</CardTitle>;
|
|
||||||
|
|
||||||
const subtitle = (
|
const subtitle = (
|
||||||
<CardSubTitle>
|
<CardSubTitle>
|
||||||
@ -86,52 +86,47 @@ const ServiceListItem = ({
|
|||||||
</CardSubTitle>
|
</CardSubTitle>
|
||||||
);
|
);
|
||||||
|
|
||||||
const header = !isChild
|
const header = !isChild ? (
|
||||||
? <StyledCardHeader>
|
<StyledCardHeader>
|
||||||
{title}
|
{title}
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
<CardInfo
|
<CardInfo
|
||||||
icon={<InstancesIcon />}
|
icon={<InstancesIcon />}
|
||||||
iconPosition="left"
|
iconPosition="left"
|
||||||
label={`${instancesCount} ${instancesCount > 1
|
label={`${instancesCount} ${instancesCount > 1
|
||||||
? 'instances'
|
? 'instances'
|
||||||
: 'instance'}`}
|
: 'instance'}`}
|
||||||
color={!service.instancesActive ? 'disabled' : 'light'}
|
color={!service.instancesActive ? 'disabled' : 'light'}
|
||||||
/>
|
/>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardOptions onClick={handleCardOptionsClick} />
|
<CardOptions onClick={handleCardOptionsClick} />
|
||||||
</StyledCardHeader>
|
</StyledCardHeader>
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
let healthyInfo = null;
|
let healthyInfo = null;
|
||||||
if(service.instancesActive) {
|
if (service.instancesActive) {
|
||||||
const { total, healthy } = service.instancesHealthy;
|
const { total, healthy } = service.instancesHealthy;
|
||||||
const iconHealthy = total === healthy ? 'HEALTHY' : 'NOT HEALTHY';
|
const iconHealthy = total === healthy ? 'HEALTHY' : 'NOT HEALTHY';
|
||||||
const icon = <HealthyIcon healthy={iconHealthy} />;
|
const icon = <HealthyIcon healthy={iconHealthy} />;
|
||||||
const label = `${healthy} of ${total} healthy`;
|
const label = `${healthy} of ${total} healthy`;
|
||||||
|
|
||||||
healthyInfo = (
|
healthyInfo = (
|
||||||
<CardInfo
|
<CardInfo icon={icon} iconPosition="left" label={label} color="dark" />
|
||||||
icon={icon}
|
);
|
||||||
iconPosition='left'
|
|
||||||
label={label}
|
|
||||||
color='dark'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = children.length
|
const view = children.length ? (
|
||||||
? <CardGroupView>
|
<CardGroupView>{childrenItems}</CardGroupView>
|
||||||
{childrenItems}
|
) : (
|
||||||
</CardGroupView>
|
<CardView>
|
||||||
: <CardView>
|
{isChild && title}
|
||||||
{isChild && title}
|
{isChild && subtitle}
|
||||||
{isChild && subtitle}
|
<CardDescription>
|
||||||
<CardDescription>
|
<Status service={service} />
|
||||||
<Status service={service} />
|
{healthyInfo}
|
||||||
{healthyInfo}
|
</CardDescription>
|
||||||
</CardDescription>
|
</CardView>
|
||||||
</CardView>;
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
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 = ({
|
const ServicesQuickActions = ({
|
||||||
show,
|
show,
|
||||||
@ -11,7 +16,7 @@ const ServicesQuickActions = ({
|
|||||||
onStopClick = () => {},
|
onStopClick = () => {},
|
||||||
onStartClick = () => {},
|
onStartClick = () => {},
|
||||||
onScaleClick = () => {},
|
onScaleClick = () => {},
|
||||||
onDeleteClick = () => {},
|
onDeleteClick = () => {}
|
||||||
}) => {
|
}) => {
|
||||||
if (!show) {
|
if (!show) {
|
||||||
return null;
|
return null;
|
||||||
@ -46,22 +51,22 @@ const ServicesQuickActions = ({
|
|||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
const startService =
|
const startService =
|
||||||
status === 'RUNNING'
|
status === 'RUNNING' ? null : (
|
||||||
? null
|
<li>
|
||||||
: <li>
|
<TooltipButton onClick={handleStartClick} disabled={disabled}>
|
||||||
<TooltipButton onClick={handleStartClick} disabled={disabled}>
|
Start
|
||||||
Start
|
</TooltipButton>
|
||||||
</TooltipButton>
|
</li>
|
||||||
</li>;
|
);
|
||||||
|
|
||||||
const stopService =
|
const stopService =
|
||||||
status === 'STOPPED'
|
status === 'STOPPED' ? null : (
|
||||||
? null
|
<li>
|
||||||
: <li>
|
<TooltipButton onClick={handleStopClick} disabled={disabled}>
|
||||||
<TooltipButton onClick={handleStopClick} disabled={disabled}>
|
Stop
|
||||||
Stop
|
</TooltipButton>
|
||||||
</TooltipButton>
|
</li>
|
||||||
</li>;
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip {...position} onBlur={onBlur}>
|
<Tooltip {...position} onBlur={onBlur}>
|
||||||
|
@ -37,16 +37,18 @@ const ServiceStatus = ({ service }) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return service.transitionalStatus
|
return service.transitionalStatus ? (
|
||||||
? <StyledStatusContainer>
|
<StyledStatusContainer>
|
||||||
<StatusLoader />
|
<StatusLoader />
|
||||||
<StyledTransitionalStatus>
|
<StyledTransitionalStatus>
|
||||||
{service.status ? service.status.toLowerCase() : ''}
|
{service.status ? service.status.toLowerCase() : ''}
|
||||||
</StyledTransitionalStatus>
|
</StyledTransitionalStatus>
|
||||||
</StyledStatusContainer>
|
</StyledStatusContainer>
|
||||||
: <StyledStatusContainer>
|
) : (
|
||||||
{getInstanceStatuses(service.instanceStatuses)}
|
<StyledStatusContainer>
|
||||||
</StyledStatusContainer>;
|
{getInstanceStatuses(service.instanceStatuses)}
|
||||||
|
</StyledStatusContainer>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
ServiceStatus.propTypes = {
|
ServiceStatus.propTypes = {
|
||||||
|
@ -5,7 +5,7 @@ import DeploymentGroupDeleteMutation from '@graphql/DeploymentGroupDeleteMutatio
|
|||||||
import DeploymentGroupQuery from '@graphql/DeploymentGroup.gql';
|
import DeploymentGroupQuery from '@graphql/DeploymentGroup.gql';
|
||||||
import { Loader, ModalErrorMessage } from '@components/messaging';
|
import { Loader, ModalErrorMessage } from '@components/messaging';
|
||||||
import { DeploymentGroupDelete as DeploymentGroupDeleteComponent } from '@components/deployment-group';
|
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';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
export class DeploymentGroupDelete extends Component {
|
export class DeploymentGroupDelete extends Component {
|
||||||
@ -21,7 +21,10 @@ export class DeploymentGroupDelete extends Component {
|
|||||||
const { history, match, loading, error } = this.props;
|
const { history, match, loading, error } = this.props;
|
||||||
|
|
||||||
const handleCloseClick = evt => {
|
const handleCloseClick = evt => {
|
||||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
const closeUrl = match.url
|
||||||
|
.split('/')
|
||||||
|
.slice(0, -2)
|
||||||
|
.join('/');
|
||||||
history.replace(closeUrl);
|
history.replace(closeUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,24 +40,21 @@ export class DeploymentGroupDelete extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occurred while loading your deployment group.'
|
message="An error occurred while loading your deployment group."
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { deploymentGroup, deleteDeploymentGroup } = this.props;
|
||||||
deploymentGroup,
|
|
||||||
deleteDeploymentGroup
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message={`An error occurred while attempting to delete the ${deploymentGroup.name} deployment group.`}
|
message={`An error occurred while attempting to delete the ${deploymentGroup.name} deployment group.`}
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
@ -117,7 +117,7 @@ const DeploymentGroupGql = graphql(DeploymentGroupQuery, {
|
|||||||
const DeploymentGroupDeleteWithData = compose(
|
const DeploymentGroupDeleteWithData = compose(
|
||||||
DeleteDeploymentGroupGql,
|
DeleteDeploymentGroupGql,
|
||||||
DeploymentGroupGql,
|
DeploymentGroupGql,
|
||||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
|
||||||
)(DeploymentGroupDelete);
|
)(DeploymentGroupDelete);
|
||||||
|
|
||||||
export default DeploymentGroupDeleteWithData;
|
export default DeploymentGroupDeleteWithData;
|
||||||
|
@ -5,9 +5,10 @@ import { Progress } from '@components/manifest/edit-or-create';
|
|||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
import { Title } from '@components/navigation';
|
import { Title } from '@components/navigation';
|
||||||
|
|
||||||
export default ({ match }) =>
|
export default ({ match }) => (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<Title>Creating deployment group</Title>
|
<Title>Creating deployment group</Title>
|
||||||
<Progress stage={match.params.stage} create />
|
<Progress stage={match.params.stage} create />
|
||||||
<ManifestEditOrCreate create />
|
<ManifestEditOrCreate create />
|
||||||
</LayoutContainer>;
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
@ -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}>
|
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
||||||
<Box>
|
<Box>
|
||||||
<StyledLink to={`${match.path}/${slug}`}>
|
<StyledLink to={`${match.path}/${slug}`}>
|
||||||
<ServiceTitle>
|
<ServiceTitle>{name}</ServiceTitle>
|
||||||
{name}
|
|
||||||
</ServiceTitle>
|
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
<StyledIconButton to={`${match.url}/${slug}/delete`}>
|
<StyledIconButton to={`${match.url}/${slug}/delete`}>
|
||||||
<BinIcon />
|
<BinIcon />
|
||||||
</StyledIconButton>
|
</StyledIconButton>
|
||||||
</Box>
|
</Box>
|
||||||
</Col>
|
</Col>
|
||||||
);
|
));
|
||||||
|
|
||||||
const create = [
|
const create = [
|
||||||
<Col xs={12} sm={4} md={3} lg={3} key="~create">
|
<Col xs={12} sm={4} md={3} lg={3} key="~create">
|
||||||
@ -165,18 +163,16 @@ export const DeploymentGroupList = ({
|
|||||||
</BoxCreate>
|
</BoxCreate>
|
||||||
</Col>
|
</Col>
|
||||||
].concat(
|
].concat(
|
||||||
forceArray(importable).map(({ slug, name }) =>
|
forceArray(importable).map(({ slug, name }) => (
|
||||||
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
<Col xs={12} sm={4} md={3} lg={3} key={slug}>
|
||||||
<BoxCreate>
|
<BoxCreate>
|
||||||
<StyledCreateLink to={`${match.path}/~import/${slug}`}>
|
<StyledCreateLink to={`${match.path}/~import/${slug}`}>
|
||||||
<Oval>⤵</Oval>
|
<Oval>⤵</Oval>
|
||||||
<CreateTitle>
|
<CreateTitle>{name}</CreateTitle>
|
||||||
{name}
|
|
||||||
</CreateTitle>
|
|
||||||
</StyledCreateLink>
|
</StyledCreateLink>
|
||||||
</BoxCreate>
|
</BoxCreate>
|
||||||
</Col>
|
</Col>
|
||||||
)
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -218,5 +214,5 @@ export default compose(
|
|||||||
importable: importableDeploymentGroups
|
importable: importableDeploymentGroups
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
|
||||||
)(DeploymentGroupList);
|
)(DeploymentGroupList);
|
||||||
|
@ -20,7 +20,6 @@ export const InstanceList = ({
|
|||||||
instancesTooltip,
|
instancesTooltip,
|
||||||
toggleInstancesTooltip
|
toggleInstancesTooltip
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const _title = <Title>Instances</Title>;
|
const _title = <Title>Instances</Title>;
|
||||||
|
|
||||||
if (loading && !forceArray(instances).length) {
|
if (loading && !forceArray(instances).length) {
|
||||||
@ -62,15 +61,12 @@ export const InstanceList = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseOver = (evt, instance, type) => {
|
const handleMouseOver = (evt, instance, type) => {
|
||||||
|
|
||||||
const label = evt.currentTarget;
|
const label = evt.currentTarget;
|
||||||
const labelRect = label.getBoundingClientRect();
|
const labelRect = label.getBoundingClientRect();
|
||||||
const offset = type === 'healthy'
|
const offset = type === 'healthy' ? 48 : type === 'status' ? 36 : 0;
|
||||||
? 48 : type === 'status' ? 36 : 0;
|
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
left:
|
left: `${window.scrollX + labelRect.left + offset}px`,
|
||||||
`${window.scrollX + labelRect.left + offset}px`,
|
|
||||||
top: `${window.scrollY + labelRect.bottom}px`
|
top: `${window.scrollY + labelRect.bottom}px`
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,16 +74,16 @@ export const InstanceList = ({
|
|||||||
instance,
|
instance,
|
||||||
position,
|
position,
|
||||||
type
|
type
|
||||||
}
|
};
|
||||||
|
|
||||||
toggleInstancesTooltip(tooltipData);
|
toggleInstancesTooltip(tooltipData);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseOut = (evt) => {
|
const handleMouseOut = evt => {
|
||||||
toggleInstancesTooltip({ show: false });
|
toggleInstancesTooltip({ show: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
const instanceList = instances.map((instance, index) =>
|
const instanceList = instances.map((instance, index) => (
|
||||||
<InstanceListItem
|
<InstanceListItem
|
||||||
instance={instance}
|
instance={instance}
|
||||||
key={instance.id}
|
key={instance.id}
|
||||||
@ -95,7 +91,7 @@ export const InstanceList = ({
|
|||||||
onStatusMouseOver={handleStatusMouseOver}
|
onStatusMouseOver={handleStatusMouseOver}
|
||||||
onMouseOut={handleMouseOut}
|
onMouseOut={handleMouseOut}
|
||||||
/>
|
/>
|
||||||
);
|
));
|
||||||
|
|
||||||
const _instances = !instanceList.length ? <EmptyInstances /> : instanceList;
|
const _instances = !instanceList.length ? <EmptyInstances /> : instanceList;
|
||||||
|
|
||||||
@ -105,7 +101,7 @@ export const InstanceList = ({
|
|||||||
{_instances}
|
{_instances}
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => ({
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
instancesTooltip: state.ui.instances.tooltip
|
instancesTooltip: state.ui.instances.tooltip
|
||||||
@ -131,7 +127,7 @@ const InstanceListGql = graphql(InstancesQuery, {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
instances: sortBy(
|
instances: sortBy(
|
||||||
forceArray(
|
forceArray(
|
||||||
@ -151,8 +147,5 @@ const InstanceListGql = graphql(InstancesQuery, {
|
|||||||
export default compose(
|
export default compose(
|
||||||
UiConnect,
|
UiConnect,
|
||||||
InstanceListGql,
|
InstanceListGql,
|
||||||
withNotFound([
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP, GqlPaths.SERVICES])
|
||||||
GqlPaths.DEPLOYMENT_GROUP,
|
|
||||||
GqlPaths.SERVICES
|
|
||||||
])
|
|
||||||
)(InstanceList);
|
)(InstanceList);
|
||||||
|
@ -12,37 +12,34 @@ const StyledContainer = styled.div`
|
|||||||
const healthMessages = {
|
const healthMessages = {
|
||||||
healthy: 'Your instance is operating as expected',
|
healthy: 'Your instance is operating as expected',
|
||||||
unhealthy: 'Your instance is not 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',
|
maintenance:
|
||||||
unknown: 'We\'ve connected to your instance but we have no health information',
|
"You've set your instance to this manually, use the Container Pilot CLI to change",
|
||||||
unavailable: 'We cannot connect to your instance',
|
unknown: "We've connected to your instance but we have no health information",
|
||||||
|
unavailable: 'We cannot connect to your instance'
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusMessages = {
|
const statusMessages = {
|
||||||
running: 'Your instance is operating',
|
running: 'Your instance is operating',
|
||||||
provisioning: 'Your instance is downloading dependencies and compiling',
|
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',
|
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??????',
|
offline: 'We have no idea what this means, do you??????',
|
||||||
failed: 'Your instance has crashed',
|
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 = ({
|
export const InstancesTooltip = ({ instancesTooltip }) => {
|
||||||
instancesTooltip
|
if (instancesTooltip.show) {
|
||||||
}) => {
|
const { type, instance } = instancesTooltip;
|
||||||
|
|
||||||
if(instancesTooltip.show) {
|
const message =
|
||||||
const {
|
type === 'healthy'
|
||||||
type,
|
? healthMessages[instance.healthy.toLowerCase()]
|
||||||
instance
|
: type === 'status'
|
||||||
} = instancesTooltip;
|
? statusMessages[instance.status.toLowerCase()]
|
||||||
|
: '';
|
||||||
const message = type === 'healthy'
|
|
||||||
? healthMessages[instance.healthy.toLowerCase()]
|
|
||||||
: type === 'status'
|
|
||||||
? statusMessages[instance.status.toLowerCase()]
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
@ -50,7 +47,7 @@ export const InstancesTooltip = ({
|
|||||||
<TooltipLabel>{message}</TooltipLabel>
|
<TooltipLabel>{message}</TooltipLabel>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -175,7 +175,9 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
name.replace(/^\$/, '')
|
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}`;
|
return `# define your interpolatable variables here\n${vars}`;
|
||||||
}
|
}
|
||||||
|
@ -47,12 +47,12 @@ const Manifest = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _notice =
|
const _notice =
|
||||||
deploymentGroup && deploymentGroup.imported && !manifest
|
deploymentGroup && deploymentGroup.imported && !manifest ? (
|
||||||
? <WarningMessage
|
<WarningMessage
|
||||||
title="Be aware"
|
title="Be aware"
|
||||||
message="Since this Deployment Group was imported, it doesn't have the initial manifest."
|
message="Since this Deployment Group was imported, it doesn't have the initial manifest."
|
||||||
/>
|
/>
|
||||||
: null;
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
|
@ -11,25 +11,16 @@ export const MetricNames = [
|
|||||||
export const withServiceMetricsPolling = ({
|
export const withServiceMetricsPolling = ({
|
||||||
pollingInterval = 1000 // in milliseconds
|
pollingInterval = 1000 // in milliseconds
|
||||||
}) => {
|
}) => {
|
||||||
return (WrappedComponent) => {
|
return WrappedComponent => {
|
||||||
|
|
||||||
return class extends Component {
|
return class extends Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
||||||
this._poll = setInterval(() => {
|
this._poll = setInterval(() => {
|
||||||
const {
|
const { loading, error, service, fetchMoreMetrics } = this.props;
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
service,
|
|
||||||
fetchMoreMetrics
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if(!loading && !error && service) {
|
if (!loading && !error && service) {
|
||||||
const previousEnd = service.instances[0].metrics[0].end;
|
const previousEnd = service.instances[0].metrics[0].end;
|
||||||
fetchMoreMetrics(previousEnd);
|
fetchMoreMetrics(previousEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, pollingInterval); // TODO this is the polling interval - think about amount is the todo I guess...
|
}, pollingInterval); // TODO this is the polling interval - think about amount is the todo I guess...
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,24 +29,28 @@ export const withServiceMetricsPolling = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <WrappedComponent {...this.props} />
|
return <WrappedComponent {...this.props} />;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export const withServiceMetricsGql = ({
|
export const withServiceMetricsGql = ({
|
||||||
gqlQuery,
|
gqlQuery,
|
||||||
graphDurationSeconds,
|
graphDurationSeconds,
|
||||||
updateIntervalSeconds
|
updateIntervalSeconds
|
||||||
}) => {
|
}) => {
|
||||||
|
const getPreviousMetrics = (
|
||||||
const getPreviousMetrics = (previousResult, serviceId, instanceId, metricName) => {
|
previousResult,
|
||||||
|
serviceId,
|
||||||
|
instanceId,
|
||||||
|
metricName
|
||||||
|
) => {
|
||||||
return previousResult.deploymentGroup.services
|
return previousResult.deploymentGroup.services
|
||||||
.find(s => s.id === serviceId).instances
|
.find(s => s.id === serviceId)
|
||||||
.find(i => i.id === instanceId).metrics
|
.instances.find(i => i.id === instanceId)
|
||||||
.find(m => m.name === metricName).metrics;
|
.metrics.find(m => m.name === metricName).metrics;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getNextResult = (previousResult, fetchNextResult) => {
|
const getNextResult = (previousResult, fetchNextResult) => {
|
||||||
const deploymentGroup = fetchNextResult.deploymentGroup;
|
const deploymentGroup = fetchNextResult.deploymentGroup;
|
||||||
@ -69,18 +64,18 @@ export const withServiceMetricsGql = ({
|
|||||||
metrics: instance.metrics.map(metric => ({
|
metrics: instance.metrics.map(metric => ({
|
||||||
...metric,
|
...metric,
|
||||||
metrics: getPreviousMetrics(
|
metrics: getPreviousMetrics(
|
||||||
previousResult,
|
previousResult,
|
||||||
service.id,
|
service.id,
|
||||||
instance.id,
|
instance.id,
|
||||||
metric.name
|
metric.name
|
||||||
).concat(metric.metrics)
|
).concat(metric.metrics)
|
||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return nextResult;
|
return nextResult;
|
||||||
}
|
};
|
||||||
|
|
||||||
return graphql(gqlQuery, {
|
return graphql(gqlQuery, {
|
||||||
options(props) {
|
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
|
// 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 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 {
|
return {
|
||||||
variables: {
|
variables: {
|
||||||
@ -102,27 +100,34 @@ export const withServiceMetricsGql = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: ({ data: { deploymentGroup, loading, error, variables, fetchMore }}) => {
|
props: ({
|
||||||
|
data: { deploymentGroup, loading, error, variables, fetchMore }
|
||||||
const fetchMoreMetrics = (previousEnd) => {
|
}) => {
|
||||||
|
const fetchMoreMetrics = previousEnd => {
|
||||||
fetchMore({
|
fetchMore({
|
||||||
variables: {
|
variables: {
|
||||||
...variables,
|
...variables,
|
||||||
start: previousEnd,
|
start: previousEnd,
|
||||||
end: moment().utc().format()
|
end: moment()
|
||||||
|
.utc()
|
||||||
|
.format()
|
||||||
},
|
},
|
||||||
updateQuery: (previousResult, { fetchMoreResult, queryVariables }) => {
|
updateQuery: (
|
||||||
|
previousResult,
|
||||||
|
{ fetchMoreResult, queryVariables }
|
||||||
|
) => {
|
||||||
return getNextResult(previousResult, fetchMoreResult);
|
return getNextResult(previousResult, fetchMoreResult);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
return ({
|
return {
|
||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
service: !loading && deploymentGroup ? deploymentGroup.services[0] : null,
|
service:
|
||||||
|
!loading && deploymentGroup ? deploymentGroup.services[0] : null,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
fetchMoreMetrics
|
fetchMoreMetrics
|
||||||
})
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
@ -9,8 +9,11 @@ import {
|
|||||||
serviceBySlugSelector
|
serviceBySlugSelector
|
||||||
} from '@root/state/selectors';
|
} from '@root/state/selectors';
|
||||||
|
|
||||||
export const Breadcrumb = ({ deploymentGroup, service, location: { pathname }}) => {
|
export const Breadcrumb = ({
|
||||||
|
deploymentGroup,
|
||||||
|
service,
|
||||||
|
location: { pathname }
|
||||||
|
}) => {
|
||||||
const path = pathname.split('/');
|
const path = pathname.split('/');
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
@ -41,7 +44,7 @@ Breadcrumb.propTypes = {
|
|||||||
deploymentGroup: PropTypes.object,
|
deploymentGroup: PropTypes.object,
|
||||||
service: PropTypes.object,
|
service: PropTypes.object,
|
||||||
location: PropTypes.object
|
location: PropTypes.object
|
||||||
}
|
};
|
||||||
|
|
||||||
const connectBreadcrumb = connect(
|
const connectBreadcrumb = connect(
|
||||||
(state, ownProps) => {
|
(state, ownProps) => {
|
||||||
@ -59,7 +62,4 @@ const connectBreadcrumb = connect(
|
|||||||
dispatch => ({})
|
dispatch => ({})
|
||||||
);
|
);
|
||||||
|
|
||||||
export default compose(
|
export default compose(connectBreadcrumb, withNotFound())(Breadcrumb);
|
||||||
connectBreadcrumb,
|
|
||||||
withNotFound()
|
|
||||||
)(Breadcrumb);
|
|
||||||
|
@ -5,8 +5,9 @@ import get from 'lodash.get';
|
|||||||
import PortalQuery from '@graphql/Portal.gql';
|
import PortalQuery from '@graphql/Portal.gql';
|
||||||
import { Header as HeaderComponent } from '@components/navigation';
|
import { Header as HeaderComponent } from '@components/navigation';
|
||||||
|
|
||||||
export const Header = ({ datacenter, username }) =>
|
export const Header = ({ datacenter, username }) => (
|
||||||
<HeaderComponent datacenter={datacenter} username={username} />;
|
<HeaderComponent datacenter={datacenter} username={username} />
|
||||||
|
);
|
||||||
|
|
||||||
const HeaderWithData = graphql(PortalQuery, {
|
const HeaderWithData = graphql(PortalQuery, {
|
||||||
props: ({ data: { portal = {} } }) => ({
|
props: ({ data: { portal = {} } }) => ({
|
||||||
|
@ -5,7 +5,6 @@ import withNotFound from './not-found-hoc';
|
|||||||
import { Menu as MenuComponent } from '@components/navigation';
|
import { Menu as MenuComponent } from '@components/navigation';
|
||||||
|
|
||||||
export const Menu = ({ location, match, sections }) => {
|
export const Menu = ({ location, match, sections }) => {
|
||||||
|
|
||||||
if (!sections || !sections.length) {
|
if (!sections || !sections.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -40,7 +39,4 @@ const connectMenu = connect(
|
|||||||
dispatch => ({})
|
dispatch => ({})
|
||||||
);
|
);
|
||||||
|
|
||||||
export default compose(
|
export default compose(connectMenu, withNotFound())(Menu);
|
||||||
connectMenu,
|
|
||||||
withNotFound()
|
|
||||||
)(Menu);
|
|
||||||
|
@ -4,31 +4,24 @@ import { NotFound } from '@components/navigation';
|
|||||||
export const GqlPaths = {
|
export const GqlPaths = {
|
||||||
DEPLOYMENT_GROUP: 'deploymentGroup',
|
DEPLOYMENT_GROUP: 'deploymentGroup',
|
||||||
SERVICES: 'services'
|
SERVICES: 'services'
|
||||||
}
|
};
|
||||||
|
|
||||||
export default (paths) => {
|
|
||||||
return (WrappedComponent) => {
|
|
||||||
|
|
||||||
|
export default paths => {
|
||||||
|
return WrappedComponent => {
|
||||||
return class extends Component {
|
return class extends Component {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (paths) {
|
||||||
if(paths) {
|
const { error, location, history } = nextProps;
|
||||||
const {
|
|
||||||
error,
|
|
||||||
location,
|
|
||||||
history
|
|
||||||
} = nextProps;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
error
|
error &&
|
||||||
&& (!location.state || !location.state.notFound)
|
(!location.state || !location.state.notFound) &&
|
||||||
&& (error.graphQLErrors && error.graphQLErrors.length)
|
(error.graphQLErrors && error.graphQLErrors.length)
|
||||||
) {
|
) {
|
||||||
const graphQLError = error.graphQLErrors[0];
|
const graphQLError = error.graphQLErrors[0];
|
||||||
if(graphQLError.message === 'Not Found') {
|
if (graphQLError.message === 'Not Found') {
|
||||||
const notFound = graphQLError.path.pop();
|
const notFound = graphQLError.path.pop();
|
||||||
if(paths.indexOf(notFound) > -1) {
|
if (paths.indexOf(notFound) > -1) {
|
||||||
history.replace(location.pathname, { notFound });
|
history.replace(location.pathname, { notFound });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,25 +30,22 @@ export default (paths) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { error, location, match } = this.props;
|
||||||
|
|
||||||
const {
|
if (location.state && location.state.notFound) {
|
||||||
error,
|
|
||||||
location,
|
|
||||||
match
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if(location.state && location.state.notFound) {
|
|
||||||
const notFound = location.state.notFound;
|
const notFound = location.state.notFound;
|
||||||
if(paths && paths.indexOf(notFound) > -1) {
|
if (paths && paths.indexOf(notFound) > -1) {
|
||||||
let title;
|
let title;
|
||||||
let to;
|
let to;
|
||||||
let link;
|
let link;
|
||||||
if(notFound === 'services' || notFound === 'service') {
|
if (notFound === 'services' || notFound === 'service') {
|
||||||
title = 'This service doesn’t exist';
|
title = 'This service doesn’t exist';
|
||||||
to = match.url.split('/').slice(0, 3).join('/');
|
to = match.url
|
||||||
|
.split('/')
|
||||||
|
.slice(0, 3)
|
||||||
|
.join('/');
|
||||||
link = 'Back to services';
|
link = 'Back to services';
|
||||||
}
|
} else if (notFound === 'deploymentGroup') {
|
||||||
else if(notFound === 'deploymentGroup') {
|
|
||||||
title = 'This deployment group doesn’t exist';
|
title = 'This deployment group doesn’t exist';
|
||||||
to = '/deployment-group';
|
to = '/deployment-group';
|
||||||
link = 'Back to dashboard';
|
link = 'Back to dashboard';
|
||||||
@ -63,17 +53,17 @@ export default (paths) => {
|
|||||||
return (
|
return (
|
||||||
<NotFound
|
<NotFound
|
||||||
title={title}
|
title={title}
|
||||||
message='Sorry, but our princess is in another castle.'
|
message="Sorry, but our princess is in another castle."
|
||||||
to={to}
|
to={to}
|
||||||
link={link}
|
link={link}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <WrappedComponent {...this.props} />
|
return <WrappedComponent {...this.props} />;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
@ -21,7 +21,10 @@ export class ServiceDelete extends Component {
|
|||||||
const { loading, error, match, history } = this.props;
|
const { loading, error, match, history } = this.props;
|
||||||
|
|
||||||
const handleCloseClick = evt => {
|
const handleCloseClick = evt => {
|
||||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
const closeUrl = match.url
|
||||||
|
.split('/')
|
||||||
|
.slice(0, -2)
|
||||||
|
.join('/');
|
||||||
history.replace(closeUrl);
|
history.replace(closeUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,8 +40,8 @@ export class ServiceDelete extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occurred while loading your service.'
|
message="An error occurred while loading your service."
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -51,7 +54,7 @@ export class ServiceDelete extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message={`An error occurred while attempting to delete your ${service.name} service.`}
|
message={`An error occurred while attempting to delete your ${service.name} service.`}
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
@ -60,9 +63,11 @@ export class ServiceDelete extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleConfirmClick = evt => {
|
const handleConfirmClick = evt => {
|
||||||
deleteServices(service.id).then(() => handleCloseClick()).catch(err => {
|
deleteServices(service.id)
|
||||||
this.setState({ error: err });
|
.then(() => handleCloseClick())
|
||||||
});
|
.catch(err => {
|
||||||
|
this.setState({ error: err });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -98,5 +103,5 @@ const DeleteServicesGql = graphql(ServicesDeleteMutation, {
|
|||||||
export default compose(
|
export default compose(
|
||||||
DeleteServicesGql,
|
DeleteServicesGql,
|
||||||
ServiceGql,
|
ServiceGql,
|
||||||
withNotFound([ GqlPaths.SERVICES ])
|
withNotFound([GqlPaths.SERVICES])
|
||||||
)(ServiceDelete);
|
)(ServiceDelete);
|
||||||
|
@ -10,17 +10,16 @@ import { ServiceMetrics as ServiceMetricsComponent } from '@components/service';
|
|||||||
import { Button } from 'joyent-ui-toolkit';
|
import { Button } from 'joyent-ui-toolkit';
|
||||||
import { Loader, ErrorMessage } from '@components/messaging';
|
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
|
// '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
|
// amount of data we'll need to initially fetch
|
||||||
const GraphDurationSeconds = 90;
|
const GraphDurationSeconds = 90;
|
||||||
|
|
||||||
const ServiceMetrics = ({
|
const ServiceMetrics = ({ service, loading, error }) => {
|
||||||
service,
|
|
||||||
loading,
|
|
||||||
error
|
|
||||||
}) => {
|
|
||||||
if (loading || !service) {
|
if (loading || !service) {
|
||||||
return (
|
return (
|
||||||
<LayoutContainer center>
|
<LayoutContainer center>
|
||||||
@ -43,8 +42,8 @@ const ServiceMetrics = ({
|
|||||||
// metricsData should prob be an array rather than an object
|
// metricsData should prob be an array rather than an object
|
||||||
const metricsData = service.instances.reduce((metrics, instance) => {
|
const metricsData = service.instances.reduce((metrics, instance) => {
|
||||||
// gather metrics of instances according to type
|
// gather metrics of instances according to type
|
||||||
instance.metrics.forEach((instanceMetrics) => {
|
instance.metrics.forEach(instanceMetrics => {
|
||||||
if(!metrics[instanceMetrics.name]) {
|
if (!metrics[instanceMetrics.name]) {
|
||||||
metrics[instanceMetrics.name] = [];
|
metrics[instanceMetrics.name] = [];
|
||||||
}
|
}
|
||||||
metrics[instanceMetrics.name].push(instanceMetrics);
|
metrics[instanceMetrics.name].push(instanceMetrics);
|
||||||
@ -69,10 +68,7 @@ export default compose(
|
|||||||
updateIntervalSeconds: 15
|
updateIntervalSeconds: 15
|
||||||
}),
|
}),
|
||||||
withServiceMetricsPolling({ pollingInterval: 1000 }),
|
withServiceMetricsPolling({ pollingInterval: 1000 }),
|
||||||
withNotFound([
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP, GqlPaths.SERVICES])
|
||||||
GqlPaths.DEPLOYMENT_GROUP,
|
|
||||||
GqlPaths.SERVICES
|
|
||||||
])
|
|
||||||
)(ServiceMetrics);
|
)(ServiceMetrics);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -22,7 +22,10 @@ export class ServiceScale extends Component {
|
|||||||
const { loading, error, match, history } = this.props;
|
const { loading, error, match, history } = this.props;
|
||||||
|
|
||||||
const handleCloseClick = evt => {
|
const handleCloseClick = evt => {
|
||||||
const closeUrl = match.url.split('/').slice(0, -2).join('/');
|
const closeUrl = match.url
|
||||||
|
.split('/')
|
||||||
|
.slice(0, -2)
|
||||||
|
.join('/');
|
||||||
history.replace(closeUrl);
|
history.replace(closeUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,8 +41,8 @@ export class ServiceScale extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occurred while loading your service.'
|
message="An error occurred while loading your service."
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -52,7 +55,7 @@ export class ServiceScale extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal width={460} onCloseClick={handleCloseClick}>
|
<Modal width={460} onCloseClick={handleCloseClick}>
|
||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message={`An error occurred while attempting to scale your ${service.name} service.`}
|
message={`An error occurred while attempting to scale your ${service.name} service.`}
|
||||||
onCloseClick={handleCloseClick}
|
onCloseClick={handleCloseClick}
|
||||||
/>
|
/>
|
||||||
@ -70,9 +73,11 @@ export class ServiceScale extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmitClick = values => {
|
const handleSubmitClick = values => {
|
||||||
scale(service.id, values.replicas).then(handleCloseClick).catch(err => {
|
scale(service.id, values.replicas)
|
||||||
this.setState({ error: err });
|
.then(handleCloseClick)
|
||||||
});
|
.catch(err => {
|
||||||
|
this.setState({ error: err });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!service) {
|
if (!service) {
|
||||||
@ -126,5 +131,5 @@ const ServiceScaleGql = graphql(ServiceScaleMutation, {
|
|||||||
export default compose(
|
export default compose(
|
||||||
ServiceScaleGql,
|
ServiceScaleGql,
|
||||||
ServiceGql,
|
ServiceGql,
|
||||||
withNotFound([ GqlPaths.SERVICES ])
|
withNotFound([GqlPaths.SERVICES])
|
||||||
)(ServiceScale);
|
)(ServiceScale);
|
||||||
|
@ -34,7 +34,7 @@ export class ServiceList extends Component {
|
|||||||
services,
|
services,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
toggleServicesQuickActions,
|
toggleServicesQuickActions
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (loading && !forceArray(services).length) {
|
if (loading && !forceArray(services).length) {
|
||||||
@ -73,8 +73,9 @@ export class ServiceList extends Component {
|
|||||||
const buttonRect = button.getBoundingClientRect();
|
const buttonRect = button.getBoundingClientRect();
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
left:
|
left: `${buttonRect.left +
|
||||||
`${buttonRect.left + window.scrollX + (buttonRect.right - buttonRect.left) / 2}px`,
|
window.scrollX +
|
||||||
|
(buttonRect.right - buttonRect.left) / 2}px`,
|
||||||
top: `${buttonRect.bottom + window.scrollY}px`
|
top: `${buttonRect.bottom + window.scrollY}px`
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,9 +121,7 @@ export class ServiceList extends Component {
|
|||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
{renderedError}
|
{renderedError}
|
||||||
<StyledContainer>
|
<StyledContainer>{serviceList}</StyledContainer>
|
||||||
{serviceList}
|
|
||||||
</StyledContainer>
|
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -134,7 +133,7 @@ ServiceList.propTypes = {
|
|||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
error: PropTypes.bool,
|
error: PropTypes.bool,
|
||||||
toggleServicesQuickActions: PropTypes.func
|
toggleServicesQuickActions: PropTypes.func
|
||||||
}
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => ({});
|
const mapStateToProps = (state, ownProps) => ({});
|
||||||
|
|
||||||
@ -153,7 +152,7 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
services: deploymentGroup
|
services: deploymentGroup
|
||||||
? processServices(deploymentGroup.services, null)
|
? processServices(deploymentGroup.services, null)
|
||||||
@ -166,7 +165,7 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
const ServiceListWithData = compose(
|
const ServiceListWithData = compose(
|
||||||
ServicesGql,
|
ServicesGql,
|
||||||
UiConnect,
|
UiConnect,
|
||||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
|
||||||
)(ServiceList);
|
)(ServiceList);
|
||||||
|
|
||||||
export default ServiceListWithData;
|
export default ServiceListWithData;
|
||||||
|
@ -20,11 +20,8 @@ const PaddedRow = Row.extend`
|
|||||||
margin-bottom: ${remcalc(18)}
|
margin-bottom: ${remcalc(18)}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ServicesMenu = ({
|
|
||||||
location: { pathname },
|
|
||||||
history: { push }
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
|
export const ServicesMenu = ({ location: { pathname }, history: { push } }) => {
|
||||||
const toggleValue = pathname.split('-').pop();
|
const toggleValue = pathname.split('-').pop();
|
||||||
|
|
||||||
const handleToggle = evt => {
|
const handleToggle = evt => {
|
||||||
|
@ -17,13 +17,12 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export class ServicesQuickActions extends Component {
|
export class ServicesQuickActions extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
errors: {}
|
errors: {}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -53,20 +52,20 @@ export class ServicesQuickActions extends Component {
|
|||||||
? 'An error occurred while attempting to restart your service.'
|
? 'An error occurred while attempting to restart your service.'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
errorMessage = (
|
errorMessage = (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<ErrorMessage title="Ooops!" message={message} />
|
<ErrorMessage title="Ooops!" message={message} />
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(servicesQuickActions.show) {
|
if (servicesQuickActions.show) {
|
||||||
const handleTooltipBlur = evt => {
|
const handleTooltipBlur = evt => {
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRestartClick = (evt, service) => {
|
const handleRestartClick = (evt, service) => {
|
||||||
this.setState({errors: {}});
|
this.setState({ errors: {} });
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
restartServices(service.id).catch(err => {
|
restartServices(service.id).catch(err => {
|
||||||
this.setState({ errors: { restart: err } });
|
this.setState({ errors: { restart: err } });
|
||||||
@ -74,7 +73,7 @@ export class ServicesQuickActions extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleStopClick = (evt, service) => {
|
const handleStopClick = (evt, service) => {
|
||||||
this.setState({errors: {}});
|
this.setState({ errors: {} });
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
stopServices(service.id).catch(err => {
|
stopServices(service.id).catch(err => {
|
||||||
this.setState({ errors: { stop: err } });
|
this.setState({ errors: { stop: err } });
|
||||||
@ -82,7 +81,7 @@ export class ServicesQuickActions extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleStartClick = (evt, service) => {
|
const handleStartClick = (evt, service) => {
|
||||||
this.setState({errors: {}});
|
this.setState({ errors: {} });
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
startServices(service.id).catch(err => {
|
startServices(service.id).catch(err => {
|
||||||
this.setState({ errors: { start: err } });
|
this.setState({ errors: { start: err } });
|
||||||
@ -90,13 +89,13 @@ export class ServicesQuickActions extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleScaleClick = (evt, service) => {
|
const handleScaleClick = (evt, service) => {
|
||||||
this.setState({errors: {}});
|
this.setState({ errors: {} });
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
push(`${url}/${service.slug}/scale`);
|
push(`${url}/${service.slug}/scale`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteClick = (evt, service) => {
|
const handleDeleteClick = (evt, service) => {
|
||||||
this.setState({errors: {}});
|
this.setState({ errors: {} });
|
||||||
toggleServicesQuickActions({ show: false });
|
toggleServicesQuickActions({ show: false });
|
||||||
push(`${url}/${service.slug}/delete`);
|
push(`${url}/${service.slug}/delete`);
|
||||||
};
|
};
|
||||||
@ -115,16 +114,16 @@ export class ServicesQuickActions extends Component {
|
|||||||
onDeleteClick={handleDeleteClick}
|
onDeleteClick={handleDeleteClick}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(quickActions || errorMessage) {
|
if (quickActions || errorMessage) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{errorMessage}
|
{errorMessage}
|
||||||
{quickActions}
|
{quickActions}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -47,7 +47,7 @@ export class ServicesTopology extends Component {
|
|||||||
services,
|
services,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
toggleServicesQuickActions,
|
toggleServicesQuickActions
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (loading && !forceArray(services).length) {
|
if (loading && !forceArray(services).length) {
|
||||||
@ -85,18 +85,27 @@ export class ServicesTopology extends Component {
|
|||||||
const container = this._refs.container;
|
const container = this._refs.container;
|
||||||
const containerRect = container.getBoundingClientRect();
|
const containerRect = container.getBoundingClientRect();
|
||||||
const position = {
|
const position = {
|
||||||
top: `${containerRect.top + window.scrollY + tooltipData.position.top}px`,
|
top: `${containerRect.top +
|
||||||
left: `${containerRect.left + window.scrollX + tooltipData.position.left}px`
|
window.scrollY +
|
||||||
}
|
tooltipData.position.top}px`,
|
||||||
|
left: `${containerRect.left +
|
||||||
|
window.scrollX +
|
||||||
|
tooltipData.position.left}px`
|
||||||
|
};
|
||||||
const data = {
|
const data = {
|
||||||
...tooltipData,
|
...tooltipData,
|
||||||
position
|
position
|
||||||
}
|
};
|
||||||
toggleServicesQuickActions(data);
|
toggleServicesQuickActions(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNodeTitleClick = (evt, { service }) => {
|
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;
|
let renderedError = null;
|
||||||
@ -173,7 +182,7 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
const ServicesTopologyWithData = compose(
|
const ServicesTopologyWithData = compose(
|
||||||
ServicesGql,
|
ServicesGql,
|
||||||
UiConnect,
|
UiConnect,
|
||||||
withNotFound([ GqlPaths.DEPLOYMENT_GROUP ])
|
withNotFound([GqlPaths.DEPLOYMENT_GROUP])
|
||||||
)(ServicesTopology);
|
)(ServicesTopology);
|
||||||
|
|
||||||
export default ServicesTopologyWithData;
|
export default ServicesTopologyWithData;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
query Instances(
|
query Instances(
|
||||||
$deploymentGroupSlug: String!,
|
$deploymentGroupSlug: String!
|
||||||
$serviceSlug: String!,
|
$serviceSlug: String!
|
||||||
$metricNames: [MetricName]!,
|
$metricNames: [MetricName]!
|
||||||
$start: String!,
|
$start: String!
|
||||||
$end: String!
|
$end: String!
|
||||||
) {
|
) {
|
||||||
deploymentGroup(slug: $deploymentGroupSlug) {
|
deploymentGroup(slug: $deploymentGroupSlug) {
|
||||||
|
@ -25,10 +25,7 @@ import {
|
|||||||
ServiceMetrics
|
ServiceMetrics
|
||||||
} from '@containers/service';
|
} from '@containers/service';
|
||||||
|
|
||||||
import {
|
import { InstanceList, InstancesTooltip } from '@containers/instances';
|
||||||
InstanceList,
|
|
||||||
InstancesTooltip
|
|
||||||
} from '@containers/instances';
|
|
||||||
|
|
||||||
import { DeploymentGroupDelete } from '@containers/deployment-group';
|
import { DeploymentGroupDelete } from '@containers/deployment-group';
|
||||||
|
|
||||||
@ -43,23 +40,27 @@ const Container = styled.div`
|
|||||||
|
|
||||||
const rootRedirect = p => <Redirect to="/deployment-groups" />;
|
const rootRedirect = p => <Redirect to="/deployment-groups" />;
|
||||||
|
|
||||||
const servicesListRedirect = p =>
|
const servicesListRedirect = p => (
|
||||||
<Redirect
|
<Redirect
|
||||||
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`}
|
to={`/deployment-groups/${p.match.params.deploymentGroup}/services-list`}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const servicesTopologyRedirect = p =>
|
const servicesTopologyRedirect = p => (
|
||||||
<Redirect
|
<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
|
<Redirect
|
||||||
to={`/deployment-groups/${p.match.params.deploymentGroup}/services/${p.match
|
to={`/deployment-groups/${p.match.params.deploymentGroup}/services/${p.match
|
||||||
.params.service}/instances`}
|
.params.service}/instances`}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const App = p =>
|
const App = p => (
|
||||||
<div>
|
<div>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
@ -222,7 +223,8 @@ const App = p =>
|
|||||||
component={servicesTopologyRedirect}
|
component={servicesTopologyRedirect}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const Router = (
|
const Router = (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { handleActions } from 'redux-actions';
|
import { handleActions } from 'redux-actions';
|
||||||
import { toggleServicesQuickActions, toggleInstancesTooltip } from '@state/actions';
|
import {
|
||||||
|
toggleServicesQuickActions,
|
||||||
|
toggleInstancesTooltip
|
||||||
|
} from '@state/actions';
|
||||||
|
|
||||||
export const _toggleServicesQuickActions = (state, action) => {
|
export const _toggleServicesQuickActions = (state, action) => {
|
||||||
const { position, service, show } = action.payload;
|
const { position, service, show } = action.payload;
|
||||||
|
@ -104,10 +104,10 @@ const getInstancesHealthy = instances => {
|
|||||||
return instances.reduce(
|
return instances.reduce(
|
||||||
(healthy, instance) => ({
|
(healthy, instance) => ({
|
||||||
total: healthy.total + 1,
|
total: healthy.total + 1,
|
||||||
healthy: instance.healthy === 'HEALTHY' ?
|
healthy:
|
||||||
healthy.healthy + 1 : 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 {
|
export {
|
||||||
deploymentGroupBySlug as deploymentGroupBySlugSelector,
|
deploymentGroupBySlug as deploymentGroupBySlugSelector,
|
||||||
serviceBySlug as serviceBySlugSelector,
|
serviceBySlug as serviceBySlugSelector,
|
||||||
@ -182,6 +184,5 @@ export {
|
|||||||
getInstancesHealthy,
|
getInstancesHealthy,
|
||||||
getService,
|
getService,
|
||||||
processServices,
|
processServices,
|
||||||
processServicesForTopology /* ,
|
processServicesForTopology
|
||||||
instancesByServiceId */
|
|
||||||
};
|
};
|
||||||
|
@ -30,8 +30,11 @@ export const client = new ApolloClient({
|
|||||||
? o.timestamp
|
? o.timestamp
|
||||||
: o.name && o.instance
|
: o.name && o.instance
|
||||||
? `${o.name}-${o.instance}`
|
? `${o.name}-${o.instance}`
|
||||||
: o.name ? o.name : o.time && o.value
|
: o.name
|
||||||
? `${o.time}-${o.value}` : 'apollo-cache-key-not-defined';
|
? o.name
|
||||||
|
: o.time && o.value
|
||||||
|
? `${o.time}-${o.value}`
|
||||||
|
: 'apollo-cache-key-not-defined';
|
||||||
return `${o.__typename}:${id}`;
|
return `${o.__typename}:${id}`;
|
||||||
},
|
},
|
||||||
networkInterface: createNetworkInterface({
|
networkInterface: createNetworkInterface({
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -12,9 +11,7 @@ import { deploymentGroup } from '../../mocks';
|
|||||||
|
|
||||||
it('renders <DeploymentGroupDelete /> without throwing', () => {
|
it('renders <DeploymentGroupDelete /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(<DeploymentGroupDelete deploymentGroup={deploymentGroup} />)
|
||||||
<DeploymentGroupDelete deploymentGroup={deploymentGroup} />
|
|
||||||
)
|
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -10,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import EmtpyInstances from '@components/instances/empty.js';
|
import EmtpyInstances from '@components/instances/empty.js';
|
||||||
|
|
||||||
it('renders <EmtpyInstances /> without throwing', () => {
|
it('renders <EmtpyInstances /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<EmtpyInstances />).toJSON();
|
||||||
.create(
|
|
||||||
<EmtpyInstances />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -11,10 +10,6 @@ import InstanceCard from '@components/instances/list-item.js';
|
|||||||
import { instance } from '../../mocks';
|
import { instance } from '../../mocks';
|
||||||
|
|
||||||
it('renders <InstanceCard /> without throwing', () => {
|
it('renders <InstanceCard /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<InstanceCard instance={instance} />).toJSON();
|
||||||
.create(
|
|
||||||
<InstanceCard instance={instance} />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -9,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import Container from '@components/layout/container';
|
import Container from '@components/layout/container';
|
||||||
|
|
||||||
it('renders <Container /> without throwing', () => {
|
it('renders <Container /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Container />).toJSON();
|
||||||
.create(
|
|
||||||
<Container />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -9,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import Error from '@components/messaging/error';
|
import Error from '@components/messaging/error';
|
||||||
|
|
||||||
it('renders <Error /> without throwing', () => {
|
it('renders <Error /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Error />).toJSON();
|
||||||
.create(
|
|
||||||
<Error />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -9,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import Loader from '@components/messaging/loader';
|
import Loader from '@components/messaging/loader';
|
||||||
|
|
||||||
it('renders <Loader /> without throwing', () => {
|
it('renders <Loader /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Loader />).toJSON();
|
||||||
.create(
|
|
||||||
<Loader />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import ModalError from '@components/messaging/modal-error';
|
|||||||
it('renders <ModalError /> without throwing', () => {
|
it('renders <ModalError /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(
|
||||||
<ModalError message='Modal error message' onCloseClick={() => {}}/>
|
<ModalError message="Modal error message" onCloseClick={() => {}} />
|
||||||
)
|
)
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
|
@ -9,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import Warning from '@components/messaging/warning';
|
import Warning from '@components/messaging/warning';
|
||||||
|
|
||||||
it('renders <Warning /> without throwing', () => {
|
it('renders <Warning /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Warning message="Warning message" />).toJSON();
|
||||||
.create(
|
|
||||||
<Warning message='Warning message'/>
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -9,10 +9,6 @@ import 'jest-styled-components';
|
|||||||
import Title from '@components/navigation/title';
|
import Title from '@components/navigation/title';
|
||||||
|
|
||||||
it('renders <Title /> without throwing', () => {
|
it('renders <Title /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Title />).toJSON();
|
||||||
.create(
|
|
||||||
<Title />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -10,10 +10,6 @@ import { service } from '../../mocks';
|
|||||||
import Delete from '@components/service/delete';
|
import Delete from '@components/service/delete';
|
||||||
|
|
||||||
it('renders <Delete /> without throwing', () => {
|
it('renders <Delete /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer.create(<Delete service={service} />).toJSON();
|
||||||
.create(
|
|
||||||
<Delete service={service} />
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -23,9 +22,7 @@ it('renders <ServiceListItem /> without throwing', () => {
|
|||||||
|
|
||||||
it('renders child <ServiceListItem /> without throwing', () => {
|
it('renders child <ServiceListItem /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(<ServiceListItem service={service} isChild />)
|
||||||
<ServiceListItem service={service} isChild />
|
|
||||||
)
|
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -12,9 +11,7 @@ import { service } from '../../mocks';
|
|||||||
|
|
||||||
xit('renders <ServiceStatus /> without throwing', () => {
|
xit('renders <ServiceStatus /> without throwing', () => {
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(<ServiceStatus instanceStatuses={service.instanceStatuses} />)
|
||||||
<ServiceStatus instanceStatuses={service.instanceStatuses} />
|
|
||||||
)
|
|
||||||
.toJSON();
|
.toJSON();
|
||||||
expect(tree).toMatchSnapshot();
|
expect(tree).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -17,12 +16,12 @@ it('renders <DeploymentGroupCreate /> without throwing', () => {
|
|||||||
stage: ''
|
stage: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(
|
||||||
<Store>
|
<Store>
|
||||||
<Router>
|
<Router>
|
||||||
<DeploymentGroupCreate { ...props } />
|
<DeploymentGroupCreate {...props} />
|
||||||
</Router>
|
</Router>
|
||||||
</Store>
|
</Store>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -15,12 +14,12 @@ it('renders <Breadcrumb /> without throwing', () => {
|
|||||||
location: {
|
location: {
|
||||||
pathname: ''
|
pathname: ''
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(
|
||||||
<Store>
|
<Store>
|
||||||
<Router>
|
<Router>
|
||||||
<Breadcrumb { ...props } />
|
<Breadcrumb {...props} />
|
||||||
</Router>
|
</Router>
|
||||||
</Store>
|
</Store>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -15,10 +14,7 @@ it('renders <ServiceList /> without throwing', () => {
|
|||||||
.create(
|
.create(
|
||||||
<Store>
|
<Store>
|
||||||
<Router>
|
<Router>
|
||||||
<ServiceList
|
<ServiceList deploymentGroup={deploymentGroup} services={services} />
|
||||||
deploymentGroup={deploymentGroup}
|
|
||||||
services={services}
|
|
||||||
/>
|
|
||||||
</Router>
|
</Router>
|
||||||
</Store>
|
</Store>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -18,12 +17,12 @@ it('renders <ServicesMenu /> without throwing', () => {
|
|||||||
history: {
|
history: {
|
||||||
push: () => {}
|
push: () => {}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const tree = renderer
|
const tree = renderer
|
||||||
.create(
|
.create(
|
||||||
<Store>
|
<Store>
|
||||||
<Router>
|
<Router>
|
||||||
<ServicesMenu { ...props } />
|
<ServicesMenu {...props} />
|
||||||
</Router>
|
</Router>
|
||||||
</Store>
|
</Store>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @jest-environment jsdom
|
* @jest-environment jsdom
|
||||||
*/
|
*/
|
||||||
@ -15,9 +14,7 @@ it('renders <ServicesTopology /> without throwing', () => {
|
|||||||
.create(
|
.create(
|
||||||
<Store>
|
<Store>
|
||||||
<Router>
|
<Router>
|
||||||
<ServicesTopology
|
<ServicesTopology services={services} />
|
||||||
services={services}
|
|
||||||
/>
|
|
||||||
</Router>
|
</Router>
|
||||||
</Store>
|
</Store>
|
||||||
)
|
)
|
||||||
|
@ -1,37 +1,31 @@
|
|||||||
export const instance = {
|
export const instance = {
|
||||||
"id": "309ecd9f-ac03-474b-aff7-4bd2e743296c",
|
id: '309ecd9f-ac03-474b-aff7-4bd2e743296c',
|
||||||
"name": "wordpress_01",
|
name: 'wordpress_01',
|
||||||
"serviceId": "be227788-74f1-4e5b-a85f-b5c71cbae8d8",
|
serviceId: 'be227788-74f1-4e5b-a85f-b5c71cbae8d8',
|
||||||
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
|
deploymentGroupId: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
|
||||||
"machineId": "011f7479-2d45-442d-99bf-7f6216954cc8",
|
machineId: '011f7479-2d45-442d-99bf-7f6216954cc8',
|
||||||
"status": "RUNNING",
|
status: 'RUNNING',
|
||||||
"healthy": "HEALTHY"
|
healthy: 'HEALTHY'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const service = {
|
export const service = {
|
||||||
"id": "081a792c-47e0-4439-924b-2efa9788ae9e",
|
id: '081a792c-47e0-4439-924b-2efa9788ae9e',
|
||||||
"slug": "nginx",
|
slug: 'nginx',
|
||||||
"name": "Nginx",
|
name: 'Nginx',
|
||||||
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
|
deploymentGroupId: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
|
||||||
"connections": ["be227788-74f1-4e5b-a85f-b5c71cbae8d8"],
|
connections: ['be227788-74f1-4e5b-a85f-b5c71cbae8d8'],
|
||||||
"instances": [instance],
|
instances: [instance],
|
||||||
"instanceStatuses": [{ status: "RUNNING", count: 1 }]
|
instanceStatuses: [{ status: 'RUNNING', count: 1 }]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deploymentGroup = {
|
export const deploymentGroup = {
|
||||||
"id": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
|
id: 'e0ea0c02-55cc-45fe-8064-3e5176a59401',
|
||||||
"slug": "wordpress-blog-example",
|
slug: 'wordpress-blog-example',
|
||||||
"name": "Wordpress Blog Example"
|
name: 'Wordpress Blog Example'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const services = [
|
export const services = [service];
|
||||||
service
|
|
||||||
];
|
|
||||||
|
|
||||||
export const instances = [
|
export const instances = [instance];
|
||||||
instance
|
|
||||||
];
|
|
||||||
|
|
||||||
export const deploymentGroups = [
|
export const deploymentGroups = [deploymentGroup];
|
||||||
deploymentGroup
|
|
||||||
]
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
|
||||||
export default ({ children }) =>
|
export default ({ children }) => <MemoryRouter>{children}</MemoryRouter>;
|
||||||
<MemoryRouter>
|
|
||||||
{children}
|
|
||||||
</MemoryRouter>;
|
|
||||||
|
@ -2,7 +2,8 @@ import React from 'react';
|
|||||||
import { client, store } from '@state/store';
|
import { client, store } from '@state/store';
|
||||||
import { ApolloProvider } from 'react-apollo';
|
import { ApolloProvider } from 'react-apollo';
|
||||||
|
|
||||||
export default ({ children }) =>
|
export default ({ children }) => (
|
||||||
<ApolloProvider client={client} store={store}>
|
<ApolloProvider client={client} store={store}>
|
||||||
{children}
|
{children}
|
||||||
</ApolloProvider>;
|
</ApolloProvider>
|
||||||
|
);
|
||||||
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import { ThemeProvider } from 'styled-components';
|
import { ThemeProvider } from 'styled-components';
|
||||||
import { theme } from 'joyent-ui-toolkit';
|
import { theme } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
export default ({ children }) =>
|
export default ({ children }) => (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>{children}</ThemeProvider>
|
||||||
{children}
|
);
|
||||||
</ThemeProvider>;
|
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
import state from '@state/state';
|
import state from '@state/state';
|
||||||
|
|
||||||
describe('ui reducer', () => {
|
describe('ui reducer', () => {
|
||||||
|
|
||||||
it('toggleServicesQuickActions shows correctly', () => {
|
it('toggleServicesQuickActions shows correctly', () => {
|
||||||
const uiState = state.ui;
|
const uiState = state.ui;
|
||||||
const expectedUiState = {
|
const expectedUiState = {
|
||||||
@ -23,17 +22,19 @@ describe('ui reducer', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const action = { payload: {
|
const action = {
|
||||||
show: true,
|
payload: {
|
||||||
position: {
|
show: true,
|
||||||
top: 10,
|
position: {
|
||||||
left: 10
|
top: 10,
|
||||||
},
|
left: 10
|
||||||
service: {
|
},
|
||||||
id: 'service-id'
|
service: {
|
||||||
|
id: 'service-id'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}};
|
};
|
||||||
const result = _toggleServicesQuickActions(uiState, action);
|
const result = _toggleServicesQuickActions(uiState, action);
|
||||||
expect(result).toEqual(expectedUiState);
|
expect(result).toEqual(expectedUiState);
|
||||||
});
|
});
|
||||||
@ -48,8 +49,8 @@ describe('ui reducer', () => {
|
|||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const action = { payload: { show: false }};
|
const action = { payload: { show: false } };
|
||||||
const result = _toggleServicesQuickActions(uiState, action);
|
const result = _toggleServicesQuickActions(uiState, action);
|
||||||
expect(result).toEqual(expectedUiState);
|
expect(result).toEqual(expectedUiState);
|
||||||
});
|
});
|
||||||
@ -72,18 +73,20 @@ describe('ui reducer', () => {
|
|||||||
type: 'healthy'
|
type: 'healthy'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const action = { payload: {
|
const action = {
|
||||||
show: true,
|
payload: {
|
||||||
position: {
|
show: true,
|
||||||
top: 10,
|
position: {
|
||||||
left: 10
|
top: 10,
|
||||||
},
|
left: 10
|
||||||
instance: {
|
},
|
||||||
id: 'instance-id'
|
instance: {
|
||||||
},
|
id: 'instance-id'
|
||||||
type: 'healthy'
|
},
|
||||||
}};
|
type: 'healthy'
|
||||||
|
}
|
||||||
|
};
|
||||||
const result = _toggleInstancesTooltip(uiState, action);
|
const result = _toggleInstancesTooltip(uiState, action);
|
||||||
expect(result).toEqual(expectedUiState);
|
expect(result).toEqual(expectedUiState);
|
||||||
});
|
});
|
||||||
@ -98,9 +101,9 @@ describe('ui reducer', () => {
|
|||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const action = { payload: { show: false }};
|
const action = { payload: { show: false } };
|
||||||
const result = _toggleInstancesTooltip(uiState, action);
|
const result = _toggleInstancesTooltip(uiState, action);
|
||||||
expect(result).toEqual(expectedUiState);
|
expect(result).toEqual(expectedUiState);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
@ -10,48 +10,45 @@ import {
|
|||||||
} from '@state/selectors';
|
} from '@state/selectors';
|
||||||
|
|
||||||
describe('Redux selectors and Apollo helpers', () => {
|
describe('Redux selectors and Apollo helpers', () => {
|
||||||
|
|
||||||
describe('getInstanceStatuses', () => {
|
describe('getInstanceStatuses', () => {
|
||||||
|
|
||||||
it('gathers instance statuses correctly', () => {
|
it('gathers instance statuses correctly', () => {
|
||||||
const service = {
|
const service = {
|
||||||
instances: [
|
instances: [
|
||||||
{ status: 'RUNNING' },
|
{ status: 'RUNNING' },
|
||||||
{ status: 'RUNNING' },
|
{ status: 'RUNNING' },
|
||||||
{ status: 'READY' },
|
{ status: 'READY' },
|
||||||
{ status: 'RUNNING' },
|
{ status: 'RUNNING' },
|
||||||
{ status: 'INCOMPLETE' },
|
{ status: 'INCOMPLETE' },
|
||||||
{ status: 'READY' },
|
{ status: 'READY' },
|
||||||
{ status: 'OFFLINE' },
|
{ status: 'OFFLINE' },
|
||||||
{ status: 'STOPPED' },
|
{ status: 'STOPPED' },
|
||||||
{ status: 'STOPPED' },
|
{ status: 'STOPPED' },
|
||||||
{ status: 'RUNNING' }
|
{ status: 'RUNNING' }
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
const expectedResult = [
|
const expectedResult = [
|
||||||
{ status: 'RUNNING', count: 4 },
|
{ status: 'RUNNING', count: 4 },
|
||||||
{ status: 'READY', count: 2 },
|
{ status: 'READY', count: 2 },
|
||||||
{ status: 'INCOMPLETE', count: 1 },
|
{ status: 'INCOMPLETE', count: 1 },
|
||||||
{ status: 'OFFLINE', count: 1 },
|
{ status: 'OFFLINE', count: 1 },
|
||||||
{ status: 'STOPPED', count: 2 }
|
{ status: 'STOPPED', count: 2 }
|
||||||
];
|
];
|
||||||
const result = getInstanceStatuses(service);
|
const result = getInstanceStatuses(service);
|
||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not throw a hissy fit if there are no instances', () => {
|
it('does not throw a hissy fit if there are no instances', () => {
|
||||||
const service = {
|
const service = {
|
||||||
instances: []
|
instances: []
|
||||||
};
|
};
|
||||||
const expectedResult = [];
|
const expectedResult = [];
|
||||||
const result = getInstanceStatuses(service);
|
const result = getInstanceStatuses(service);
|
||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getInstancesActive', () => {
|
describe('getInstancesActive', () => {
|
||||||
|
it("returns true if all instances' status is active", () => {
|
||||||
it('returns true if all instances\' status is active', () => {
|
|
||||||
const statuses = [
|
const statuses = [
|
||||||
{ status: 'RUNNING' },
|
{ status: 'RUNNING' },
|
||||||
{ status: 'READY' },
|
{ status: 'READY' },
|
||||||
@ -63,7 +60,7 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns false if no instances\' status is active', () => {
|
it("returns false if no instances' status is active", () => {
|
||||||
const statuses = [
|
const statuses = [
|
||||||
{ status: 'STOPPING' },
|
{ status: 'STOPPING' },
|
||||||
{ status: 'FAILED' },
|
{ status: 'FAILED' },
|
||||||
@ -75,7 +72,7 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns true if some instances\' status is active', () => {
|
it("returns true if some instances' status is active", () => {
|
||||||
const statuses = [
|
const statuses = [
|
||||||
{ status: 'STOPPING' },
|
{ status: 'STOPPING' },
|
||||||
{ status: 'FAILED' },
|
{ status: 'FAILED' },
|
||||||
@ -89,7 +86,6 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getInstancesHealthy', () => {
|
describe('getInstancesHealthy', () => {
|
||||||
|
|
||||||
it('returns the number of healthy instances correctly', () => {
|
it('returns the number of healthy instances correctly', () => {
|
||||||
const instances = [
|
const instances = [
|
||||||
{ healthy: 'HEALTHY' },
|
{ healthy: 'HEALTHY' },
|
||||||
@ -106,39 +102,31 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getService', () => {
|
describe('getService', () => {
|
||||||
|
|
||||||
it('returns the service decorated with details for display correctly', () => {
|
it('returns the service decorated with details for display correctly', () => {
|
||||||
|
|
||||||
const result = getService(nginxService, 0);
|
const result = getService(nginxService, 0);
|
||||||
expect(result).toEqual(nginxExpectedResult);
|
expect(result).toEqual(nginxExpectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the consul service decorated with details for display correctly', () => {
|
it('returns the consul service decorated with details for display correctly', () => {
|
||||||
|
|
||||||
const result = getService(consulService, 1);
|
const result = getService(consulService, 1);
|
||||||
expect(result).toEqual(consulExpectedResult);
|
expect(result).toEqual(consulExpectedResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('processServices', () => {
|
describe('processServices', () => {
|
||||||
|
|
||||||
it('returns the services decorated with details for display correctly', () => {
|
it('returns the services decorated with details for display correctly', () => {
|
||||||
const services = [
|
const services = [nginxService, consulService];
|
||||||
nginxService,
|
const expectedResult = [nginxExpectedResult, consulExpectedResult];
|
||||||
consulService
|
|
||||||
];
|
|
||||||
const expectedResult = [
|
|
||||||
nginxExpectedResult,
|
|
||||||
consulExpectedResult
|
|
||||||
];
|
|
||||||
const result = processServices(services);
|
const result = processServices(services);
|
||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removes deleted services', () => {
|
it('removes deleted services', () => {
|
||||||
const services = [{
|
const services = [
|
||||||
status: 'DELETED'
|
{
|
||||||
}];
|
status: 'DELETED'
|
||||||
|
}
|
||||||
|
];
|
||||||
const expectedResult = [];
|
const expectedResult = [];
|
||||||
const result = processServices(services);
|
const result = processServices(services);
|
||||||
expect(result).toEqual(expectedResult);
|
expect(result).toEqual(expectedResult);
|
||||||
@ -146,16 +134,12 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('processServicesForTopology', () => {
|
describe('processServicesForTopology', () => {
|
||||||
|
|
||||||
it('returns the services decorated with details for display correctly', () => {
|
it('returns the services decorated with details for display correctly', () => {
|
||||||
const services = [
|
const services = [
|
||||||
{
|
{
|
||||||
...nginxService,
|
...nginxService,
|
||||||
id: 'nginx-service-0',
|
id: 'nginx-service-0',
|
||||||
connections: [
|
connections: ['consul-service-0', 'consul-service-1']
|
||||||
'consul-service-0',
|
|
||||||
'consul-service-1'
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...nginxService,
|
...nginxService,
|
||||||
@ -164,9 +148,7 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
{
|
{
|
||||||
...consulService,
|
...consulService,
|
||||||
id: 'consul-service-0',
|
id: 'consul-service-0',
|
||||||
connections: [
|
connections: ['consul-service-1']
|
||||||
'consul-service-1'
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...consulService,
|
...consulService,
|
||||||
@ -177,10 +159,7 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
{
|
{
|
||||||
...nginxExpectedResult,
|
...nginxExpectedResult,
|
||||||
id: 'nginx-service-0',
|
id: 'nginx-service-0',
|
||||||
connections: [
|
connections: ['consul-service-0', 'consul-service-1'],
|
||||||
'consul-service-0',
|
|
||||||
'consul-service-1'
|
|
||||||
],
|
|
||||||
connected: true,
|
connected: true,
|
||||||
index: 0
|
index: 0
|
||||||
},
|
},
|
||||||
@ -193,9 +172,7 @@ describe('Redux selectors and Apollo helpers', () => {
|
|||||||
{
|
{
|
||||||
...consulExpectedResult,
|
...consulExpectedResult,
|
||||||
id: 'consul-service-0',
|
id: 'consul-service-0',
|
||||||
connections: [
|
connections: ['consul-service-1'],
|
||||||
'consul-service-1'
|
|
||||||
],
|
|
||||||
connected: true,
|
connected: true,
|
||||||
index: 2
|
index: 2
|
||||||
},
|
},
|
||||||
|
@ -48,12 +48,8 @@
|
|||||||
"tap-xunit": "^1.7.0"
|
"tap-xunit": "^1.7.0"
|
||||||
},
|
},
|
||||||
"ava": {
|
"ava": {
|
||||||
"files": [
|
"files": ["test/*.js"],
|
||||||
"test/*.js"
|
"source": ["src/*.js"],
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"src/*.js"
|
|
||||||
],
|
|
||||||
"failFast": true
|
"failFast": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,8 +268,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"id": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
||||||
"slug": "extra service reported by containerpilot: redbaloonservice-https",
|
"slug":
|
||||||
"name": "Extra service reported by ContainerPilot: RedBaloonService-HTTPS",
|
"extra service reported by containerpilot: redbaloonservice-https",
|
||||||
|
"name":
|
||||||
|
"Extra service reported by ContainerPilot: RedBaloonService-HTTPS",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"status": "ACTIVE"
|
"status": "ACTIVE"
|
||||||
},
|
},
|
||||||
@ -578,7 +580,8 @@
|
|||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
||||||
"machineId": "c9a49cff-4438-460f-bc46-610bfecbddca",
|
"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",
|
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-1",
|
||||||
@ -587,7 +590,8 @@
|
|||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
||||||
"machineId": "4252ddb5-e9b4-4d1e-aa53-6e1bdcdeab30",
|
"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",
|
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-2",
|
||||||
@ -596,7 +600,8 @@
|
|||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
||||||
"machineId": "783c5eb2-2145-4fd2-a22f-274bec3b2ffc",
|
"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",
|
"id": "instance-31663285-2b58-4f92-b6f5-3ef34591c3a3-3",
|
||||||
@ -605,7 +610,8 @@
|
|||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
"serviceId": "31663285-2b58-4f92-b6f5-3ef34591c3a3",
|
||||||
"machineId": "f8a54a11-93f4-4b0a-9c80-be6542393448",
|
"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",
|
"id": "instance-3b954132-49fc-405c-9d91-c59b8953d7b8-0",
|
||||||
@ -1747,7 +1753,8 @@
|
|||||||
"healthy": "UNKNOWN",
|
"healthy": "UNKNOWN",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"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"
|
"machineId": "20f5bf63-c7d7-4b80-bbe0-63dd744f1b72"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1756,7 +1763,8 @@
|
|||||||
"healthy": "UNKNOWN",
|
"healthy": "UNKNOWN",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"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"
|
"machineId": "bf10d972-17e0-4267-908e-4a8184d7c164"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1765,7 +1773,8 @@
|
|||||||
"healthy": "UNKNOWN",
|
"healthy": "UNKNOWN",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"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"
|
"machineId": "d7204a39-5005-4925-a2d5-02afbb2457db"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1774,7 +1783,8 @@
|
|||||||
"healthy": "UNKNOWN",
|
"healthy": "UNKNOWN",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"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"
|
"machineId": "80dac6f7-e459-4f42-b824-5abdd6f13d41"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1783,7 +1793,8 @@
|
|||||||
"healthy": "UNKNOWN",
|
"healthy": "UNKNOWN",
|
||||||
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
"deploymentGroupId": "ba217234-9b1b-41a7-8079-08f9a4aadb0f",
|
||||||
"serviceId": "1ad6dd4e-15bd-4ea5-a0db-bf071d7958c4",
|
"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"
|
"machineId": "dbb819d5-9df2-48e1-8412-7cd48ca4c186"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -53,4 +53,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -34466,4 +34466,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -34490,4 +34490,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -22993,4 +22993,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -48,17 +48,11 @@ const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q));
|
|||||||
let metricDataIndex = 0;
|
let metricDataIndex = 0;
|
||||||
|
|
||||||
const getMetrics = query => {
|
const getMetrics = query => {
|
||||||
const {
|
const { names, start, end, instanceId } = query;
|
||||||
names,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
instanceId
|
|
||||||
} = query;
|
|
||||||
|
|
||||||
const metrics = names.reduce((metrics, name) => {
|
const metrics = names.reduce((metrics, name) => {
|
||||||
|
|
||||||
// pick one of the three metric data jsons, so there's variety
|
// pick one of the three metric data jsons, so there's variety
|
||||||
const index = metricDataIndex%metricData.length;
|
const index = metricDataIndex % metricData.length;
|
||||||
metricDataIndex++;
|
metricDataIndex++;
|
||||||
|
|
||||||
const md = metricData[index].find(md => md.name === name);
|
const md = metricData[index].find(md => md.name === name);
|
||||||
@ -69,17 +63,20 @@ const getMetrics = query => {
|
|||||||
|
|
||||||
// how many records do we need?
|
// how many records do we need?
|
||||||
const duration = e.diff(s); // duration for which we need data
|
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 = [];
|
const requiredMetrics = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const time = moment(s);
|
const time = moment(s);
|
||||||
// start at a random point within the dataset for variety
|
// start at a random point within the dataset for variety
|
||||||
const randomIndex = Math.round(Math.random() * m.length);
|
const randomIndex = Math.round(Math.random() * m.length);
|
||||||
while(i < records) {
|
while (i < records) {
|
||||||
const index = (randomIndex + i)%m.length; // loop if not enough data
|
const index = (randomIndex + i) % m.length; // loop if not enough data
|
||||||
const requiredMetric = m[index];
|
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);
|
requiredMetrics.push(requiredMetric);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -90,13 +87,13 @@ const getMetrics = query => {
|
|||||||
start: s.utc().format(),
|
start: s.utc().format(),
|
||||||
end: time.utc().format(), // this will be used by the frontend for the next fetch
|
end: time.utc().format(), // this will be used by the frontend for the next fetch
|
||||||
metrics: requiredMetrics
|
metrics: requiredMetrics
|
||||||
}
|
};
|
||||||
metrics.push(requiredMetricData);
|
metrics.push(requiredMetricData);
|
||||||
return metrics;
|
return metrics;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return Promise.resolve(metrics);
|
return Promise.resolve(metrics);
|
||||||
}
|
};
|
||||||
|
|
||||||
const getInstances = query => {
|
const getInstances = query => {
|
||||||
const metricsResolver = ({ id }) => query =>
|
const metricsResolver = ({ id }) => query =>
|
||||||
@ -175,13 +172,12 @@ const getServices = query => {
|
|||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve(services)
|
return Promise.resolve(services).then(services => {
|
||||||
.then((services) => {
|
if (!services || !services.length) {
|
||||||
if(!services || !services.length) {
|
throw Boom.notFound();
|
||||||
throw Boom.notFound();
|
}
|
||||||
}
|
return services;
|
||||||
return services;
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDeploymentGroups = query => {
|
const getDeploymentGroups = query => {
|
||||||
@ -199,8 +195,8 @@ const getDeploymentGroups = query => {
|
|||||||
|
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
deploymentGroups.filter(find(cleanQuery(query))).map(addNestedResolvers)
|
deploymentGroups.filter(find(cleanQuery(query))).map(addNestedResolvers)
|
||||||
).then((deploymentGroups) => {
|
).then(deploymentGroups => {
|
||||||
if(!deploymentGroups || !deploymentGroups.length) {
|
if (!deploymentGroups || !deploymentGroups.length) {
|
||||||
throw Boom.notFound();
|
throw Boom.notFound();
|
||||||
}
|
}
|
||||||
return deploymentGroups;
|
return deploymentGroups;
|
||||||
@ -406,11 +402,16 @@ const updateServiceAndInstancesStatus = (
|
|||||||
instancesStatus
|
instancesStatus
|
||||||
) => {
|
) => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
getServices({ id: serviceId })/* ,
|
getServices({
|
||||||
|
id: serviceId
|
||||||
|
}) /* ,
|
||||||
getServices({ parentId: serviceId }) */
|
getServices({ parentId: serviceId }) */
|
||||||
])
|
])
|
||||||
.then(services => {
|
.then(services => {
|
||||||
return services.reduce((services, service) => services.concat(service), [])
|
return services.reduce(
|
||||||
|
(services, service) => services.concat(service),
|
||||||
|
[]
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.then(services => {
|
.then(services => {
|
||||||
updateServiceStatus(services, serviceStatus);
|
updateServiceStatus(services, serviceStatus);
|
||||||
@ -431,7 +432,9 @@ const updateServiceAndInstancesStatus = (
|
|||||||
})
|
})
|
||||||
.then(() =>
|
.then(() =>
|
||||||
Promise.all([
|
Promise.all([
|
||||||
getUnfilteredServices({ id: serviceId })/* ,
|
getUnfilteredServices({
|
||||||
|
id: serviceId
|
||||||
|
}) /* ,
|
||||||
getUnfilteredServices({ parentId: serviceId }) */
|
getUnfilteredServices({ parentId: serviceId }) */
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@ -536,12 +539,7 @@ const parseEnvVars = (str = '') =>
|
|||||||
const findEnvInterpolation = (str = '') =>
|
const findEnvInterpolation = (str = '') =>
|
||||||
uniq(str.match(INTERPOLATE_REGEX).map(name => name.replace(/^\$/, '')));
|
uniq(str.match(INTERPOLATE_REGEX).map(name => name.replace(/^\$/, '')));
|
||||||
|
|
||||||
const config = ({
|
const config = ({ environment = '', files = [], raw = '', _plain = false }) => {
|
||||||
environment = '',
|
|
||||||
files = [],
|
|
||||||
raw = '',
|
|
||||||
_plain = false
|
|
||||||
}) => {
|
|
||||||
const interpolatableNames = findEnvInterpolation(raw);
|
const interpolatableNames = findEnvInterpolation(raw);
|
||||||
const interpolatableEnv = parseEnvVars(environment);
|
const interpolatableEnv = parseEnvVars(environment);
|
||||||
|
|
||||||
@ -588,11 +586,10 @@ const config = ({
|
|||||||
config: Object.assign(service.config, {
|
config: Object.assign(service.config, {
|
||||||
id: hasha(JSON.stringify(service.config)),
|
id: hasha(JSON.stringify(service.config)),
|
||||||
environment: Object.keys(service.config.environment).map(name => ({
|
environment: Object.keys(service.config.environment).map(name => ({
|
||||||
name,
|
name,
|
||||||
id: hasha(JSON.stringify(service.config.environment[name])),
|
id: hasha(JSON.stringify(service.config.environment[name])),
|
||||||
value: service.config.environment[name]
|
value: service.config.environment[name]
|
||||||
})
|
}))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -203,7 +203,6 @@ type Datacenter {
|
|||||||
region: String!
|
region: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# we probably wont use some of these queries or arguments
|
# we probably wont use some of these queries or arguments
|
||||||
# but this way we expose the entire db through gql
|
# but this way we expose the entire db through gql
|
||||||
type Query {
|
type Query {
|
||||||
@ -265,7 +264,13 @@ type Query {
|
|||||||
): [Service]
|
): [Service]
|
||||||
importableDeploymentGroups: [DeploymentGroup]
|
importableDeploymentGroups: [DeploymentGroup]
|
||||||
# start and end should be .toISOString() date strings
|
# 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 {
|
type Mutation {
|
||||||
|
@ -152,17 +152,17 @@ export const Button = styled.button`
|
|||||||
appearance: button;
|
appearance: button;
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
&::-moz-focus-inner,
|
||||||
&[type="button"]::-moz-focus-inner,
|
&[type='button']::-moz-focus-inner,
|
||||||
&[type="reset"]::-moz-focus-inner,
|
&[type='reset']::-moz-focus-inner,
|
||||||
&[type="submit"]::-moz-focus-inner {
|
&[type='submit']::-moz-focus-inner {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:-moz-focusring,
|
&:-moz-focusring,
|
||||||
&[type="button"]:-moz-focusring,
|
&[type='button']:-moz-focusring,
|
||||||
&[type="reset"]:-moz-focusring,
|
&[type='reset']:-moz-focusring,
|
||||||
&[type="submit"]:-moz-focusring {
|
&[type='submit']:-moz-focusring {
|
||||||
outline: ${remcalc(1)} dotted ButtonText;
|
outline: ${remcalc(1)} dotted ButtonText;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -174,24 +174,24 @@ export const Input = styled.input`
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
&[type="checkbox"],
|
&[type='checkbox'],
|
||||||
&[type="radio"] {
|
&[type='radio'] {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type="number"]::-webkit-inner-spin-button,
|
&[type='number']::-webkit-inner-spin-button,
|
||||||
&[type="number"]::-webkit-outer-spin-button {
|
&[type='number']::-webkit-outer-spin-button {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type="search"] {
|
&[type='search'] {
|
||||||
appearance: textfield;
|
appearance: textfield;
|
||||||
outline-offset: ${remcalc(-2)};
|
outline-offset: ${remcalc(-2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type="search"]::-webkit-search-cancel-button,
|
&[type='search']::-webkit-search-cancel-button,
|
||||||
&[type="search"]::-webkit-search-decoration {
|
&[type='search']::-webkit-search-decoration {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,7 @@ const Anchor = ({ children, ...rest }) => {
|
|||||||
const Views = [() => (to ? StyledLink : null), () => StyledAnchor];
|
const Views = [() => (to ? StyledLink : null), () => StyledAnchor];
|
||||||
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
||||||
|
|
||||||
return (
|
return <View {...rest}>{children}</View>;
|
||||||
<View {...rest}>
|
|
||||||
{children}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Anchor.propTypes = {
|
Anchor.propTypes = {
|
||||||
|
@ -21,6 +21,6 @@ export default css`
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: ${theme.background};
|
background: ${theme.background};
|
||||||
font-family: 'Libre Franklin'
|
font-family: 'Libre Franklin';
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -18,4 +18,6 @@ export default Component =>
|
|||||||
? Component.extend`
|
? Component.extend`
|
||||||
${alignsFromProps};
|
${alignsFromProps};
|
||||||
`
|
`
|
||||||
: styled(Component)`${alignsFromProps}`;
|
: styled(Component)`
|
||||||
|
${alignsFromProps};
|
||||||
|
`;
|
||||||
|
@ -33,4 +33,6 @@ export default Component =>
|
|||||||
? Component.extend`
|
? Component.extend`
|
||||||
${unitsFromProps};
|
${unitsFromProps};
|
||||||
`
|
`
|
||||||
: styled(Component)`${unitsFromProps}`;
|
: styled(Component)`
|
||||||
|
${unitsFromProps};
|
||||||
|
`;
|
||||||
|
@ -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 modalShadow = `0 0 ${remcalc(6)} ${remcalc(1)} rgba(0, 0, 0, 0.1)`;
|
||||||
|
|
||||||
export const border = {
|
export const border = {
|
||||||
checked: css`${remcalc(1)} solid ${props => props.theme.primary}`,
|
checked: css`${remcalc(1)} solid ${props => props.theme.primary};`,
|
||||||
unchecked: css`${remcalc(1)} solid ${props => props.theme.grey}`,
|
unchecked: css`${remcalc(1)} solid ${props => props.theme.grey};`,
|
||||||
confirmed: 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}`,
|
error: css`${remcalc(1)} solid ${props => props.theme.red};`,
|
||||||
secondary: css`${remcalc(1)} solid ${props => props.theme.secondaryActive}`,
|
secondary: css`${remcalc(1)} solid ${props => props.theme.secondaryActive};`
|
||||||
};
|
};
|
||||||
|
@ -4,9 +4,10 @@ import { Row } from 'react-styled-flexboxgrid';
|
|||||||
/**
|
/**
|
||||||
* @example ./usage.md
|
* @example ./usage.md
|
||||||
*/
|
*/
|
||||||
export default ({ children, ...rest }) =>
|
export default ({ children, ...rest }) => (
|
||||||
<Row name="breadcrum" {...rest}>
|
<Row name="breadcrum" {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</Row>;
|
</Row>
|
||||||
|
);
|
||||||
|
|
||||||
export { default as Item } from './item';
|
export { default as Item } from './item';
|
||||||
|
@ -21,10 +21,11 @@ const Arrow = styled.div`
|
|||||||
margin: ${remcalc(3)} ${remcalc(10)} ${remcalc(3)} ${remcalc(10)};
|
margin: ${remcalc(3)} ${remcalc(10)} ${remcalc(3)} ${remcalc(10)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default ({ children, ...rest }) =>
|
export default ({ children, ...rest }) => (
|
||||||
<div>
|
<div>
|
||||||
<Name name="breadcrum-item" {...rest}>
|
<Name name="breadcrum-item" {...rest}>
|
||||||
{children}
|
{children}
|
||||||
</Name>
|
</Name>
|
||||||
<Arrow />
|
<Arrow />
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user