feat(ui-toolkit, cp-fronted, portal-api): Env variables input redesign
This commit is contained in:
parent
2eb7f4197f
commit
2fb4a77c96
@ -27,9 +27,13 @@
|
|||||||
"jest-cli": "^20.0.4",
|
"jest-cli": "^20.0.4",
|
||||||
"joyent-manifest-editor": "^1.0.0",
|
"joyent-manifest-editor": "^1.0.0",
|
||||||
"joyent-ui-toolkit": "^1.1.0",
|
"joyent-ui-toolkit": "^1.1.0",
|
||||||
|
"js-yaml": "^3.9.1",
|
||||||
|
"lodash.find": "^4.6.0",
|
||||||
|
"lodash.flatten": "^4.4.0",
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"lodash.isstring": "^4.0.1",
|
"lodash.isstring": "^4.0.1",
|
||||||
"lodash.remove": "^4.7.0",
|
"lodash.remove": "^4.7.0",
|
||||||
|
"lodash.uniq": "^4.5.0",
|
||||||
"normalized-styled-components": "^1.0.8",
|
"normalized-styled-components": "^1.0.8",
|
||||||
"param-case": "^2.1.1",
|
"param-case": "^2.1.1",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
border: solid 1px #d8d8d8;
|
border: solid 1px #d8d8d8;
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body, #root {
|
html, body, #root {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Field } from 'redux-form';
|
import { Field } from 'redux-form';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import SimpleTable from 'react-simple-table';
|
|
||||||
import { Row, Col } from 'react-styled-flexboxgrid';
|
import { Row, Col } from 'react-styled-flexboxgrid';
|
||||||
import Bundle from 'react-bundle';
|
import Bundle from 'react-bundle';
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
import forceArray from 'force-array';
|
import forceArray from 'force-array';
|
||||||
|
import is from 'styled-is';
|
||||||
|
|
||||||
import { Loader } from '@components/messaging';
|
import { Loader } from '@components/messaging';
|
||||||
|
|
||||||
@ -19,36 +19,56 @@ import {
|
|||||||
ProgressbarItem,
|
ProgressbarItem,
|
||||||
ProgressbarButton,
|
ProgressbarButton,
|
||||||
H3,
|
H3,
|
||||||
|
P,
|
||||||
typography,
|
typography,
|
||||||
StatusLoader
|
Divider,
|
||||||
|
Chevron
|
||||||
} from 'joyent-ui-toolkit';
|
} from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
|
|
||||||
|
const EnvironmentChevron = Chevron.extend`
|
||||||
|
float: right;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const EnvironmentDivider = Divider.extend`
|
||||||
|
margin-top: ${remcalc(34)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ServiceDivider = Divider.extend`
|
||||||
|
margin: ${remcalc(13)} ${remcalc(-20)} 0 ${remcalc(-20)};
|
||||||
|
`;
|
||||||
|
|
||||||
const Dl = styled.dl`
|
const Dl = styled.dl`
|
||||||
margin: ${remcalc(13)} ${remcalc(19)};
|
margin: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ServiceName = H3.extend`
|
const ServiceName = H3.extend`
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: ${remcalc(5)};
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
font-weight: 600;
|
font-size: ${remcalc(18)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ServiceCard = Card.extend`
|
const ImageTitle = H3.extend`
|
||||||
min-height: ${remcalc(72)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ImageTitle = ServiceName.extend`
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Image = styled.span`
|
const Image = styled.span`
|
||||||
${typography.fontFamily};
|
${typography.fontFamily};
|
||||||
|
font-size: ${remcalc(15)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ServiceEnvironmentTitle = P.extend`
|
||||||
|
margin: ${remcalc(13)} 0 0 0;
|
||||||
|
|
||||||
|
${is('expanded')`
|
||||||
|
margin-bottom: ${remcalc(13)};
|
||||||
|
`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ButtonsRow = Row.extend`
|
const ButtonsRow = Row.extend`
|
||||||
margin-top: ${remcalc(29)};
|
margin: ${remcalc(29)} 0 ${remcalc(60)} 0;
|
||||||
margin-bottom: ${remcalc(60)};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FilenameContainer = styled.span`
|
const FilenameContainer = styled.span`
|
||||||
@ -64,17 +84,36 @@ const FilenameInput = styled(Input)`
|
|||||||
order: 0;
|
order: 0;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
|
margin: 0 0 ${remcalc(13)} 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FilenameRemove = Button.extend`
|
const FilenameRemove = Button.extend`
|
||||||
order: 0;
|
order: 0;
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
align-self: auto;
|
align-self: auto;
|
||||||
margin: ${remcalc(8)};
|
margin: 0 0 0 ${remcalc(8)};
|
||||||
margin-right: 0;
|
|
||||||
height: ${remcalc(48)};
|
height: ${remcalc(48)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const FileCard = Card.extend`
|
||||||
|
padding: ${remcalc(24)} ${remcalc(19)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ServiceCard = Card.extend`
|
||||||
|
padding: ${remcalc(13)} ${remcalc(19)};
|
||||||
|
min-height: initial;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Subtitle = H3.extend`
|
||||||
|
margin-top: ${remcalc(34)};
|
||||||
|
margin-bottom: ${remcalc(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Description = P.extend`
|
||||||
|
margin-top: ${remcalc(3)};
|
||||||
|
margin-bottom: ${remcalc(20)};
|
||||||
|
`;
|
||||||
|
|
||||||
class ManifestEditorBundle extends Component {
|
class ManifestEditorBundle extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -112,18 +151,20 @@ class ManifestEditorBundle extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MEditor = ({ input, defaultValue }) =>
|
const MEditor = ({ input, defaultValue, readOnly }) =>
|
||||||
<ManifestEditorBundle
|
<ManifestEditorBundle
|
||||||
mode="yaml"
|
mode="yaml"
|
||||||
{...input}
|
{...input}
|
||||||
value={input.value || defaultValue}
|
value={input.value || defaultValue}
|
||||||
|
readOnly={readOnly}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
const EEditor = ({ input, defaultValue }) =>
|
const EEditor = ({ input, defaultValue, readOnly }) =>
|
||||||
<ManifestEditorBundle
|
<ManifestEditorBundle
|
||||||
mode="ini"
|
mode="ini"
|
||||||
{...input}
|
{...input}
|
||||||
value={input.value || defaultValue}
|
value={input.value || defaultValue}
|
||||||
|
readOnly={readOnly}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
||||||
@ -137,7 +178,7 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<ButtonsRow>
|
<ButtonsRow>
|
||||||
<Button onClick={onCancel} secondary>
|
<Button type="button" onClick={onCancel} secondary>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" disabled={!dirty}>
|
<Button type="submit" disabled={!dirty}>
|
||||||
@ -156,53 +197,74 @@ export const Manifest = ({
|
|||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<Field name="manifest" defaultValue={defaultValue} component={MEditor} />
|
<Field name="manifest" defaultValue={defaultValue} component={MEditor} />
|
||||||
<ButtonsRow>
|
<ButtonsRow>
|
||||||
<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}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
{loading ? <StatusLoader /> : 'Environment'}
|
Environment
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsRow>
|
</ButtonsRow>
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
const Filename = ({ name, onRemoveFile }) =>
|
const File = ({ id, name, value, onRemoveFile, readOnly }) => {
|
||||||
<FilenameContainer>
|
const removeButton = !readOnly
|
||||||
<FilenameInput
|
? <FilenameRemove type="button" onClick={onRemoveFile} secondary>
|
||||||
type="text"
|
Remove
|
||||||
placeholder="Filename including extension…"
|
</FilenameRemove>
|
||||||
defaultValue={name}
|
: null;
|
||||||
/>
|
|
||||||
<FilenameRemove type="button" onClick={onRemoveFile} secondary>
|
|
||||||
Remove
|
|
||||||
</FilenameRemove>
|
|
||||||
</FilenameContainer>;
|
|
||||||
|
|
||||||
export const Files = ({ loading, files, onRemoveFile }) => {
|
const fileEditor = !readOnly
|
||||||
if (loading) {
|
? <Field
|
||||||
return <Loader />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _files = files.map(({ id, name, value }) =>
|
|
||||||
<div key={id}>
|
|
||||||
<FormGroup name={`file-name-${id}`} reduxForm>
|
|
||||||
<FormMeta left />
|
|
||||||
<Filename name={name} onRemoveFile={() => onRemoveFile(id)} />
|
|
||||||
</FormGroup>
|
|
||||||
<Field
|
|
||||||
name={`file-value-${id}`}
|
name={`file-value-${id}`}
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
component={EEditor}
|
component={EEditor}
|
||||||
/>
|
/>
|
||||||
</div>
|
: <EEditor input={{ value }} readOnly />;
|
||||||
|
|
||||||
|
const input = !readOnly
|
||||||
|
? <FilenameInput type="text" placeholder="Filename including extension…" />
|
||||||
|
: <FilenameInput
|
||||||
|
type="text"
|
||||||
|
placeholder="Filename including extension…"
|
||||||
|
value={name}
|
||||||
|
/>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FileCard>
|
||||||
|
<FormGroup name={`file-name-${id}`} reduxForm={!readOnly}>
|
||||||
|
<FilenameContainer>
|
||||||
|
{input}
|
||||||
|
{removeButton}
|
||||||
|
</FilenameContainer>
|
||||||
|
</FormGroup>
|
||||||
|
{fileEditor}
|
||||||
|
</FileCard>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Files = ({ files, onAddFile, onRemoveFile, readOnly }) => {
|
||||||
|
const footer = !readOnly
|
||||||
|
? <Button type="button" onClick={onAddFile} secondary>
|
||||||
|
Create new .env file
|
||||||
|
</Button>
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<H3>Files:</H3>
|
{files.map(({ id, ...rest }) =>
|
||||||
{_files}
|
<File
|
||||||
|
key={id}
|
||||||
|
id={id}
|
||||||
|
onRemoveFile={() => onRemoveFile(id)}
|
||||||
|
readOnly={readOnly}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{footer}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -215,66 +277,101 @@ export const Environment = ({
|
|||||||
dirty,
|
dirty,
|
||||||
defaultValue = '',
|
defaultValue = '',
|
||||||
files = [],
|
files = [],
|
||||||
|
readOnly = false,
|
||||||
loading
|
loading
|
||||||
}) =>
|
}) => {
|
||||||
<form onSubmit={handleSubmit}>
|
const envEditor = !readOnly
|
||||||
<Field name="environment" defaultValue={defaultValue} component={EEditor} />
|
? <Field
|
||||||
<Files files={files} onRemoveFile={onRemoveFile} loading={loading} />
|
name="environment"
|
||||||
<ButtonsRow>
|
defaultValue={defaultValue}
|
||||||
<Button onClick={onCancel} secondary>
|
component={EEditor}
|
||||||
Cancel
|
/>
|
||||||
</Button>
|
: <EEditor input={{ value: defaultValue }} readOnly />;
|
||||||
<Button type="button" onClick={onAddFile} secondary>
|
|
||||||
Add File
|
const footerDivider = !readOnly ? <EnvironmentDivider /> : null;
|
||||||
</Button>
|
|
||||||
<Button
|
const footer = !readOnly
|
||||||
disabled={!(dirty || !loading || defaultValue.length)}
|
? <ButtonsRow>
|
||||||
type="submit"
|
<Button type="button" onClick={onCancel} secondary>
|
||||||
>
|
Cancel
|
||||||
{loading ? <StatusLoader /> : 'Review'}
|
</Button>
|
||||||
</Button>
|
<Button
|
||||||
</ButtonsRow>
|
disabled={!(dirty || !loading || defaultValue.length)}
|
||||||
</form>;
|
loading={loading}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</Button>
|
||||||
|
</ButtonsRow>
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<Subtitle>Global variables</Subtitle>
|
||||||
|
<Description>
|
||||||
|
These variables are going to be availabe for interpolation in the
|
||||||
|
manifest
|
||||||
|
</Description>
|
||||||
|
{envEditor}
|
||||||
|
<EnvironmentDivider />
|
||||||
|
<Subtitle>Enviroment files</Subtitle>
|
||||||
|
<Description>
|
||||||
|
The variables from this files will be applied to the services that
|
||||||
|
require them
|
||||||
|
</Description>
|
||||||
|
<Files
|
||||||
|
files={files}
|
||||||
|
onAddFile={onAddFile}
|
||||||
|
onRemoveFile={onRemoveFile}
|
||||||
|
readOnly={readOnly}
|
||||||
|
/>
|
||||||
|
{footerDivider}
|
||||||
|
{footer}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const EnvironmentReview = ({ environment }) => {
|
||||||
|
const value = environment
|
||||||
|
.map(({ name, value }) => `${name}=${value}`)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
return <EEditor input={{ value }} />;
|
||||||
|
};
|
||||||
|
|
||||||
export const Review = ({
|
export const Review = ({
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
onEnvironmentToggle = () => null,
|
||||||
onCancel,
|
onCancel,
|
||||||
dirty,
|
dirty,
|
||||||
loading,
|
loading,
|
||||||
|
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>
|
||||||
|
{name}
|
||||||
|
</ServiceName>
|
||||||
<Dl>
|
<Dl>
|
||||||
<dt>
|
|
||||||
<ServiceName>
|
|
||||||
{name}
|
|
||||||
</ServiceName>
|
|
||||||
</dt>
|
|
||||||
<dt>
|
<dt>
|
||||||
<ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image>
|
<ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image>
|
||||||
</dt>
|
</dt>
|
||||||
{config.environment.length
|
|
||||||
? <dt>
|
|
||||||
<ImageTitle>Environment:</ImageTitle>
|
|
||||||
</dt>
|
|
||||||
: undefined}
|
|
||||||
{config.environment.length
|
|
||||||
? <SimpleTable
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
columnHeader: 'Name',
|
|
||||||
path: 'name'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
columnHeader: 'Value',
|
|
||||||
path: 'value'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
data={config.environment}
|
|
||||||
/>
|
|
||||||
: undefined}
|
|
||||||
</Dl>
|
</Dl>
|
||||||
|
<ServiceDivider />
|
||||||
|
<ServiceEnvironmentTitle
|
||||||
|
expanded={environmentToggles[name]}
|
||||||
|
onClick={() => onEnvironmentToggle(name)}
|
||||||
|
>
|
||||||
|
Environment variables{' '}
|
||||||
|
<EnvironmentChevron
|
||||||
|
down={!environmentToggles[name]}
|
||||||
|
up={environmentToggles[name]}
|
||||||
|
/>
|
||||||
|
</ServiceEnvironmentTitle>
|
||||||
|
{environmentToggles[name]
|
||||||
|
? <EnvironmentReview environment={config.environment} />
|
||||||
|
: null}
|
||||||
</ServiceCard>
|
</ServiceCard>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -282,11 +379,11 @@ export const Review = ({
|
|||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
{serviceList}
|
{serviceList}
|
||||||
<ButtonsRow>
|
<ButtonsRow>
|
||||||
<Button onClick={onCancel} disabled={loading} secondary>
|
<Button type="button" onClick={onCancel} disabled={loading} secondary>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button disabled={loading} type="submit">
|
<Button disabled={loading} loading={loading} type="submit">
|
||||||
{loading ? <StatusLoader /> : 'Confirm and Deploy'}
|
Confirm and Deploy
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsRow>
|
</ButtonsRow>
|
||||||
</form>
|
</form>
|
||||||
|
@ -2,15 +2,8 @@ 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 = ({
|
const ErrorMessage = ({ title, message = "Ooops, there's been an error" }) =>
|
||||||
title,
|
<Message title={title} message={message} type="ERROR" />;
|
||||||
message = 'Ooops, there\'s been an error'
|
|
||||||
}) =>
|
|
||||||
<Message
|
|
||||||
title={title}
|
|
||||||
message={message}
|
|
||||||
type='ERROR'
|
|
||||||
/>
|
|
||||||
|
|
||||||
ErrorMessage.propTypes = {
|
ErrorMessage.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
@ -2,15 +2,8 @@ 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 = ({
|
const WarningMessage = ({ title, message }) =>
|
||||||
title,
|
<Message title={title} message={message} type="WARNING" />;
|
||||||
message
|
|
||||||
}) =>
|
|
||||||
<Message
|
|
||||||
title={title}
|
|
||||||
message={message}
|
|
||||||
type='WARNING'
|
|
||||||
/>
|
|
||||||
|
|
||||||
WarningMessage.propTypes = {
|
WarningMessage.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
@ -9,13 +9,12 @@ import { Modal, ModalHeading, Button } from 'joyent-ui-toolkit'
|
|||||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
class DeploymentGroupDelete extends Component {
|
class DeploymentGroupDelete extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
error: null
|
error: null
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -40,7 +39,8 @@ class DeploymentGroupDelete extends Component {
|
|||||||
<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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -56,7 +56,8 @@ class DeploymentGroupDelete extends Component {
|
|||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title='Ooops!'
|
||||||
message={`An error occured while attempting to delete the ${deploymentGroup.name} deployment group.`}
|
message={`An error occured while attempting to delete the ${deploymentGroup.name} deployment group.`}
|
||||||
onCloseClick={handleCloseClick} />
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -64,8 +65,7 @@ class DeploymentGroupDelete extends Component {
|
|||||||
const handleConfirmClick = evt => {
|
const handleConfirmClick = evt => {
|
||||||
deleteDeploymentGroup(deploymentGroup.id)
|
deleteDeploymentGroup(deploymentGroup.id)
|
||||||
.then(() => handleCloseClick())
|
.then(() => handleCloseClick())
|
||||||
.catch((err) => {
|
.catch(err => {
|
||||||
console.log('err = ', err);
|
|
||||||
this.setState({ error: err });
|
this.setState({ error: err });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -46,8 +46,9 @@ class DeploymentGroupImport extends Component {
|
|||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
{_title}
|
{_title}
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occurred while importing your deployment groups.' />
|
message="An error occurred while importing your deployment groups."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import { Title } from '@components/navigation';
|
|||||||
import { ErrorMessage, Loader } from '@components/messaging';
|
import { ErrorMessage, Loader } from '@components/messaging';
|
||||||
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
import DeploymentGroupsQuery from '@graphql/DeploymentGroups.gql';
|
||||||
import DeploymentGroupsImportableQuery from '@graphql/DeploymentGroupsImportable.gql';
|
import DeploymentGroupsImportableQuery from '@graphql/DeploymentGroupsImportable.gql';
|
||||||
import { H2, H3, Small, IconButton, BinIcon } from 'joyent-ui-toolkit';
|
import { H3, Small, IconButton, BinIcon } from 'joyent-ui-toolkit';
|
||||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
const DGsRows = Row.extend`
|
const DGsRows = Row.extend`
|
||||||
@ -134,8 +134,9 @@ const DeploymentGroupList = ({
|
|||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
{_title}
|
{_title}
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occured while loading your deployment groups.' />
|
message="An error occured while loading your deployment groups."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
64
packages/cp-frontend/src/containers/environment/index.js
Normal file
64
packages/cp-frontend/src/containers/environment/index.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { compose, graphql } from 'react-apollo';
|
||||||
|
import get from 'lodash.get';
|
||||||
|
|
||||||
|
import ManifestQuery from '@graphql/Manifest.gql';
|
||||||
|
|
||||||
|
import { LayoutContainer } from '@components/layout';
|
||||||
|
import { Title } from '@components/navigation';
|
||||||
|
import { Loader, ErrorMessage, WarningMessage } from '@components/messaging';
|
||||||
|
import { Environment } from '@components/manifest/edit-or-create';
|
||||||
|
|
||||||
|
const EnvironmentReadOnly = ({
|
||||||
|
files = [],
|
||||||
|
environment = '',
|
||||||
|
loading,
|
||||||
|
error
|
||||||
|
}) => {
|
||||||
|
const _title = <Title>Environment</Title>;
|
||||||
|
|
||||||
|
if (loading && !environment.length && !files.length) {
|
||||||
|
return (
|
||||||
|
<LayoutContainer center>
|
||||||
|
{_title}
|
||||||
|
<Loader />
|
||||||
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
{_title}
|
||||||
|
<ErrorMessage
|
||||||
|
title="Ooops!"
|
||||||
|
message="An error occured while loading environment data."
|
||||||
|
/>
|
||||||
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
{_title}
|
||||||
|
<Environment defaultValue={environment} files={files} readOnly />
|
||||||
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
graphql(ManifestQuery, {
|
||||||
|
options: props => ({
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
variables: {
|
||||||
|
deploymentGroupSlug: props.match.params.deploymentGroup
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||||
|
files: get(deploymentGroup, 'version.manifest.files', []),
|
||||||
|
environment: get(deploymentGroup, 'version.manifest.environment', ''),
|
||||||
|
loading,
|
||||||
|
error
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)(EnvironmentReadOnly);
|
@ -1,8 +1,6 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import { compose, graphql } from 'react-apollo';
|
import { compose, graphql } from 'react-apollo';
|
||||||
import InstancesQuery from '@graphql/Instances.gql';
|
import InstancesQuery from '@graphql/Instances.gql';
|
||||||
import { Row } from 'react-styled-flexboxgrid';
|
|
||||||
import remcalc from 'remcalc';
|
|
||||||
import forceArray from 'force-array';
|
import forceArray from 'force-array';
|
||||||
import sortBy from 'lodash.sortby';
|
import sortBy from 'lodash.sortby';
|
||||||
|
|
||||||
@ -30,8 +28,9 @@ const InstanceList = ({ deploymentGroup, instances = [], loading, error }) => {
|
|||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
{_title}
|
{_title}
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occured while loading your instances.' />
|
message="An error occured while loading your instances."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@ import { Redirect } from 'react-router-dom';
|
|||||||
import intercept from 'apr-intercept';
|
import intercept from 'apr-intercept';
|
||||||
import paramCase from 'param-case';
|
import paramCase from 'param-case';
|
||||||
import remove from 'lodash.remove';
|
import remove from 'lodash.remove';
|
||||||
|
import flatten from 'lodash.flatten';
|
||||||
|
import uniq from 'lodash.uniq';
|
||||||
|
import find from 'lodash.find';
|
||||||
|
import { safeLoad } from 'js-yaml';
|
||||||
import uuid from 'uuid/v4';
|
import uuid from 'uuid/v4';
|
||||||
|
|
||||||
import DeploymentGroupBySlugQuery from '@graphql/DeploymentGroupBySlug.gql';
|
import DeploymentGroupBySlugQuery from '@graphql/DeploymentGroupBySlug.gql';
|
||||||
@ -22,13 +26,15 @@ import {
|
|||||||
Review
|
Review
|
||||||
} from '@components/manifest/edit-or-create';
|
} from '@components/manifest/edit-or-create';
|
||||||
|
|
||||||
|
const INTERPOLATE_REGEX = /\$([_a-z][_a-z0-9]*)/gi;
|
||||||
|
|
||||||
// TODO: move state to redux. why: because in redux we can cache transactional
|
// TODO: move state to redux. why: because in redux we can cache transactional
|
||||||
// state between refreshes
|
// state between refreshes
|
||||||
class DeploymentGroupEditOrCreate extends Component {
|
class DeploymentGroupEditOrCreate extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const { create, edit, files = [] } = props;
|
const { create, files = [], manifest } = props;
|
||||||
const type = create ? 'create' : 'edit';
|
const type = create ? 'create' : 'edit';
|
||||||
|
|
||||||
const NameForm =
|
const NameForm =
|
||||||
@ -38,63 +44,59 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
destroyOnUnmount: true,
|
destroyOnUnmount: true,
|
||||||
forceUnregisterOnUnmount: true,
|
forceUnregisterOnUnmount: true,
|
||||||
asyncValidate: async ({ name = '' }) => {
|
asyncValidate: async ({ name = '' }) => {
|
||||||
const [err] = await intercept(client.query({
|
const [err, res] = await intercept(
|
||||||
fetchPolicy: 'network-only',
|
client.query({
|
||||||
query: DeploymentGroupBySlugQuery,
|
fetchPolicy: 'network-only',
|
||||||
variables: {
|
query: DeploymentGroupBySlugQuery,
|
||||||
slug: paramCase(name.trim())
|
variables: {
|
||||||
}
|
slug: paramCase(name.trim())
|
||||||
}));
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (!err) {
|
if (err) {
|
||||||
// eslint-disable-next-line no-throw-literal
|
return;
|
||||||
throw { name: `"${name}" already exists!` };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!res.data.deploymentGroups.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw { name: `"${name}" already exists!` };
|
||||||
}
|
}
|
||||||
})(Name);
|
})(Name);
|
||||||
|
|
||||||
const ManifestForm = reduxForm({
|
const ManifestForm = reduxForm({
|
||||||
form: `${type}-deployment-group`,
|
form: `${type}-deployment-group`
|
||||||
destroyOnUnmount: true,
|
|
||||||
forceUnregisterOnUnmount: true
|
|
||||||
})(Manifest);
|
})(Manifest);
|
||||||
|
|
||||||
const EnvironmentForm = reduxForm({
|
|
||||||
form: `${type}-deployment-group`,
|
|
||||||
destroyOnUnmount: true,
|
|
||||||
forceUnregisterOnUnmount: true
|
|
||||||
})(Environment);
|
|
||||||
|
|
||||||
const ReviewForm = reduxForm({
|
const ReviewForm = reduxForm({
|
||||||
form: `${type}-deployment-group`,
|
form: `${type}-deployment-group`
|
||||||
destroyOnUnmount: true,
|
|
||||||
forceUnregisterOnUnmount: true
|
|
||||||
})(Review);
|
})(Review);
|
||||||
|
|
||||||
if (!files.length) {
|
|
||||||
files.push({
|
|
||||||
id: uuid(),
|
|
||||||
name: '',
|
|
||||||
value: '#'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
type,
|
||||||
defaultStage: create ? 'name' : 'edit',
|
defaultStage: create ? 'name' : 'edit',
|
||||||
manifestStage: create ? 'manifest' : 'edit',
|
manifestStage: create ? 'manifest' : 'edit',
|
||||||
name: '',
|
name: '',
|
||||||
manifest: '',
|
manifest: '',
|
||||||
environment: '',
|
environment: '',
|
||||||
files,
|
files: this.resolveManifestFiles(files, manifest),
|
||||||
services: [],
|
services: [],
|
||||||
|
environmentToggles: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
NameForm,
|
NameForm,
|
||||||
ManifestForm,
|
ReviewForm,
|
||||||
EnvironmentForm,
|
ManifestForm
|
||||||
ReviewForm
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.state.EnvironmentForm = this.getEnvironmentForm(
|
||||||
|
this.state.files,
|
||||||
|
manifest
|
||||||
|
);
|
||||||
|
|
||||||
this.stages = {
|
this.stages = {
|
||||||
name: create && this.renderNameForm.bind(this),
|
name: create && this.renderNameForm.bind(this),
|
||||||
[create ? 'manifest' : 'edit']: this.renderManifestEditor.bind(this),
|
[create ? 'manifest' : 'edit']: this.renderManifestEditor.bind(this),
|
||||||
@ -111,10 +113,77 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
this.handleCancel = this.handleCancel.bind(this);
|
this.handleCancel = this.handleCancel.bind(this);
|
||||||
this.handleFileAdd = this.handleFileAdd.bind(this);
|
this.handleFileAdd = this.handleFileAdd.bind(this);
|
||||||
this.handleRemoveFile = this.handleRemoveFile.bind(this);
|
this.handleRemoveFile = this.handleRemoveFile.bind(this);
|
||||||
|
this.handleEnvironmentToggle = this.handleEnvironmentToggle.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (edit) {
|
resolveManifestFiles(currentFiles = [], manifestStr = '') {
|
||||||
setTimeout(this.getDeploymentGroup, 16);
|
if (!manifestStr.length) {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let manifest = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
manifest = safeLoad(manifestStr);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const services = manifest.services ? manifest.services : manifest;
|
||||||
|
|
||||||
|
const filenames = uniq(
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
flatten(Object.values(services).map(({ env_file }) => env_file))
|
||||||
|
);
|
||||||
|
|
||||||
|
return filenames
|
||||||
|
.filter(filename => !find(currentFiles, ['name', filename]))
|
||||||
|
.map(this.getDefaultFile)
|
||||||
|
.concat(currentFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
getEnvironmentForm(files = [], manifest = '') {
|
||||||
|
const { type } = this.state;
|
||||||
|
|
||||||
|
const initialValues = files.reduce(
|
||||||
|
(acc, { id, name, value }) =>
|
||||||
|
Object.assign(acc, {
|
||||||
|
[`file-name-${id}`]: name,
|
||||||
|
[`file-value-${id}`]: value
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
return reduxForm({
|
||||||
|
form: `${type}-deployment-group`,
|
||||||
|
initialValues
|
||||||
|
})(Environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
getEnvironmentDefaultValue() {
|
||||||
|
const { environment = '' } = this.props;
|
||||||
|
const { manifest = '' } = this.state;
|
||||||
|
|
||||||
|
if (environment.length) {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const names = manifest
|
||||||
|
.match(INTERPOLATE_REGEX)
|
||||||
|
.map(name => name.replace(/^\$/, ''));
|
||||||
|
|
||||||
|
const vars = uniq(names).map(name => `\n${name}=`).join('');
|
||||||
|
|
||||||
|
return `# define your interpolatable variables here\n${vars}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDefaultFile(name = '') {
|
||||||
|
return {
|
||||||
|
id: uuid(),
|
||||||
|
name,
|
||||||
|
value: '# define your environment variables here\n'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createDeploymentGroup = async () => {
|
createDeploymentGroup = async () => {
|
||||||
@ -176,9 +245,19 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleManifestSubmit({ manifest = '' }) {
|
handleManifestSubmit({ manifest = '' }) {
|
||||||
this.setState({ manifest: manifest || this.props.manifest }, () => {
|
const { files } = this.state;
|
||||||
this.redirect({ stage: 'environment', prog: true });
|
|
||||||
});
|
const _manifest = manifest || this.props.manifest;
|
||||||
|
const _files = this.resolveManifestFiles(files, _manifest);
|
||||||
|
|
||||||
|
const EnvironmentForm = this.getEnvironmentForm(_files, _manifest);
|
||||||
|
|
||||||
|
this.setState(
|
||||||
|
{ manifest: _manifest, EnvironmentForm, files: _files },
|
||||||
|
() => {
|
||||||
|
this.redirect({ stage: 'environment', prog: true });
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEnvironmentSubmit(change) {
|
handleEnvironmentSubmit(change) {
|
||||||
@ -270,23 +349,33 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
const { history, create, deploymentGroup } = this.props;
|
const { history, create, deploymentGroup } = this.props;
|
||||||
|
|
||||||
history.push(create ? '/' : `/deployment-groups/${deploymentGroup.slug}`);
|
history.push(create ? '/' : `/deployment-groups/${deploymentGroup.slug}`);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFileAdd() {
|
handleFileAdd() {
|
||||||
|
const { files = [] } = this.state;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
files: this.state.files.concat([
|
files: files.concat([this.getDefaultFile()])
|
||||||
{
|
|
||||||
id: uuid(),
|
|
||||||
name: '',
|
|
||||||
value: '#'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRemoveFile(fileId) {
|
handleRemoveFile(fileId) {
|
||||||
|
const { files = [] } = this.state;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
files: remove(this.state.files, ({ id }) => id !== fileId)
|
files: remove(files, ({ id }) => id !== fileId)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEnvironmentToggle(serviceName) {
|
||||||
|
const { environmentToggles } = this.state;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
environmentToggles: Object.assign({}, environmentToggles, {
|
||||||
|
[serviceName]: !environmentToggles[serviceName]
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,40 +416,40 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderEnvironmentEditor() {
|
renderEnvironmentEditor() {
|
||||||
const { EnvironmentForm } = this.state;
|
const { EnvironmentForm, files, loading } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EnvironmentForm
|
<EnvironmentForm
|
||||||
defaultValue={this.props.environment}
|
defaultValue={this.getEnvironmentDefaultValue()}
|
||||||
files={this.state.files}
|
files={files}
|
||||||
onSubmit={this.handleEnvironmentSubmit}
|
onSubmit={this.handleEnvironmentSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
onAddFile={this.handleFileAdd}
|
onAddFile={this.handleFileAdd}
|
||||||
onRemoveFile={this.handleRemoveFile}
|
onRemoveFile={this.handleRemoveFile}
|
||||||
loading={this.state.loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderReview() {
|
renderReview() {
|
||||||
const { ReviewForm } = this.state;
|
const { ReviewForm, environmentToggles } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReviewForm
|
<ReviewForm
|
||||||
onSubmit={this.handleReviewSubmit}
|
onSubmit={this.handleReviewSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
|
onEnvironmentToggle={this.handleEnvironmentToggle}
|
||||||
|
environmentToggles={environmentToggles}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { error, loading, defaultStage, manifestStage } = this.state;
|
const { error, defaultStage, manifestStage, manifest, name } = this.state;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <ErrorMessage
|
return <ErrorMessage title="Ooops!" message={error} />;
|
||||||
title='Ooops!'
|
|
||||||
message={error} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { match, create } = this.props;
|
const { match, create } = this.props;
|
||||||
@ -374,11 +463,11 @@ class DeploymentGroupEditOrCreate extends Component {
|
|||||||
return this.redirect({ stage: defaultStage });
|
return this.redirect({ stage: defaultStage });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create && stage !== 'name' && !this.state.name) {
|
if (create && stage !== 'name' && !name) {
|
||||||
return this.redirect({ stage: defaultStage });
|
return this.redirect({ stage: defaultStage });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage === 'environment' && !this.state.manifest) {
|
if (stage === 'environment' && !manifest) {
|
||||||
return this.redirect({ stage: manifestStage });
|
return this.redirect({ stage: manifestStage });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,13 +17,15 @@ const Manifest = ({
|
|||||||
error,
|
error,
|
||||||
manifest = '',
|
manifest = '',
|
||||||
environment = '',
|
environment = '',
|
||||||
|
files = [],
|
||||||
deploymentGroup = null,
|
deploymentGroup = null,
|
||||||
|
hasManifest = false,
|
||||||
match
|
match
|
||||||
}) => {
|
}) => {
|
||||||
const stage = match.params.stage;
|
const stage = match.params.stage;
|
||||||
const _title = <Title>Edit Manifest</Title>;
|
const _title = <Title>Edit Manifest</Title>;
|
||||||
|
|
||||||
if (loading || !deploymentGroup) {
|
if (loading || !deploymentGroup || !hasManifest) {
|
||||||
return (
|
return (
|
||||||
<LayoutContainer center>
|
<LayoutContainer center>
|
||||||
{_title}
|
{_title}
|
||||||
@ -37,8 +39,9 @@ const Manifest = ({
|
|||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
{_title}
|
{_title}
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occured while loading your deployment group.' />
|
message="An error occured while loading your deployment group."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -46,8 +49,9 @@ 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 DeploymentGroup was imported, it doesn't have the initial manifest.' />
|
message="Since this DeploymentGroup was imported, it doesn't have the initial manifest."
|
||||||
|
/>
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -58,6 +62,7 @@ const Manifest = ({
|
|||||||
<ManifestEditOrCreate
|
<ManifestEditOrCreate
|
||||||
manifest={manifest}
|
manifest={manifest}
|
||||||
environment={environment}
|
environment={environment}
|
||||||
|
files={files}
|
||||||
deploymentGroup={deploymentGroup}
|
deploymentGroup={deploymentGroup}
|
||||||
edit
|
edit
|
||||||
/>
|
/>
|
||||||
@ -74,8 +79,10 @@ export default compose(
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
props: ({ data: { deploymentGroup, loading, error } }) => ({
|
||||||
|
files: get(deploymentGroup, 'version.manifest.files', []),
|
||||||
manifest: get(deploymentGroup, 'version.manifest.raw', ''),
|
manifest: get(deploymentGroup, 'version.manifest.raw', ''),
|
||||||
environment: get(deploymentGroup, 'version.manifest.environment', ''),
|
environment: get(deploymentGroup, 'version.manifest.environment', ''),
|
||||||
|
hasManifest: Boolean(get(deploymentGroup, 'version.manifest')),
|
||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
})
|
})
|
||||||
|
@ -9,13 +9,12 @@ import ServiceGql from './service-gql';
|
|||||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
class ServiceDelete extends Component {
|
class ServiceDelete extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
error: null
|
error: null
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -40,30 +39,30 @@ class ServiceDelete extends Component {
|
|||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title='Ooops!'
|
||||||
message='An error occured while loading your service.'
|
message='An error occured while loading your service.'
|
||||||
onCloseClick={handleCloseClick} />
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { service, deleteServices } = this.props;
|
const { service, deleteServices } = 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 occured while attempting to delete the ${service.name} service.`}
|
message={`An error occured while attempting to delete the ${service.name} service.`}
|
||||||
onCloseClick={handleCloseClick} />
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleConfirmClick = evt => {
|
const handleConfirmClick = evt => {
|
||||||
deleteServices(service.id)
|
deleteServices(service.id).then(() => handleCloseClick()).catch(err => {
|
||||||
.then(() => handleCloseClick())
|
this.setState({ error: err });
|
||||||
.catch((err) => {
|
});
|
||||||
this.setState({ error: err });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -10,13 +10,12 @@ import ServiceGql from './service-gql';
|
|||||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
class ServiceScale extends Component {
|
class ServiceScale extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
error: null
|
error: null
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -41,20 +40,22 @@ class ServiceScale extends Component {
|
|||||||
<ModalErrorMessage
|
<ModalErrorMessage
|
||||||
title='Ooops!'
|
title='Ooops!'
|
||||||
message='An error occured while loading your service.'
|
message='An error occured while loading your service.'
|
||||||
onCloseClick={handleCloseClick} />
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { service, scale } = this.props;
|
const { service, scale } = 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 occured while attempting to scale the ${service.name} service.`}
|
message={`An error occured while attempting to scale the ${service.name} service.`}
|
||||||
onCloseClick={handleCloseClick} />
|
onCloseClick={handleCloseClick}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -69,11 +70,9 @@ class ServiceScale extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmitClick = values => {
|
const handleSubmitClick = values => {
|
||||||
scale(service.id, values.replicas)
|
scale(service.id, values.replicas).then(handleCloseClick).catch(err => {
|
||||||
.then(handleCloseClick)
|
this.setState({ error: err });
|
||||||
.catch((err) => {
|
});
|
||||||
this.setState({ error: err });
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!service) {
|
if (!service) {
|
||||||
|
@ -19,8 +19,6 @@ import { ServiceListItem } from '@components/services';
|
|||||||
|
|
||||||
import { ServicesQuickActions } from '@components/services';
|
import { ServicesQuickActions } from '@components/services';
|
||||||
|
|
||||||
import { Message } from 'joyent-ui-toolkit';
|
|
||||||
|
|
||||||
import { withNotFound, GqlPaths } from '@containers/navigation';
|
import { withNotFound, GqlPaths } from '@containers/navigation';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -28,13 +26,12 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
class ServiceList extends Component {
|
class ServiceList extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
errors: {}
|
errors: {}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ref(name) {
|
ref(name) {
|
||||||
@ -73,8 +70,9 @@ class ServiceList extends Component {
|
|||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occured while loading your services.' />
|
message="An error occured while loading your services."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -113,26 +111,23 @@ class ServiceList extends Component {
|
|||||||
|
|
||||||
const handleRestartClick = (evt, service) => {
|
const handleRestartClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
restartServices(service.id)
|
restartServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { restart: err } });
|
||||||
this.setState({ errors: { restart: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStopClick = (evt, service) => {
|
const handleStopClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
stopServices(service.id)
|
stopServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { stop: err } });
|
||||||
this.setState({ errors: { stop: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartClick = (evt, service) => {
|
const handleStartClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
startServices(service.id)
|
startServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { start: err } });
|
||||||
this.setState({ errors: { start: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleScaleClick = (evt, service) => {
|
const handleScaleClick = (evt, service) => {
|
||||||
@ -151,21 +146,22 @@ class ServiceList extends Component {
|
|||||||
|
|
||||||
let renderedError = null;
|
let renderedError = null;
|
||||||
|
|
||||||
if (this.state.errors.stop || this.state.errors.start || this.state.errors.restart) {
|
if (
|
||||||
|
this.state.errors.stop ||
|
||||||
|
this.state.errors.start ||
|
||||||
|
this.state.errors.restart
|
||||||
|
) {
|
||||||
const message = this.state.errors.stop
|
const message = this.state.errors.stop
|
||||||
? 'An error occured while attempting to stop your service.'
|
? 'An error occured while attempting to stop your service.'
|
||||||
: this.state.errors.start
|
: this.state.errors.start
|
||||||
? 'An error occured while attempting to start your service.'
|
? 'An error occured while attempting to start your service.'
|
||||||
: this.state.errors.restart
|
: this.state.errors.restart
|
||||||
? 'An error occured while attempting to restart your service.'
|
? 'An error occured while attempting to restart your service.'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
renderedError = (
|
renderedError = (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<ErrorMessage
|
<ErrorMessage title="Ooops!" message={message} />
|
||||||
title='Ooops!'
|
|
||||||
message={message} />
|
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { LayoutContainer } from '@components/layout';
|
|||||||
import { Title } from '@components/navigation';
|
import { Title } from '@components/navigation';
|
||||||
import { withNotFound } from '@containers/navigation';
|
import { withNotFound } from '@containers/navigation';
|
||||||
|
|
||||||
import { H2, FormGroup, Toggle, ToggleList, Legend } from 'joyent-ui-toolkit';
|
import { FormGroup, Toggle, ToggleList, Legend } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const StyledLegend = Legend.extend`
|
const StyledLegend = Legend.extend`
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -30,23 +30,20 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
class ServicesTopology extends Component {
|
class ServicesTopology extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
errors: {}
|
errors: {}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
url,
|
url,
|
||||||
push,
|
push,
|
||||||
deploymentGroup,
|
deploymentGroup,
|
||||||
services,
|
services,
|
||||||
datacenter,
|
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
servicesQuickActions,
|
servicesQuickActions,
|
||||||
@ -69,8 +66,9 @@ class ServicesTopology extends Component {
|
|||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title='Ooops!'
|
title="Ooops!"
|
||||||
message='An error occured while loading your services.' />
|
message="An error occured while loading your services."
|
||||||
|
/>
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -97,26 +95,23 @@ class ServicesTopology extends Component {
|
|||||||
|
|
||||||
const handleRestartClick = (evt, service) => {
|
const handleRestartClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
restartServices(service.id)
|
restartServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { restart: err } });
|
||||||
this.setState({ errors: { restart: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStopClick = (evt, service) => {
|
const handleStopClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
stopServices(service.id)
|
stopServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { stop: err } });
|
||||||
this.setState({ errors: { stop: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartClick = (evt, service) => {
|
const handleStartClick = (evt, service) => {
|
||||||
this.setState({ errors: {} });
|
this.setState({ errors: {} });
|
||||||
startServices(service.id)
|
startServices(service.id).catch(err => {
|
||||||
.catch((err) => {
|
this.setState({ errors: { start: err } });
|
||||||
this.setState({ errors: { start: err }});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleScaleClick = (evt, service) => {
|
const handleScaleClick = (evt, service) => {
|
||||||
@ -135,28 +130,29 @@ class ServicesTopology extends Component {
|
|||||||
|
|
||||||
let renderedError = null;
|
let renderedError = null;
|
||||||
|
|
||||||
if (this.state.errors.stop || this.state.errors.start || this.state.errors.restart) {
|
if (
|
||||||
|
this.state.errors.stop ||
|
||||||
|
this.state.errors.start ||
|
||||||
|
this.state.errors.restart
|
||||||
|
) {
|
||||||
const message = this.state.errors.stop
|
const message = this.state.errors.stop
|
||||||
? 'An error occured while attempting to stop your service.'
|
? 'An error occured while attempting to stop your service.'
|
||||||
: this.state.errors.start
|
: this.state.errors.start
|
||||||
? 'An error occured while attempting to start your service.'
|
? 'An error occured while attempting to start your service.'
|
||||||
: this.state.errors.restart
|
: this.state.errors.restart
|
||||||
? 'An error occured while attempting to restart your service.'
|
? 'An error occured while attempting to restart your service.'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
renderedError = (
|
renderedError = (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<ErrorMessage
|
<ErrorMessage title="Ooops!" message={message} />
|
||||||
title='Ooops!'
|
|
||||||
message={message} />
|
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ renderedError }
|
{renderedError}
|
||||||
<StyledBackground>
|
<StyledBackground>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<Topology
|
<Topology
|
||||||
|
@ -5,6 +5,11 @@ query ManifestById($deploymentGroupSlug: String!) {
|
|||||||
id
|
id
|
||||||
type
|
type
|
||||||
environment
|
environment
|
||||||
|
files {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
format
|
format
|
||||||
raw
|
raw
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { Header, Breadcrumb, Menu } from '@containers/navigation';
|
|||||||
import { ServiceScale, ServiceDelete } from '@containers/service';
|
import { ServiceScale, ServiceDelete } from '@containers/service';
|
||||||
import { InstanceList } from '@containers/instances';
|
import { InstanceList } from '@containers/instances';
|
||||||
import Manifest from '@containers/manifest';
|
import Manifest from '@containers/manifest';
|
||||||
|
import Environment from '@containers/environment';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DeploymentGroupList,
|
DeploymentGroupList,
|
||||||
@ -48,9 +49,8 @@ const serviceRedirect = p =>
|
|||||||
.params.service}/instances`}
|
.params.service}/instances`}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
const App = p => (
|
const App = p =>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path="/deployment-groups/:deploymentGroup/services/:service"
|
path="/deployment-groups/:deploymentGroup/services/:service"
|
||||||
@ -118,6 +118,12 @@ const App = p => (
|
|||||||
component={Manifest}
|
component={Manifest}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
path="/deployment-groups/:deploymentGroup/environment"
|
||||||
|
exact
|
||||||
|
component={Environment}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/deployment-groups/:deploymentGroup/services-list"
|
path="/deployment-groups/:deploymentGroup/services-list"
|
||||||
component={ServiceList}
|
component={ServiceList}
|
||||||
@ -178,8 +184,7 @@ const App = p => (
|
|||||||
component={servicesTopologyRedirect}
|
component={servicesTopologyRedirect}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>;
|
||||||
)
|
|
||||||
|
|
||||||
const Router = (
|
const Router = (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
@ -13,6 +13,10 @@ const state = {
|
|||||||
{
|
{
|
||||||
pathname: 'manifest/edit',
|
pathname: 'manifest/edit',
|
||||||
name: 'Manifest'
|
name: 'Manifest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pathname: 'environment',
|
||||||
|
name: 'Environment'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
services: [
|
services: [
|
||||||
|
@ -14,7 +14,8 @@ const GLOBAL =
|
|||||||
};
|
};
|
||||||
|
|
||||||
const GQL_PORT = process.env.REACT_APP_GQL_PORT || 443;
|
const GQL_PORT = process.env.REACT_APP_GQL_PORT || 443;
|
||||||
const GQL_HOSTNAME = process.env.REACT_APP_GQL_HOSTNAME || GLOBAL.location.hostname;
|
const GQL_HOSTNAME =
|
||||||
|
process.env.REACT_APP_GQL_HOSTNAME || GLOBAL.location.hostname;
|
||||||
const GQL_PROTOCOL = process.env.REACT_APP_GQL_PROTOCOL || 'https';
|
const GQL_PROTOCOL = process.env.REACT_APP_GQL_PROTOCOL || 'https';
|
||||||
|
|
||||||
export const client = new ApolloClient({
|
export const client = new ApolloClient({
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"build-array": "^1.0.0",
|
"build-array": "^1.0.0",
|
||||||
"camel-case": "^3.0.0",
|
"camel-case": "^3.0.0",
|
||||||
|
"force-array": "^3.1.0",
|
||||||
"good": "^7.2.0",
|
"good": "^7.2.0",
|
||||||
"good-console": "^6.4.0",
|
"good-console": "^6.4.0",
|
||||||
"good-squeeze": "^5.0.2",
|
"good-squeeze": "^5.0.2",
|
||||||
@ -25,7 +26,7 @@
|
|||||||
"hasha": "^3.0.0",
|
"hasha": "^3.0.0",
|
||||||
"joi": "^10.6.0",
|
"joi": "^10.6.0",
|
||||||
"joyent-cp-gql-schema": "^1.0.4",
|
"joyent-cp-gql-schema": "^1.0.4",
|
||||||
"js-yaml": "^3.8.4",
|
"js-yaml": "^3.9.1",
|
||||||
"lodash.find": "^4.6.0",
|
"lodash.find": "^4.6.0",
|
||||||
"lodash.findindex": "^4.6.0",
|
"lodash.findindex": "^4.6.0",
|
||||||
"lodash.flatten": "^4.4.0",
|
"lodash.flatten": "^4.4.0",
|
||||||
@ -47,8 +48,12 @@
|
|||||||
"tap-xunit": "^1.7.0"
|
"tap-xunit": "^1.7.0"
|
||||||
},
|
},
|
||||||
"ava": {
|
"ava": {
|
||||||
"files": ["test/*.js"],
|
"files": [
|
||||||
"source": ["src/*.js"],
|
"test/*.js"
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"src/*.js"
|
||||||
|
],
|
||||||
"failFast": true
|
"failFast": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ const { v4: uuid } = require('uuid');
|
|||||||
const paramCase = require('param-case');
|
const paramCase = require('param-case');
|
||||||
const camelCase = require('camel-case');
|
const camelCase = require('camel-case');
|
||||||
const buildArray = require('build-array');
|
const buildArray = require('build-array');
|
||||||
|
const forceArray = require('force-array');
|
||||||
const lfind = require('lodash.find');
|
const lfind = require('lodash.find');
|
||||||
const findIndex = require('lodash.findindex');
|
const findIndex = require('lodash.findindex');
|
||||||
const flatten = require('lodash.flatten');
|
const flatten = require('lodash.flatten');
|
||||||
@ -31,6 +32,8 @@ const instances = wpData.instances
|
|||||||
.concat(cpData.instances)
|
.concat(cpData.instances)
|
||||||
.concat(complexData.instances);
|
.concat(complexData.instances);
|
||||||
|
|
||||||
|
const INTERPOLATE_REGEX = /\$([_a-z][_a-z0-9]*)/gi;
|
||||||
|
|
||||||
const find = (query = {}) => item =>
|
const find = (query = {}) => item =>
|
||||||
Object.keys(query).every(key => item[key] === query[key]);
|
Object.keys(query).every(key => item[key] === query[key]);
|
||||||
|
|
||||||
@ -185,14 +188,41 @@ const deleteDeploymentGroup = options => {
|
|||||||
return Promise.resolve(deleteDeploymentGroup);
|
return Promise.resolve(deleteDeploymentGroup);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createServicesFromManifest = ({ deploymentGroupId, raw }) => {
|
const createServicesFromManifest = ({
|
||||||
|
deploymentGroupId = '',
|
||||||
|
environment = '',
|
||||||
|
files = [],
|
||||||
|
type,
|
||||||
|
format,
|
||||||
|
raw = ''
|
||||||
|
}) => {
|
||||||
|
const _config = config({
|
||||||
|
environment,
|
||||||
|
files,
|
||||||
|
raw,
|
||||||
|
_plain: true
|
||||||
|
});
|
||||||
|
|
||||||
const manifest = yaml.safeLoad(raw);
|
const manifest = yaml.safeLoad(raw);
|
||||||
|
|
||||||
|
const version = {
|
||||||
|
id: uuid(),
|
||||||
|
manifest: {
|
||||||
|
id: uuid(),
|
||||||
|
type,
|
||||||
|
format,
|
||||||
|
environment,
|
||||||
|
files,
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Object.keys(manifest).forEach(name => {
|
Object.keys(manifest).forEach(name => {
|
||||||
const _service = {
|
const _service = {
|
||||||
deploymentGroupId,
|
deploymentGroupId,
|
||||||
slug: paramCase(name),
|
slug: paramCase(name),
|
||||||
name
|
name,
|
||||||
|
config: lfind(_config, ['name', name]).config
|
||||||
};
|
};
|
||||||
|
|
||||||
const service = Object.assign({}, _service, {
|
const service = Object.assign({}, _service, {
|
||||||
@ -213,6 +243,12 @@ const createServicesFromManifest = ({ deploymentGroupId, raw }) => {
|
|||||||
instances.push(instance);
|
instances.push(instance);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dgIndex = findIndex(deploymentGroups, ['id', deploymentGroupId]);
|
||||||
|
deploymentGroups[dgIndex] = Object.assign(deploymentGroups[dgIndex], {
|
||||||
|
version,
|
||||||
|
history: forceArray(deploymentGroups[dgIndex].history).concat([version])
|
||||||
|
});
|
||||||
|
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -409,6 +445,86 @@ const restartServices = options => {
|
|||||||
return Promise.resolve(restartService);
|
return Promise.resolve(restartService);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parseEnvVars = (str = '') =>
|
||||||
|
str
|
||||||
|
.split(/\n/g)
|
||||||
|
.filter(line => line.match(/\=/g))
|
||||||
|
.map(line => line.split(/\=/))
|
||||||
|
.reduce(
|
||||||
|
(acc, [name, value]) =>
|
||||||
|
Object.assign(acc, {
|
||||||
|
[name.trim()]: value.trim()
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
const findEnvInterpolation = (str = '') =>
|
||||||
|
uniq(str.match(INTERPOLATE_REGEX).map(name => name.replace(/^\$/, '')));
|
||||||
|
|
||||||
|
const config = ({
|
||||||
|
environment = '',
|
||||||
|
files = [],
|
||||||
|
raw = '',
|
||||||
|
_plain = false
|
||||||
|
}) => {
|
||||||
|
const interpolatableNames = findEnvInterpolation(raw);
|
||||||
|
const interpolatableEnv = parseEnvVars(environment);
|
||||||
|
|
||||||
|
const interpolatedRaw = interpolatableNames.reduce(
|
||||||
|
(str = '', name) =>
|
||||||
|
str.replace(new RegExp(`\\$${name}`), interpolatableEnv[name]),
|
||||||
|
raw
|
||||||
|
);
|
||||||
|
|
||||||
|
const manifest = yaml.safeLoad(interpolatedRaw);
|
||||||
|
const services = manifest.services || manifest;
|
||||||
|
|
||||||
|
const config = Object.keys(services)
|
||||||
|
.map(name =>
|
||||||
|
Object.assign(services[name], {
|
||||||
|
name
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
.map(({ name, image, env_file, environment }) => ({
|
||||||
|
name,
|
||||||
|
slug: paramCase(name),
|
||||||
|
instances: [],
|
||||||
|
config: {
|
||||||
|
image,
|
||||||
|
environment: forceArray(env_file).reduce(
|
||||||
|
(env, file) =>
|
||||||
|
Object.assign(
|
||||||
|
env,
|
||||||
|
parseEnvVars(lfind(files, ['name', file]).value)
|
||||||
|
),
|
||||||
|
forceArray(environment)
|
||||||
|
.map(parseEnvVars)
|
||||||
|
.reduce(
|
||||||
|
(genv, variable) => Object.assign(genv, variable),
|
||||||
|
interpolatableEnv
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.map(service =>
|
||||||
|
Object.assign(service, {
|
||||||
|
id: hasha(JSON.stringify(service)),
|
||||||
|
config: Object.assign(service.config, {
|
||||||
|
id: hasha(JSON.stringify(service.config)),
|
||||||
|
environment: Object.keys(service.config.environment).map(name => ({
|
||||||
|
name,
|
||||||
|
id: hasha(JSON.stringify(service.config.environment[name])),
|
||||||
|
value: service.config.environment[name]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return _plain ? config : Promise.resolve(config);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
portal: getPortal,
|
portal: getPortal,
|
||||||
deploymentGroups: getDeploymentGroups,
|
deploymentGroups: getDeploymentGroups,
|
||||||
@ -430,5 +546,6 @@ module.exports = {
|
|||||||
scale: (options, reguest, fn) => fn(null, scale(options)),
|
scale: (options, reguest, fn) => fn(null, scale(options)),
|
||||||
restartServices: (options, request, fn) => fn(null, restartServices(options)),
|
restartServices: (options, request, fn) => fn(null, restartServices(options)),
|
||||||
stopServices: (options, request, fn) => fn(null, stopServices(options)),
|
stopServices: (options, request, fn) => fn(null, stopServices(options)),
|
||||||
startServices: (options, request, fn) => fn(null, startServices(options))
|
startServices: (options, request, fn) => fn(null, startServices(options)),
|
||||||
|
config
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
"code": "^4.1.0",
|
"code": "^4.1.0",
|
||||||
"eslint": "^3.19.0",
|
"eslint": "^3.19.0",
|
||||||
"eslint-config-joyent-portal": "2.0.0",
|
"eslint-config-joyent-portal": "2.0.0",
|
||||||
"js-yaml": "^3.8.4",
|
"js-yaml": "^3.9.1",
|
||||||
"lab": "^14.0.1"
|
"lab": "^14.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Yamljs = require('yamljs');
|
|
||||||
const ParamCase = require('param-case');
|
const ParamCase = require('param-case');
|
||||||
const Uuid = require('uuid/v4');
|
const Uuid = require('uuid/v4');
|
||||||
|
|
||||||
@ -138,8 +137,7 @@ exports.toManifest = function (clientManifest) {
|
|||||||
id: m.id || Uuid()
|
id: m.id || Uuid()
|
||||||
});
|
});
|
||||||
}) : undefined,
|
}) : undefined,
|
||||||
raw: clientManifest.raw,
|
raw: clientManifest.raw
|
||||||
json: clientManifest.json || Yamljs.parse(clientManifest.raw)
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@
|
|||||||
"triton": "^5.2.0",
|
"triton": "^5.2.0",
|
||||||
"triton-watch": "^1.1.0",
|
"triton-watch": "^1.1.0",
|
||||||
"uuid": "^3.1.0",
|
"uuid": "^3.1.0",
|
||||||
"vasync": "^1.6.4",
|
"vasync": "^1.6.4"
|
||||||
"yamljs": "^0.2.10"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import { bottomShaddow, borderRadius } from '../boxes';
|
|||||||
import paperEffect from '../paper-effect';
|
import paperEffect from '../paper-effect';
|
||||||
import typography from '../typography';
|
import typography from '../typography';
|
||||||
import Baseline from '../baseline';
|
import Baseline from '../baseline';
|
||||||
|
import StatusLoader from '../status-loader';
|
||||||
|
|
||||||
// Based on bootstrap 4
|
// Based on bootstrap 4
|
||||||
const style = css`
|
const style = css`
|
||||||
@ -169,7 +170,7 @@ const StyledLink = styled(Link)`
|
|||||||
* @example ./usage.md
|
* @example ./usage.md
|
||||||
*/
|
*/
|
||||||
const Button = props => {
|
const Button = props => {
|
||||||
const { href = '', to = '' } = props;
|
const { href = '', to = '', loading = false, secondary, tertiary } = props;
|
||||||
|
|
||||||
const Views = [
|
const Views = [
|
||||||
() => (to ? StyledLink : null),
|
() => (to ? StyledLink : null),
|
||||||
@ -179,9 +180,13 @@ const Button = props => {
|
|||||||
|
|
||||||
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
||||||
|
|
||||||
|
const children = loading
|
||||||
|
? <StatusLoader secondary={!secondary} tertiary={tertiary} />
|
||||||
|
: props.children;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View {...props}>
|
<View {...props}>
|
||||||
{props.children}
|
{children}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,13 @@ const StyledCard = Row.extend`
|
|||||||
/**
|
/**
|
||||||
* @example ./usage.md
|
* @example ./usage.md
|
||||||
*/
|
*/
|
||||||
const Card = ({ children, collapsed = false, headed = false, disabled = false, ...rest }) => {
|
const Card = ({
|
||||||
|
children,
|
||||||
|
collapsed = false,
|
||||||
|
headed = false,
|
||||||
|
disabled = false,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
const render = value => {
|
const render = value => {
|
||||||
const newValue = {
|
const newValue = {
|
||||||
fromHeader: (value || {}).fromHeader,
|
fromHeader: (value || {}).fromHeader,
|
||||||
@ -54,7 +60,13 @@ const Card = ({ children, collapsed = false, headed = false, disabled = false, .
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Broadcast channel="card" value={newValue}>
|
<Broadcast channel="card" value={newValue}>
|
||||||
<StyledCard name="card" disabled={disabled} collapsed={collapsed} headed={headed} {...rest}>
|
<StyledCard
|
||||||
|
name="card"
|
||||||
|
disabled={disabled}
|
||||||
|
collapsed={collapsed}
|
||||||
|
headed={headed}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Broadcast>
|
</Broadcast>
|
||||||
|
@ -35,7 +35,13 @@ const Header = ({ children, ...rest }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Broadcast channel="card" value={newValue}>
|
<Broadcast channel="card" value={newValue}>
|
||||||
<StyledCard name="card-header" disabled={disabled} collapsed headed {...rest}>
|
<StyledCard
|
||||||
|
name="card-header"
|
||||||
|
disabled={disabled}
|
||||||
|
collapsed
|
||||||
|
headed
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
</Broadcast>
|
</Broadcast>
|
||||||
|
@ -79,7 +79,11 @@ const StyledCircle = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Options = ({ children, ...rest }) => {
|
const Options = ({ children, ...rest }) => {
|
||||||
const render = ({ fromHeader = false, collapsed = false, disabled = false }) =>
|
const render = ({
|
||||||
|
fromHeader = false,
|
||||||
|
collapsed = false,
|
||||||
|
disabled = false
|
||||||
|
}) =>
|
||||||
<StyledNav disabled={disabled} fromHeader={fromHeader} name="card-options">
|
<StyledNav disabled={disabled} fromHeader={fromHeader} name="card-options">
|
||||||
<StyledButton
|
<StyledButton
|
||||||
secondary={!fromHeader}
|
secondary={!fromHeader}
|
||||||
|
@ -27,7 +27,13 @@ const StyledCol = Col.extend`
|
|||||||
|
|
||||||
const Outlet = ({ children, ...rest }) => {
|
const Outlet = ({ children, ...rest }) => {
|
||||||
const render = ({ disabled = false, collapsed = false }) =>
|
const render = ({ disabled = false, collapsed = false }) =>
|
||||||
<StyledCol name="card-outlet" disabled={disabled} collapsed={collapsed} xs={6} {...rest}>
|
<StyledCol
|
||||||
|
name="card-outlet"
|
||||||
|
disabled={disabled}
|
||||||
|
collapsed={collapsed}
|
||||||
|
xs={6}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</StyledCol>;
|
</StyledCol>;
|
||||||
|
|
||||||
|
@ -47,7 +47,11 @@ const StyledTitle = Title.extend`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Subtitle = ({ children, ...props }) => {
|
const Subtitle = ({ children, ...props }) => {
|
||||||
const render = ({ disabled = false, fromHeader = false, collapsed = false }) =>
|
const render = ({
|
||||||
|
disabled = false,
|
||||||
|
fromHeader = false,
|
||||||
|
collapsed = false
|
||||||
|
}) =>
|
||||||
<StyledTitle
|
<StyledTitle
|
||||||
name="card-subtitle"
|
name="card-subtitle"
|
||||||
fromHeader={fromHeader}
|
fromHeader={fromHeader}
|
||||||
|
@ -59,7 +59,11 @@ const Title = ({ children, ...rest }) => {
|
|||||||
</Span>
|
</Span>
|
||||||
: children;
|
: children;
|
||||||
|
|
||||||
const render = ({ collapsed = false, disabled = false, fromHeader = false }) =>
|
const render = ({
|
||||||
|
collapsed = false,
|
||||||
|
disabled = false,
|
||||||
|
fromHeader = false
|
||||||
|
}) =>
|
||||||
<Container
|
<Container
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
fromHeader={fromHeader}
|
fromHeader={fromHeader}
|
||||||
|
27
packages/ui-toolkit/src/chevron/index.js
Normal file
27
packages/ui-toolkit/src/chevron/index.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import is from 'styled-is';
|
||||||
|
import typography from '../typography';
|
||||||
|
import P from '../text/p';
|
||||||
|
|
||||||
|
export default P.extend`
|
||||||
|
${typography.fontFamily};
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
${is('up')`
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
`};
|
||||||
|
|
||||||
|
${is('down')`
|
||||||
|
transform: rotate(90deg);
|
||||||
|
`};
|
||||||
|
|
||||||
|
${is('left')`
|
||||||
|
transform: rotate(180deg);
|
||||||
|
`};
|
||||||
|
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "\\003e";
|
||||||
|
}
|
||||||
|
`;
|
9
packages/ui-toolkit/src/divider/index.js
Normal file
9
packages/ui-toolkit/src/divider/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
import { Row } from 'react-styled-flexboxgrid';
|
||||||
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
|
export default styled(Row)`
|
||||||
|
background-color: ${props => props.theme.grey};
|
||||||
|
height: ${remcalc(1)};
|
||||||
|
margin: 0;
|
||||||
|
`;
|
@ -13,7 +13,9 @@ export { default as theme } from './theme';
|
|||||||
export { default as typography, fonts } from './typography';
|
export { default as typography, fonts } from './typography';
|
||||||
export { default as Topology } from './topology';
|
export { default as Topology } from './topology';
|
||||||
export { default as Modal, ModalHeading, ModalText } from './modal';
|
export { default as Modal, ModalHeading, ModalText } from './modal';
|
||||||
|
export { default as Chevron } from './chevron';
|
||||||
export { default as CloseButton } from './close-button';
|
export { default as CloseButton } from './close-button';
|
||||||
|
export { default as Divider } from './divider';
|
||||||
export { default as IconButton } from './icon-button';
|
export { default as IconButton } from './icon-button';
|
||||||
export { Tooltip, TooltipButton, TooltipDivider } from './tooltip';
|
export { Tooltip, TooltipButton, TooltipDivider } from './tooltip';
|
||||||
export { Dropdown } from './dropdown';
|
export { Dropdown } from './dropdown';
|
||||||
|
@ -23,10 +23,11 @@ const StyledColor = styled.div`
|
|||||||
width: ${unitcalc(6)};
|
width: ${unitcalc(6)};
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: ${props =>
|
background-color: ${props =>
|
||||||
props.type === 'ERROR' ? props.theme.red
|
props.type === 'ERROR'
|
||||||
: props.type === 'WARNING' ? props.theme.orange
|
? props.theme.red
|
||||||
: props.type === 'EDUCATION' ? props.theme.green
|
: props.type === 'WARNING'
|
||||||
: props.theme.green};
|
? props.theme.orange
|
||||||
|
: props.type === 'EDUCATION' ? props.theme.green : props.theme.green};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledMessageContainer = styled.div`
|
const StyledMessageContainer = styled.div`
|
||||||
@ -48,29 +49,27 @@ const StyledClose = styled(CloseButton)`
|
|||||||
top: ${unitcalc(0.5)};
|
top: ${unitcalc(0.5)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Message = ({
|
const Message = ({ title, message, onCloseClick, type = 'MESSAGE' }) => {
|
||||||
title,
|
const renderTitle = title
|
||||||
message,
|
? <StyledTitle>
|
||||||
onCloseClick,
|
{title}
|
||||||
type='MESSAGE'
|
</StyledTitle>
|
||||||
}) => {
|
|
||||||
|
|
||||||
const renderTitle = title
|
|
||||||
? <StyledTitle>{title}</StyledTitle>
|
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const renderClose = onCloseClick
|
const renderClose = onCloseClick
|
||||||
? <StyledClose onClick={ onCloseClick } />
|
? <StyledClose onClick={onCloseClick} />
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledColor type={type} />
|
<StyledColor type={type} />
|
||||||
<StyledMessageContainer>
|
<StyledMessageContainer>
|
||||||
{ renderTitle }
|
{renderTitle}
|
||||||
<StyledMessage>{message}</StyledMessage>
|
<StyledMessage>
|
||||||
|
{message}
|
||||||
|
</StyledMessage>
|
||||||
</StyledMessageContainer>
|
</StyledMessageContainer>
|
||||||
{ renderClose }
|
{renderClose}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -79,12 +78,7 @@ Message.propTypes = {
|
|||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
message: PropTypes.string.isRequired,
|
message: PropTypes.string.isRequired,
|
||||||
onCloseClick: PropTypes.func,
|
onCloseClick: PropTypes.func,
|
||||||
type: PropTypes.oneOf([
|
type: PropTypes.oneOf(['ERROR', 'WARNING', 'EDUCATION', 'MESSAGE'])
|
||||||
'ERROR',
|
|
||||||
'WARNING',
|
|
||||||
'EDUCATION',
|
|
||||||
'MESSAGE'
|
|
||||||
])
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Message;
|
export default Message;
|
||||||
|
@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import disableScroll from 'disable-scroll';
|
import disableScroll from 'disable-scroll';
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
import theme from '../theme';
|
|
||||||
import { modalShadow } from '../boxes';
|
import { modalShadow } from '../boxes';
|
||||||
import CloseButton from '../close-button';
|
import CloseButton from '../close-button';
|
||||||
import P from '../text/p';
|
import P from '../text/p';
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import theme from '../theme';
|
|
||||||
|
|
||||||
const StyledList = styled.ul`
|
const StyledList = styled.ul`
|
||||||
display: table;
|
display: table;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
background-color: ${theme.white};
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import Baseline from '../baseline';
|
|||||||
|
|
||||||
const StyledItem = styled.li`
|
const StyledItem = styled.li`
|
||||||
float: left;
|
float: left;
|
||||||
|
background-color: ${props => props.theme.white};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ProgressbarItem = ({ children, ...props }) =>
|
const ProgressbarItem = ({ children, ...props }) =>
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled, { keyframes } from 'styled-components';
|
import styled, { keyframes } from 'styled-components';
|
||||||
|
import is from 'styled-is';
|
||||||
|
|
||||||
const animationName = keyframes`
|
const animationName = keyframes`
|
||||||
0% {
|
0% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
stroke-width: 0;
|
stroke-width: 0;
|
||||||
@ -15,6 +17,17 @@ const animationName = keyframes`
|
|||||||
const StyledFirstRect = styled.rect`
|
const StyledFirstRect = styled.rect`
|
||||||
fill: ${props => props.theme.primary};
|
fill: ${props => props.theme.primary};
|
||||||
stroke: ${props => props.theme.primary};
|
stroke: ${props => props.theme.primary};
|
||||||
|
|
||||||
|
${is('secondary')`
|
||||||
|
fill: ${props => props.theme.white};
|
||||||
|
stroke: ${props => props.theme.white};
|
||||||
|
`};
|
||||||
|
|
||||||
|
${is('tertiary')`
|
||||||
|
fill: ${props => props.theme.secondary};
|
||||||
|
stroke: ${props => props.theme.secondary};
|
||||||
|
`};
|
||||||
|
|
||||||
animation: ${animationName} 1.5s ease-out 0s infinite;
|
animation: ${animationName} 1.5s ease-out 0s infinite;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -26,9 +39,30 @@ const StyledThirdRect = StyledFirstRect.extend`
|
|||||||
animation-delay: 1s;
|
animation-delay: 1s;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default () =>
|
export default ({ secondary, tertiary }) =>
|
||||||
<svg width="28" height="10">
|
<svg width="28" height="10">
|
||||||
<StyledFirstRect x="2" y="2" width="6" height="6" />
|
<StyledFirstRect
|
||||||
<StyledSecondRect x="11" y="2" width="6" height="6" />
|
tertiary={tertiary}
|
||||||
<StyledThirdRect x="20" y="2" width="6" height="6" />
|
secondary={secondary}
|
||||||
|
x="2"
|
||||||
|
y="2"
|
||||||
|
width="6"
|
||||||
|
height="6"
|
||||||
|
/>
|
||||||
|
<StyledSecondRect
|
||||||
|
tertiary={tertiary}
|
||||||
|
secondary={secondary}
|
||||||
|
x="11"
|
||||||
|
y="2"
|
||||||
|
width="6"
|
||||||
|
height="6"
|
||||||
|
/>
|
||||||
|
<StyledThirdRect
|
||||||
|
tertiary={tertiary}
|
||||||
|
secondary={secondary}
|
||||||
|
x="20"
|
||||||
|
y="2"
|
||||||
|
width="6"
|
||||||
|
height="6"
|
||||||
|
/>
|
||||||
</svg>;
|
</svg>;
|
||||||
|
@ -16,7 +16,7 @@ const GraphNode = ({
|
|||||||
onQuickActions
|
onQuickActions
|
||||||
}) => {
|
}) => {
|
||||||
const { left, top, width, height } = data.nodeRect;
|
const { left, top, width, height } = data.nodeRect;
|
||||||
const { connected, id, children, instancesActive, isConsul, status } = data;
|
const { connected, id, children, instancesActive, isConsul } = data;
|
||||||
|
|
||||||
let x = data.x;
|
let x = data.x;
|
||||||
let y = data.y;
|
let y = data.y;
|
||||||
@ -75,7 +75,6 @@ const GraphNode = ({
|
|||||||
).children
|
).children
|
||||||
: <GraphNodeContent data={data} />;
|
: <GraphNodeContent data={data} />;
|
||||||
|
|
||||||
|
|
||||||
const nodeShadow = instancesActive
|
const nodeShadow = instancesActive
|
||||||
? <GraphShadowRect
|
? <GraphShadowRect
|
||||||
x={0}
|
x={0}
|
||||||
|
118
yarn.lock
118
yarn.lock
@ -85,7 +85,7 @@ abbrev@1:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
|
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
|
||||||
|
|
||||||
accept@2.x.x:
|
accept@^2.1.4:
|
||||||
version "2.1.4"
|
version "2.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/accept/-/accept-2.1.4.tgz#887af54ceee5c7f4430461971ec400c61d09acbb"
|
resolved "https://registry.yarnpkg.com/accept/-/accept-2.1.4.tgz#887af54ceee5c7f4430461971ec400c61d09acbb"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -201,7 +201,7 @@ amdefine@>=0.0.4:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||||
|
|
||||||
ammo@2.x.x:
|
ammo@2.x.x, ammo@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/ammo/-/ammo-2.0.4.tgz#bf80aab211698ea78f63ef5e7f113dd5d9e8917f"
|
resolved "https://registry.yarnpkg.com/ammo/-/ammo-2.0.4.tgz#bf80aab211698ea78f63ef5e7f113dd5d9e8917f"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1981,7 +1981,7 @@ call-signature@0.0.2:
|
|||||||
version "0.0.2"
|
version "0.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/call-signature/-/call-signature-0.0.2.tgz#a84abc825a55ef4cb2b028bd74e205a65b9a4996"
|
resolved "https://registry.yarnpkg.com/call-signature/-/call-signature-0.0.2.tgz#a84abc825a55ef4cb2b028bd74e205a65b9a4996"
|
||||||
|
|
||||||
call@4.x.x:
|
call@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/call/-/call-4.0.2.tgz#df76f5f51ee8dd48b856ac8400f7e69e6d7399c4"
|
resolved "https://registry.yarnpkg.com/call/-/call-4.0.2.tgz#df76f5f51ee8dd48b856ac8400f7e69e6d7399c4"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2042,12 +2042,12 @@ caniuse-api@^1.5.2:
|
|||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||||
version "1.0.30000709"
|
version "1.0.30000710"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000709.tgz#0b600072b7cdbbf6336a8758b71b9ad03268ede2"
|
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000710.tgz#f03614ef04b76ba41232755b7d4e45d7cc1c13b8"
|
||||||
|
|
||||||
caniuse-lite@^1.0.30000669, caniuse-lite@^1.0.30000670, caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000704:
|
caniuse-lite@^1.0.30000669, caniuse-lite@^1.0.30000670, caniuse-lite@^1.0.30000697, caniuse-lite@^1.0.30000704:
|
||||||
version "1.0.30000709"
|
version "1.0.30000710"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000709.tgz#e027c7a0dfd5ada58f931a1080fc71965375559b"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000710.tgz#1c249bf7c6a61161c9b10906e3ad9fa5b6761af1"
|
||||||
|
|
||||||
capture-stack-trace@^1.0.0:
|
capture-stack-trace@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@ -2061,13 +2061,13 @@ caseless@~0.12.0:
|
|||||||
version "0.12.0"
|
version "0.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||||
|
|
||||||
catbox-memory@2.x.x:
|
catbox-memory@^2.0.4:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/catbox-memory/-/catbox-memory-2.0.4.tgz#433e255902caf54233d1286429c8f4df14e822d5"
|
resolved "https://registry.yarnpkg.com/catbox-memory/-/catbox-memory-2.0.4.tgz#433e255902caf54233d1286429c8f4df14e822d5"
|
||||||
dependencies:
|
dependencies:
|
||||||
hoek "4.x.x"
|
hoek "4.x.x"
|
||||||
|
|
||||||
catbox@7.x.x:
|
catbox@^7.1.5:
|
||||||
version "7.1.5"
|
version "7.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/catbox/-/catbox-7.1.5.tgz#c56f7e8e9555d27c0dc038a96ef73e57d186bb1f"
|
resolved "https://registry.yarnpkg.com/catbox/-/catbox-7.1.5.tgz#c56f7e8e9555d27c0dc038a96ef73e57d186bb1f"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2929,7 +2929,7 @@ cryptiles@2.x.x:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boom "2.x.x"
|
boom "2.x.x"
|
||||||
|
|
||||||
cryptiles@3.x.x:
|
cryptiles@3.x.x, cryptiles@^3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
|
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3744,8 +3744,8 @@ dtrace-provider@~0.6:
|
|||||||
nan "^2.0.8"
|
nan "^2.0.8"
|
||||||
|
|
||||||
dtrace-provider@~0.8:
|
dtrace-provider@~0.8:
|
||||||
version "0.8.4"
|
version "0.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.4.tgz#f27c12dc0ec3105606f9833c118b8d711c8d532a"
|
resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.5.tgz#98ebba221afac46e1c39fd36858d8f9367524b92"
|
||||||
dependencies:
|
dependencies:
|
||||||
nan "^2.3.3"
|
nan "^2.3.3"
|
||||||
|
|
||||||
@ -3789,8 +3789,8 @@ ee-first@1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||||
|
|
||||||
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.16:
|
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.16:
|
||||||
version "1.3.16"
|
version "1.3.17"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz#d0e026735754770901ae301a21664cba45d92f7d"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.17.tgz#41c13457cc7166c5c15e767ae61d86a8cacdee5d"
|
||||||
|
|
||||||
elliptic@^6.0.0:
|
elliptic@^6.0.0:
|
||||||
version "6.4.0"
|
version "6.4.0"
|
||||||
@ -3869,13 +3869,14 @@ error-ex@^1.2.0:
|
|||||||
is-arrayish "^0.2.1"
|
is-arrayish "^0.2.1"
|
||||||
|
|
||||||
es-abstract@^1.7.0:
|
es-abstract@^1.7.0:
|
||||||
version "1.7.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
|
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.8.0.tgz#3b00385e85729932beffa9163bbea1234e932914"
|
||||||
dependencies:
|
dependencies:
|
||||||
es-to-primitive "^1.1.1"
|
es-to-primitive "^1.1.1"
|
||||||
function-bind "^1.1.0"
|
function-bind "^1.1.0"
|
||||||
|
has "^1.0.1"
|
||||||
is-callable "^1.1.3"
|
is-callable "^1.1.3"
|
||||||
is-regex "^1.0.3"
|
is-regex "^1.0.4"
|
||||||
|
|
||||||
es-to-primitive@^1.1.1:
|
es-to-primitive@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
@ -4595,10 +4596,10 @@ fillers@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.1.tgz#9d1a8f0150d47f78a898de4cd43cf079d417148e"
|
resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.1.tgz#9d1a8f0150d47f78a898de4cd43cf079d417148e"
|
||||||
|
|
||||||
finalhandler@~1.0.3:
|
finalhandler@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89"
|
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7"
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "2.6.7"
|
debug "2.6.8"
|
||||||
encodeurl "~1.0.1"
|
encodeurl "~1.0.1"
|
||||||
escape-html "~1.0.3"
|
escape-html "~1.0.3"
|
||||||
on-finished "~2.3.0"
|
on-finished "~2.3.0"
|
||||||
@ -5225,27 +5226,27 @@ hapi-swagger@^7.7.0:
|
|||||||
swagger-parser "^3.4.1"
|
swagger-parser "^3.4.1"
|
||||||
|
|
||||||
hapi@^16.4.3:
|
hapi@^16.4.3:
|
||||||
version "16.5.0"
|
version "16.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/hapi/-/hapi-16.5.0.tgz#89e4770f0034e3b69ee99ed929cc5b573805f303"
|
resolved "https://registry.yarnpkg.com/hapi/-/hapi-16.5.2.tgz#d1dadf33721c6ac3aaa905ce086d9c7ffb883092"
|
||||||
dependencies:
|
dependencies:
|
||||||
accept "2.x.x"
|
accept "^2.1.4"
|
||||||
ammo "2.x.x"
|
ammo "^2.0.4"
|
||||||
boom "5.x.x"
|
boom "^5.2.0"
|
||||||
call "4.x.x"
|
call "^4.0.2"
|
||||||
catbox "7.x.x"
|
catbox "^7.1.5"
|
||||||
catbox-memory "2.x.x"
|
catbox-memory "^2.0.4"
|
||||||
cryptiles "3.x.x"
|
cryptiles "^3.1.2"
|
||||||
heavy "4.x.x"
|
heavy "^4.0.4"
|
||||||
hoek "4.x.x"
|
hoek "^4.2.0"
|
||||||
iron "4.x.x"
|
iron "^4.0.5"
|
||||||
items "2.x.x"
|
items "^2.1.1"
|
||||||
joi "10.x.x"
|
joi "^10.6.0"
|
||||||
mimos "3.x.x"
|
mimos "^3.0.3"
|
||||||
podium "1.x.x"
|
podium "^1.3.0"
|
||||||
shot "3.x.x"
|
shot "^3.4.2"
|
||||||
statehood "5.x.x"
|
statehood "^5.0.3"
|
||||||
subtext "5.x.x"
|
subtext "^5.0.0"
|
||||||
topo "2.x.x"
|
topo "^2.0.2"
|
||||||
|
|
||||||
har-schema@^1.0.5:
|
har-schema@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
@ -5342,7 +5343,7 @@ he@1.1.x:
|
|||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||||
|
|
||||||
heavy@4.x.x:
|
heavy@^4.0.4:
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/heavy/-/heavy-4.0.4.tgz#36c91336c00ccfe852caa4d153086335cd2f00e9"
|
resolved "https://registry.yarnpkg.com/heavy/-/heavy-4.0.4.tgz#36c91336c00ccfe852caa4d153086335cd2f00e9"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5380,7 +5381,7 @@ hoek@2.x.x:
|
|||||||
version "2.16.3"
|
version "2.16.3"
|
||||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
|
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
|
||||||
|
|
||||||
hoek@4.x.x, hoek@^4.0.1, hoek@^4.1.1:
|
hoek@4.x.x, hoek@^4.0.1, hoek@^4.1.1, hoek@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
|
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
|
||||||
|
|
||||||
@ -5748,7 +5749,7 @@ ipaddr.js@1.4.0:
|
|||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0"
|
||||||
|
|
||||||
iron@4.x.x:
|
iron@4.x.x, iron@^4.0.5:
|
||||||
version "4.0.5"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/iron/-/iron-4.0.5.tgz#4f042cceb8b9738f346b59aa734c83a89bc31428"
|
resolved "https://registry.yarnpkg.com/iron/-/iron-4.0.5.tgz#4f042cceb8b9738f346b59aa734c83a89bc31428"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5990,7 +5991,7 @@ is-redirect@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
|
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
|
||||||
|
|
||||||
is-regex@^1.0.3:
|
is-regex@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
|
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -6189,7 +6190,7 @@ isurl@^1.0.0-alpha5:
|
|||||||
has-to-string-tag-x "^1.2.0"
|
has-to-string-tag-x "^1.2.0"
|
||||||
is-object "^1.0.1"
|
is-object "^1.0.1"
|
||||||
|
|
||||||
items@2.x.x:
|
items@2.x.x, items@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198"
|
resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198"
|
||||||
|
|
||||||
@ -7484,7 +7485,7 @@ mimic-response@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
|
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
|
||||||
|
|
||||||
mimos@3.x.x:
|
mimos@^3.0.3:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/mimos/-/mimos-3.0.3.tgz#b9109072ad378c2b72f6a0101c43ddfb2b36641f"
|
resolved "https://registry.yarnpkg.com/mimos/-/mimos-3.0.3.tgz#b9109072ad378c2b72f6a0101c43ddfb2b36641f"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -7556,8 +7557,8 @@ moment@2.x.x, moment@^2.10.6, moment@^2.6.0:
|
|||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
|
||||||
|
|
||||||
mooremachine@^2.0.1:
|
mooremachine@^2.0.1:
|
||||||
version "2.1.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/mooremachine/-/mooremachine-2.1.0.tgz#e935cf356ca6b6a28b92fbd446d1b31a5c19848d"
|
resolved "https://registry.yarnpkg.com/mooremachine/-/mooremachine-2.2.0.tgz#ec70bf284f5ae478afa7b359b294af67e2c97906"
|
||||||
dependencies:
|
dependencies:
|
||||||
assert-plus ">=0.2.0 <0.3.0"
|
assert-plus ">=0.2.0 <0.3.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@ -8448,7 +8449,7 @@ pluralize@^6.0.0:
|
|||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-6.0.0.tgz#d9b51afad97d3d51075cc1ddba9b132cacccb7ba"
|
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-6.0.0.tgz#d9b51afad97d3d51075cc1ddba9b132cacccb7ba"
|
||||||
|
|
||||||
podium@1.x.x:
|
podium@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/podium/-/podium-1.3.0.tgz#3c490f54d16f10f5260cbe98641f1cb733a8851c"
|
resolved "https://registry.yarnpkg.com/podium/-/podium-1.3.0.tgz#3c490f54d16f10f5260cbe98641f1cb733a8851c"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -10401,7 +10402,7 @@ sherlock@1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/sherlock/-/sherlock-1.0.0.tgz#e246eacfd72c0e3b3e8243a6c9e55340d80c854e"
|
resolved "https://registry.yarnpkg.com/sherlock/-/sherlock-1.0.0.tgz#e246eacfd72c0e3b3e8243a6c9e55340d80c854e"
|
||||||
|
|
||||||
shot@3.x.x:
|
shot@^3.4.2:
|
||||||
version "3.4.2"
|
version "3.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/shot/-/shot-3.4.2.tgz#1e5c3f6f2b26649adc42f7eb350214a5a0291d67"
|
resolved "https://registry.yarnpkg.com/shot/-/shot-3.4.2.tgz#1e5c3f6f2b26649adc42f7eb350214a5a0291d67"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -10755,7 +10756,7 @@ state-toggle@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.0.tgz#d20f9a616bb4f0c3b98b91922d25b640aa2bc425"
|
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.0.tgz#d20f9a616bb4f0c3b98b91922d25b640aa2bc425"
|
||||||
|
|
||||||
statehood@5.x.x:
|
statehood@^5.0.3:
|
||||||
version "5.0.3"
|
version "5.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/statehood/-/statehood-5.0.3.tgz#c07a75620db5379b60d2edd47f538002a8ac7dd6"
|
resolved "https://registry.yarnpkg.com/statehood/-/statehood-5.0.3.tgz#c07a75620db5379b60d2edd47f538002a8ac7dd6"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -10940,8 +10941,8 @@ style-search@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
|
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
|
||||||
|
|
||||||
styled-components@^2.1.1:
|
styled-components@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.1.1.tgz#7e9b5bc319ee3963b47aebb74f4658119ea9d484"
|
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.1.2.tgz#bb419978e1287c5d0d88fa9106b2dd75f66a324c"
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer "^5.0.3"
|
buffer "^5.0.3"
|
||||||
css-to-react-native "^2.0.3"
|
css-to-react-native "^2.0.3"
|
||||||
@ -11127,7 +11128,7 @@ stylis@^3.2.1:
|
|||||||
version "3.2.8"
|
version "3.2.8"
|
||||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.2.8.tgz#9b23a3e06597f7944a3d9ae880d5796248b8784f"
|
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.2.8.tgz#9b23a3e06597f7944a3d9ae880d5796248b8784f"
|
||||||
|
|
||||||
subtext@5.x.x:
|
subtext@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/subtext/-/subtext-5.0.0.tgz#9c3f083018bb1586b167ad8cfd87083f5ccdfe0f"
|
resolved "https://registry.yarnpkg.com/subtext/-/subtext-5.0.0.tgz#9c3f083018bb1586b167ad8cfd87083f5ccdfe0f"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -11551,7 +11552,7 @@ to-vfile@^2.1.1:
|
|||||||
is-buffer "^1.1.4"
|
is-buffer "^1.1.4"
|
||||||
vfile "^2.0.0"
|
vfile "^2.0.0"
|
||||||
|
|
||||||
topo@2.x.x:
|
topo@2.x.x, topo@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
resolved "https://registry.yarnpkg.com/topo/-/topo-2.0.2.tgz#cd5615752539057c0dc0491a621c3bc6fbe1d182"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -12576,13 +12577,6 @@ yamlish@0.0.7:
|
|||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/yamlish/-/yamlish-0.0.7.tgz#b4af9a1dcc63618873c3d6e451ec3213c39a57fb"
|
resolved "https://registry.yarnpkg.com/yamlish/-/yamlish-0.0.7.tgz#b4af9a1dcc63618873c3d6e451ec3213c39a57fb"
|
||||||
|
|
||||||
yamljs@^0.2.10:
|
|
||||||
version "0.2.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/yamljs/-/yamljs-0.2.10.tgz#481cc7c25ca73af59f591f0c96e3ce56c757a40f"
|
|
||||||
dependencies:
|
|
||||||
argparse "^1.0.7"
|
|
||||||
glob "^7.0.5"
|
|
||||||
|
|
||||||
yargs-parser@^4.2.0:
|
yargs-parser@^4.2.0:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
|
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
|
||||||
|
Loading…
Reference in New Issue
Block a user