feat: environment stage

This commit is contained in:
Sérgio Ramos 2017-07-05 14:33:16 +01:00 committed by Judit Greskovits
parent 9730b5733a
commit 5ccd873a54
13 changed files with 353 additions and 138 deletions

View File

@ -41,6 +41,7 @@
"react-redux": "^5.0.5", "react-redux": "^5.0.5",
"react-router": "^4.1.1", "react-router": "^4.1.1",
"react-router-dom": "^4.1.1", "react-router-dom": "^4.1.1",
"react-simple-table": "^1.0.1",
"react-styled-flexboxgrid": "^2.0.1", "react-styled-flexboxgrid": "^2.0.1",
"redux": "^3.6.0", "redux": "^3.6.0",
"redux-actions": "^2.0.3", "redux-actions": "^2.0.3",

View File

@ -1,6 +1,7 @@
import React from 'react'; import React 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 { Dots2 } from 'styled-text-spinners'; import { Dots2 } from 'styled-text-spinners';
import Bundle from 'react-bundle'; import Bundle from 'react-bundle';
@ -48,9 +49,12 @@ const ButtonsRow = Row.extend`
margin-bottom: ${remcalc(60)}; margin-bottom: ${remcalc(60)};
`; `;
const Editor = ManifestEditor => ({ input, defaultValue }) => const MEditor = ManifestEditor => ({ input, defaultValue }) =>
<ManifestEditor mode="yaml" {...input} value={input.value || defaultValue} />; <ManifestEditor mode="yaml" {...input} value={input.value || defaultValue} />;
const EEditor = ManifestEditor => ({ input, defaultValue }) =>
<ManifestEditor mode="ini" {...input} value={input.value || defaultValue} />;
export const Name = ({ handleSubmit, onCancel, dirty }) => export const Name = ({ handleSubmit, onCancel, dirty }) =>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<Row> <Row>
@ -67,14 +71,7 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
</ButtonsRow> </ButtonsRow>
</form>; </form>;
export const Manifest = ({ export const Manifest = ({ handleSubmit, onCancel, dirty, defaultValue }) =>
handleSubmit,
onCancel,
dirty,
defaultValue,
mode,
loading
}) =>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<Bundle load={() => import('joyent-manifest-editor')}> <Bundle load={() => import('joyent-manifest-editor')}>
{ManifestEditor => {ManifestEditor =>
@ -82,7 +79,33 @@ export const Manifest = ({
? <Field ? <Field
name="manifest" name="manifest"
defaultValue={defaultValue} defaultValue={defaultValue}
component={Editor(ManifestEditor)} component={MEditor(ManifestEditor)}
/>
: <Dots2 />}
</Bundle>
<ButtonsRow>
<Button onClick={onCancel} secondary>Cancel</Button>
<Button disabled={!dirty} type="submit">
Environment
</Button>
</ButtonsRow>
</form>;
export const Environment = ({
handleSubmit,
onCancel,
dirty,
defaultValue,
loading
}) =>
<form onSubmit={handleSubmit}>
<Bundle load={() => import('joyent-manifest-editor')}>
{ManifestEditor =>
ManifestEditor
? <Field
name="environment"
defaultValue={defaultValue}
component={EEditor(ManifestEditor)}
/> />
: <Dots2 />} : <Dots2 />}
</Bundle> </Bundle>
@ -95,11 +118,29 @@ export const Manifest = ({
</form>; </form>;
export const Review = ({ handleSubmit, onCancel, dirty, ...state }) => { export const Review = ({ handleSubmit, onCancel, dirty, ...state }) => {
const serviceList = forceArray(state.services).map(({ name, image }) => const serviceList = forceArray(state.services).map(({ name, config }) =>
<ServiceCard key={name}> <ServiceCard key={name}>
<Dl> <Dl>
<dt><ServiceName>{name}</ServiceName></dt> <dt><ServiceName>{name}</ServiceName></dt>
<dt><ImageTitle>Image:</ImageTitle> <Image>{image}</Image></dt> <dt><ImageTitle>Image:</ImageTitle> <Image>{config.image}</Image></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>
</ServiceCard> </ServiceCard>
); );
@ -136,7 +177,7 @@ export const Progress = ({ stage, create, edit }) => {
</ProgressbarButton> </ProgressbarButton>
</ProgressbarItem>; </ProgressbarItem>;
const _manifestCompleted = stage === 'review'; const _manifestCompleted = ['environment', 'review'].indexOf(stage) >= 0;
const _manifestActive = create ? stage === 'manifest' : stage === 'edit'; const _manifestActive = create ? stage === 'manifest' : stage === 'edit';
const _manifest = ( const _manifest = (
@ -147,7 +188,22 @@ export const Progress = ({ stage, create, edit }) => {
active={_manifestActive} active={_manifestActive}
first={edit} first={edit}
> >
Define services Define Services
</ProgressbarButton>
</ProgressbarItem>
);
const _environmentCompleted = stage === 'review';
const _environmentActive = stage === 'environment';
const _environment = (
<ProgressbarItem>
<ProgressbarButton
zIndex="8"
completed={_environmentCompleted}
active={_environmentActive}
>
Define Environment
</ProgressbarButton> </ProgressbarButton>
</ProgressbarItem> </ProgressbarItem>
); );
@ -156,7 +212,7 @@ export const Progress = ({ stage, create, edit }) => {
const _review = ( const _review = (
<ProgressbarItem> <ProgressbarItem>
<ProgressbarButton zIndex="8" active={stage === 'review'} last> <ProgressbarButton zIndex="7" active={_reviewActive} last>
Review and deploy Review and deploy
</ProgressbarButton> </ProgressbarButton>
</ProgressbarItem> </ProgressbarItem>
@ -166,6 +222,7 @@ export const Progress = ({ stage, create, edit }) => {
<Progressbar> <Progressbar>
{_name} {_name}
{_manifest} {_manifest}
{_environment}
{_review} {_review}
</Progressbar> </Progressbar>
); );

View File

@ -96,6 +96,7 @@ const ServiceListItem = ({
</CardDescription> </CardDescription>
<CardOptions onClick={handleCardOptionsClick} /> <CardOptions onClick={handleCardOptionsClick} />
</StyledCardHeader>; </StyledCardHeader>;
const view = children const view = children
? <CardGroupView> ? <CardGroupView>
{children} {children}

View File

@ -12,7 +12,12 @@ import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.
import DeploymentGroupConfigQuery from '@graphql/DeploymentGroupConfig.gql'; import DeploymentGroupConfigQuery from '@graphql/DeploymentGroupConfig.gql';
import { client } from '@state/store'; import { client } from '@state/store';
import { Name, Manifest, Review } from '@components/deployment-groups/create'; import {
Name,
Manifest,
Environment,
Review
} from '@components/deployment-groups/create';
// 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
@ -51,6 +56,12 @@ class DeploymentGroupEditOrCreate extends Component {
forceUnregisterOnUnmount: 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, destroyOnUnmount: true,
@ -62,17 +73,20 @@ class DeploymentGroupEditOrCreate extends Component {
manifestStage: create ? 'manifest' : 'edit', manifestStage: create ? 'manifest' : 'edit',
name: '', name: '',
manifest: '', manifest: '',
environment: '',
services: [], services: [],
loading: false, loading: false,
error: null, error: null,
NameForm, NameForm,
ManifestForm, ManifestForm,
EnvironmentForm,
ReviewForm ReviewForm
}; };
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),
environment: this.renderEnvironmentEditor.bind(this),
review: this.renderReview.bind(this) review: this.renderReview.bind(this)
}; };
@ -80,6 +94,7 @@ class DeploymentGroupEditOrCreate extends Component {
type === 'create' && this.handleNameSubmit.bind(this); type === 'create' && this.handleNameSubmit.bind(this);
this.handleManifestSubmit = this.handleManifestSubmit.bind(this); this.handleManifestSubmit = this.handleManifestSubmit.bind(this);
this.handleEnvironmentSubmit = this.handleEnvironmentSubmit.bind(this);
this.handleReviewSubmit = this.handleReviewSubmit.bind(this); this.handleReviewSubmit = this.handleReviewSubmit.bind(this);
this.handleCancel = this.handleCancel.bind(this); this.handleCancel = this.handleCancel.bind(this);
@ -117,7 +132,7 @@ class DeploymentGroupEditOrCreate extends Component {
}; };
provision = async deploymentGroupId => { provision = async deploymentGroupId => {
const { manifest } = this.state; const { manifest, environment } = this.state;
const { provisionManifest } = this.props; const { provisionManifest } = this.props;
const [err] = await intercept( const [err] = await intercept(
@ -125,6 +140,7 @@ class DeploymentGroupEditOrCreate extends Component {
deploymentGroupId, deploymentGroupId,
type: 'COMPOSE', type: 'COMPOSE',
format: 'YAML', format: 'YAML',
environment,
raw: manifest raw: manifest
}) })
); );
@ -145,16 +161,24 @@ class DeploymentGroupEditOrCreate extends Component {
} }
handleManifestSubmit({ manifest = '' }) { handleManifestSubmit({ manifest = '' }) {
const { name } = this.state; this.setState({ manifest }, () => {
this.redirect({ stage: 'environment', prog: true });
});
}
handleEnvironmentSubmit({ environment = '' }) {
const { name, manifest } = this.state;
const getConfig = async () => { const getConfig = async () => {
const [err, conf] = await intercept( const [err, conf] = await intercept(
client.query({ client.query({
query: DeploymentGroupConfigQuery, query: DeploymentGroupConfigQuery,
fetchPolicy: 'network-only',
variables: { variables: {
deploymentGroupName: name, deploymentGroupName: name,
type: 'COMPOSE', type: 'COMPOSE',
format: 'YAML', format: 'YAML',
environment,
raw: manifest raw: manifest
} }
}) })
@ -174,7 +198,7 @@ class DeploymentGroupEditOrCreate extends Component {
}); });
}; };
this.setState({ manifest, loading: true }, getConfig); this.setState({ environment, loading: true }, getConfig);
} }
handleReviewSubmit() { handleReviewSubmit() {
@ -237,6 +261,18 @@ class DeploymentGroupEditOrCreate extends Component {
defaultValue={this.props.manifest} defaultValue={this.props.manifest}
onSubmit={this.handleManifestSubmit} onSubmit={this.handleManifestSubmit}
onCancel={this.handleCancel} onCancel={this.handleCancel}
/>
);
}
renderEnvironmentEditor() {
const { EnvironmentForm } = this.state;
return (
<EnvironmentForm
defaultValue={this.props.environment}
onSubmit={this.handleEnvironmentSubmit}
onCancel={this.handleCancel}
loading={this.state.loading} loading={this.state.loading}
/> />
); );
@ -276,10 +312,20 @@ class DeploymentGroupEditOrCreate extends Component {
return this.redirect({ stage: defaultStage }); return this.redirect({ stage: defaultStage });
} }
if (stage === 'review' && !this.state.manifest) { if (stage === 'environment' && !this.state.manifest) {
return this.redirect({ stage: manifestStage }); return this.redirect({ stage: manifestStage });
} }
if (stage === 'review' && !this.state.environment) {
if (!this.state.manifest) {
return this.redirect({ stage: manifestStage });
}
if (!this.state.environment) {
return this.redirect({ stage: 'environment' });
}
}
return this.stages[stage](); return this.stages[stage]();
} }
} }

View File

@ -1,8 +1,22 @@
#import "./ServiceInfo.gql" #import "./ServiceInfo.gql"
query config($deploymentGroupName: String!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) { query config($deploymentGroupName: String!, $type: ManifestType!, $format: ManifestFormat!, $environment: String!, $raw: String!) {
config(deploymentGroupName: $deploymentGroupName, type: $type, format: $format, raw: $raw) { config(deploymentGroupName: $deploymentGroupName, type: $type, format: $format, environment: $environment, raw: $raw) {
image
...ServiceInfo ...ServiceInfo
config {
id
image
ports
environment {
id
name
value
}
labels {
id
name
value
}
}
} }
} }

View File

@ -1,5 +1,5 @@
mutation provisionManifest($deploymentGroupId: ID!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) { mutation provisionManifest($deploymentGroupId: ID!, $type: ManifestType!, $format: ManifestFormat!, $environment: String!, $raw: String!) {
provisionManifest(deploymentGroupId: $deploymentGroupId, type: $type, format: $format, raw: $raw) { provisionManifest(deploymentGroupId: $deploymentGroupId, type: $type, format: $format, environment: $environment, raw: $raw) {
scale { scale {
serviceName serviceName
replicas replicas

View File

@ -68,15 +68,14 @@ const activeInstanceStatuses = [
'INCOMPLETE' 'INCOMPLETE'
]; ];
const getInstanceStatuses = (service) => { const getInstanceStatuses = service => {
const instanceStatuses = service.instances.reduce((statuses, instance) => { const instanceStatuses = service.instances.reduce((statuses, instance) => {
// if (instance.status !== 'RUNNING') { // if (instance.status !== 'RUNNING') {
if (statuses[instance.status]) { if (statuses[instance.status]) {
statuses[instance.status]++; statuses[instance.status]++;
} else { } else {
statuses[instance.status] = 1; statuses[instance.status] = 1;
} }
// } // }
return statuses; return statuses;
}, {}); }, {});
@ -85,31 +84,35 @@ const getInstanceStatuses = (service) => {
status, status,
count: instanceStatuses[status] count: instanceStatuses[status]
})); }));
}
const getInstancesActive = (instanceStatuses) => {
return instanceStatuses.reduce((active, instanceStatus) =>
activeInstanceStatuses.indexOf(instanceStatus.status) === -1 ?
active : true, false);
}
const getService = (service, index) => {
const statuses = getInstanceStatuses(service);
const instancesActive = getInstancesActive(statuses);
const instanceStatuses = statuses.length === 1 && statuses[0].status === 'RUNNING' ?
[] : statuses;
return ({
index,
...service,
instanceStatuses,
instancesActive,
isConsul: service.slug === 'consul'
});
}; };
const processServices = (services) => { const getInstancesActive = instanceStatuses => {
return instanceStatuses.reduce(
(active, instanceStatus) =>
activeInstanceStatuses.indexOf(instanceStatus.status) === -1
? active
: true,
false
);
};
const getService = (service, index) => {
const statuses = getInstanceStatuses(service);
const instancesActive = getInstancesActive(statuses);
const instanceStatuses = statuses.length === 1 &&
statuses[0].status === 'RUNNING'
? []
: statuses;
return {
index,
...service,
instanceStatuses,
instancesActive,
isConsul: service.slug === 'consul'
};
};
const processServices = services => {
return forceArray(services).reduce((ss, s, i) => { return forceArray(services).reduce((ss, s, i) => {
if (s.parent) { if (s.parent) {
const parents = ss.filter(parentS => parentS.id === s.parent); const parents = ss.filter(parentS => parentS.id === s.parent);
@ -124,7 +127,9 @@ const processServices = (services) => {
parent.children = []; parent.children = [];
} }
const child = getService(s, i); const child = getService(s, i);
parent.instancesActive = parent.instancesActive ? true : child.instancesActive; parent.instancesActive = parent.instancesActive
? true
: child.instancesActive;
parent.children.push(child); parent.children.push(child);
} else { } else {
const serviceIndex = ss.findIndex(existingS => existingS.id === s.id); const serviceIndex = ss.findIndex(existingS => existingS.id === s.id);
@ -141,19 +146,22 @@ const processServices = (services) => {
}, []); }, []);
}; };
const processServicesForTopology = (services) => { const processServicesForTopology = services => {
const processedServices = processServices(services); const processedServices = processServices(services);
const connectedServices = processedServices.reduce((connections, service) => const connectedServices = processedServices.reduce(
service.connections && service.connections.length ? (connections, service) =>
connections.concat(service.connections).concat(service.id) : connections, []); service.connections && service.connections.length
? connections.concat(service.connections).concat(service.id)
: connections,
[]
);
return processedServices.map(service => ({ return processedServices.map(service => ({
...service, ...service,
connected: connectedServices.indexOf(service.id) !== -1 connected: connectedServices.indexOf(service.id) !== -1
})); }));
} };
export { export {
deploymentGroupBySlug as deploymentGroupBySlugSelector, deploymentGroupBySlug as deploymentGroupBySlugSelector,

View File

@ -1,6 +1,3 @@
scalar Date
scalar Object
type Portal { type Portal {
id: ID! id: ID!
user: User! user: User!
@ -36,6 +33,7 @@ type DeploymentGroup {
} }
type ServiceScale { type ServiceScale {
id: ID!
serviceName: String! serviceName: String!
replicas: Int! replicas: Int!
} }
@ -50,6 +48,7 @@ enum ConvergenceActionType {
} }
type ConvergenceAction { type ConvergenceAction {
id: ID!
type: ConvergenceActionType! type: ConvergenceActionType!
service: String! # service name service: String! # service name
toProcess: Int, # merely used for book keeping toProcess: Int, # merely used for book keeping
@ -58,6 +57,7 @@ type ConvergenceAction {
} }
type Version { type Version {
id: ID!
manifest: Manifest! manifest: Manifest!
scale(serviceName: String): [ServiceScale]! scale(serviceName: String): [ServiceScale]!
plan: [ConvergenceAction] plan: [ConvergenceAction]
@ -79,8 +79,8 @@ type Manifest {
id: ID! id: ID!
type: ManifestType! type: ManifestType!
format: ManifestFormat! format: ManifestFormat!
environment: String!
raw: String! raw: String!
obj: Object
} }
enum ServiceStatus { enum ServiceStatus {
@ -95,6 +95,21 @@ enum ServiceStatus {
UNKNOWN UNKNOWN
} }
type KeyValue {
id: ID!
name: String!
value: String!
}
type ServiceConfig {
id: ID!
package: Package # we don't have this in current mock data
environment: [KeyValue]
image: String # used only for config
labels: [KeyValue]
ports: [String]
}
# immutable # immutable
type Service { type Service {
id: ID! # unique id for db row id: ID! # unique id for db row
@ -102,11 +117,9 @@ type Service {
name: String! # human readable name name: String! # human readable name
slug: String! slug: String!
instances(name: String, machineId: ID, status: InstanceStatus): [Instance]! instances(name: String, machineId: ID, status: InstanceStatus): [Instance]!
connections: [String!] # list of serviceIds connections: [String] # list of serviceIds
parent: ID # parent service id parent: ID # parent service id
package: Package! # we don't have this in current mock data, config: ServiceConfig
environment: [Environment]
image: String # used only for config
status: ServiceStatus status: ServiceStatus
} }
@ -124,12 +137,6 @@ type Package {
group: String! group: String!
} }
# environment variables
type Environment {
name: String!
value: String!
}
enum InstanceStatus { enum InstanceStatus {
PROVISIONING PROVISIONING
READY READY
@ -184,7 +191,7 @@ type Query {
datacenter(id: ID, region: String): Datacenter datacenter(id: ID, region: String): Datacenter
datacenters: [Datacenter] datacenters: [Datacenter]
config(deploymentGroupName: String!, type: ManifestType!, format: ManifestFormat!, raw: String!): [Service] config(deploymentGroupName: String!, type: ManifestType!, format: ManifestFormat!, environment: String!, raw: String!): [Service]
importableDeploymentGroups: [DeploymentGroup] importableDeploymentGroups: [DeploymentGroup]
} }
@ -192,7 +199,7 @@ type Mutation {
createDeploymentGroup(name: String!): DeploymentGroup createDeploymentGroup(name: String!): DeploymentGroup
updateDeploymentGroup(id: ID!, name: String!): DeploymentGroup updateDeploymentGroup(id: ID!, name: String!): DeploymentGroup
provisionManifest(deploymentGroupId: ID!, type: ManifestType!, format: ManifestFormat!, raw: String!): Version provisionManifest(deploymentGroupId: ID!, type: ManifestType!, format: ManifestFormat!, environment: String!, raw: String!): Version
scale(serviceId: ID!, replicas: Int!): Version scale(serviceId: ID!, replicas: Int!): Version
stopServices(ids: [ID]!): [Service] stopServices(ids: [ID]!): [Service]

View File

@ -22,13 +22,17 @@ module.exports = class DockerComposeClient extends EventEmitter {
return this.client.close(); return this.client.close();
} }
provision({ projectName, manifest }, cb) { provision({ projectName, environment, manifest }, cb) {
// eslint-disable-next-line camelcase return this._invoke('up', {
return this._invoke('up', { project_name: projectName }, manifest, cb); // eslint-disable-next-line camelcase
project_name: projectName,
environment
}, manifest, cb);
} }
scale({ projectName, services, manifest }, cb) { scale({ projectName, services, environment, manifest }, cb) {
const options = { const options = {
environment,
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
project_name: projectName, project_name: projectName,
services: Object.keys(services).map(name => ({ services: Object.keys(services).map(name => ({
@ -40,10 +44,11 @@ module.exports = class DockerComposeClient extends EventEmitter {
return this._invoke('scale', options, manifest, cb); return this._invoke('scale', options, manifest, cb);
} }
config({ projectName, manifest }, cb) { config({ projectName, environment, manifest }, cb) {
const options = { const options = {
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
project_name: projectName project_name: projectName,
environment
}; };
return this._invoke('config', options, manifest, cb); return this._invoke('config', options, manifest, cb);

View File

@ -4,6 +4,7 @@ import 'codemirror/addon/fold/foldgutter.css';
import 'codemirror/addon/lint/lint.css'; import 'codemirror/addon/lint/lint.css';
import 'codemirror/mode/yaml/yaml'; import 'codemirror/mode/yaml/yaml';
import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/properties/properties';
import 'codemirror/addon/edit/closebrackets'; import 'codemirror/addon/edit/closebrackets';
import 'codemirror/addon/edit/matchbrackets'; import 'codemirror/addon/edit/matchbrackets';
import 'codemirror/addon/fold/foldcode'; import 'codemirror/addon/fold/foldcode';
@ -60,7 +61,8 @@ class ManifestEditor extends Component {
name: 'javascript', name: 'javascript',
json: true json: true
}, },
yaml: 'yaml' yaml: 'yaml',
ini: 'properties'
}; };
return Object.assign({}, options, { return Object.assign({}, options, {

View File

@ -13,7 +13,6 @@ const Hoek = require('hoek');
const Triton = require('triton'); const Triton = require('triton');
const ParamCase = require('param-case'); const ParamCase = require('param-case');
const Penseur = require('penseur'); const Penseur = require('penseur');
const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch');
const UniqBy = require('lodash.uniqby'); const UniqBy = require('lodash.uniqby');
const Find = require('lodash.find'); const Find = require('lodash.find');
const Get = require('lodash.get'); const Get = require('lodash.get');
@ -24,6 +23,7 @@ const VAsync = require('vasync');
// local modules // local modules
const Transform = require('./transform'); const Transform = require('./transform');
const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch');
const NON_IMPORTABLE_STATES = [ const NON_IMPORTABLE_STATES = [
@ -153,7 +153,11 @@ class Data extends EventEmitter {
const portal = portals.shift(); const portal = portals.shift();
// Sub query/filter for deploymentGroups // Sub query/filter for deploymentGroups
const deploymentGroups = (args) => { const deploymentGroups = (args, cb) => {
if (typeof cb === 'function') {
return this.getDeploymentGroups(args, cb);
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.getDeploymentGroups(args, internals.resolveCb(resolve, reject)); this.getDeploymentGroups(args, internals.resolveCb(resolve, reject));
}); });
@ -372,7 +376,7 @@ class Data extends EventEmitter {
} }
if (!deploymentGroups || !deploymentGroups.length) { if (!deploymentGroups || !deploymentGroups.length) {
return cb(null, {}); return cb();
} }
cb(null, Transform.fromDeploymentGroup(this._getDeploymentGroupFns(deploymentGroups[0]))); cb(null, Transform.fromDeploymentGroup(this._getDeploymentGroupFns(deploymentGroups[0])));
@ -512,6 +516,7 @@ class Data extends EventEmitter {
]); ]);
return { return {
id: Uuid(),
serviceName: name, serviceName: name,
replicas: Number.isFinite(currentScale) ? currentScale : 1 replicas: Number.isFinite(currentScale) ? currentScale : 1
}; };
@ -554,6 +559,7 @@ class Data extends EventEmitter {
}); });
return { return {
id: Uuid(),
serviceName: name, serviceName: name,
replicas: existingMachines.length ? existingMachines.length : 1 replicas: existingMachines.length ? existingMachines.length : 1
}; };
@ -565,7 +571,7 @@ class Data extends EventEmitter {
this._listMachines(deploymentGroupName, handleMachinesList); this._listMachines(deploymentGroupName, handleMachinesList);
} }
scale ({ serviceId, replicas }, cb) { scale ({ serviceId, environment, replicas }, cb) {
Hoek.assert(serviceId, 'service id is required'); Hoek.assert(serviceId, 'service id is required');
Hoek.assert(typeof replicas === 'number' && replicas >= 0, 'replicas must be a number no less than 0'); Hoek.assert(typeof replicas === 'number' && replicas >= 0, 'replicas must be a number no less than 0');
@ -636,6 +642,7 @@ class Data extends EventEmitter {
this._dockerCompose.scale({ this._dockerCompose.scale({
projectName: ctx.deploymentGroup.name, projectName: ctx.deploymentGroup.name,
environment,
services: { services: {
[ctx.service.name]: replicas [ctx.service.name]: replicas
}, },
@ -647,6 +654,7 @@ class Data extends EventEmitter {
const getNewScale = () => { const getNewScale = () => {
return ctx.currentScale.map(({ serviceName, replicas }) => { return ctx.currentScale.map(({ serviceName, replicas }) => {
return { return {
id: Uuid(),
serviceName: serviceName, serviceName: serviceName,
replicas: serviceName === ctx.service.name ? replicas: serviceName === ctx.service.name ?
(ctx.serviceScale + ctx.diff) : (ctx.serviceScale + ctx.diff) :
@ -661,6 +669,7 @@ class Data extends EventEmitter {
deploymentGroupId: ctx.deploymentGroup.id, deploymentGroupId: ctx.deploymentGroup.id,
scale: getNewScale(), scale: getNewScale(),
plan: [{ plan: [{
id: Uuid(),
type: 'REMOVE', type: 'REMOVE',
service: ctx.service.name, service: ctx.service.name,
toProcess: Math.abs(ctx.diff), toProcess: Math.abs(ctx.diff),
@ -683,6 +692,7 @@ class Data extends EventEmitter {
deploymentGroupId: ctx.deploymentGroup.id, deploymentGroupId: ctx.deploymentGroup.id,
scale: getNewScale(), scale: getNewScale(),
plan: [{ plan: [{
id: Uuid(),
type: 'CREATE', type: 'CREATE',
service: ctx.service.name, service: ctx.service.name,
toProcess: Math.abs(ctx.diff), toProcess: Math.abs(ctx.diff),
@ -908,6 +918,7 @@ class Data extends EventEmitter {
if (!provision) { if (!provision) {
return { return {
id: Uuid(),
type: 'REMOVE', type: 'REMOVE',
service: name, service: name,
toProcess: machines.length, toProcess: machines.length,
@ -918,6 +929,7 @@ class Data extends EventEmitter {
const ActionMap = { const ActionMap = {
'NOOP': () => { 'NOOP': () => {
return { return {
id: Uuid(),
type: 'NOOP', type: 'NOOP',
service: name, service: name,
machines machines
@ -925,6 +937,7 @@ class Data extends EventEmitter {
}, },
'CREATE': () => { 'CREATE': () => {
return { return {
id: Uuid(),
type: 'CREATE', type: 'CREATE',
service: name, service: name,
toProcess: scale, toProcess: scale,
@ -933,6 +946,7 @@ class Data extends EventEmitter {
}, },
'RECREATE': () => { 'RECREATE': () => {
return { return {
id: Uuid(),
type: 'CREATE', type: 'CREATE',
service: name, service: name,
toProcess: machines.length, toProcess: machines.length,
@ -941,6 +955,7 @@ class Data extends EventEmitter {
}, },
'START': () => { 'START': () => {
return { return {
id: Uuid(),
type: 'START', type: 'START',
service: name, service: name,
machines machines
@ -1077,12 +1092,17 @@ class Data extends EventEmitter {
const action = Get(provision, 'plan.action', 'noop').toUpperCase(); const action = Get(provision, 'plan.action', 'noop').toUpperCase();
const service = services.shift(); const service = services.shift();
const { config } = Find(ctx.config, ['name', serviceName], {
config: {}
});
const payload = { const payload = {
hash: provision.hash, hash: provision.hash,
deploymentGroupId: ctx.currentDeploymentGroup.id, deploymentGroupId: ctx.currentDeploymentGroup.id,
name: serviceName, name: serviceName,
slug: ParamCase(serviceName), slug: ParamCase(serviceName),
status: ServiceStatusFromPlan[action] status: ServiceStatusFromPlan[action],
config
}; };
return !service ? return !service ?
@ -1133,6 +1153,7 @@ class Data extends EventEmitter {
this._dockerCompose.provision({ this._dockerCompose.provision({
projectName: ctx.currentDeploymentGroup.name, projectName: ctx.currentDeploymentGroup.name,
environment: clientManifest.environment,
manifest: ctx.newManifest.raw manifest: ctx.newManifest.raw
}, handleProvisionResponse); }, handleProvisionResponse);
}); });
@ -1830,23 +1851,19 @@ class Data extends EventEmitter {
}); });
} }
updateInstance ({ id, status, healthy}, cb) { updateInstance (clientInstance, cb) {
const changes = { id }; const instance = Transform.toInstance(clientInstance);
if (typeof healthy === 'boolean') { if (typeof instance.healthy !== 'boolean') {
changes.healthy = healthy; instance.healthy = null;
} }
if (status) { this._db.instances.update([instance], (err) => {
changes.status = status;
}
this._db.instances.update([changes], (err) => {
if (err) { if (err) {
return cb(err); return cb(err);
} }
this.getInstance({ id }, cb); this.getInstance({ id: instance.id }, cb);
}); });
} }
@ -1989,7 +2006,7 @@ class Data extends EventEmitter {
}); });
} }
getConfig ({deploymentGroupName = '', type = '', format = '', raw = '' }, cb) { getConfig ({deploymentGroupName = '', type = '', format = '', environment = '', raw = '' }, cb) {
if (type.toUpperCase() !== 'COMPOSE') { if (type.toUpperCase() !== 'COMPOSE') {
return cb(new Error('"COMPOSE" is the only `type` supported')); return cb(new Error('"COMPOSE" is the only `type` supported'));
} }
@ -2002,6 +2019,7 @@ class Data extends EventEmitter {
this._dockerCompose.config({ this._dockerCompose.config({
projectName: deploymentGroupName, projectName: deploymentGroupName,
environment,
manifest: raw manifest: raw
}, (err, config = {}) => { }, (err, config = {}) => {
if (err) { if (err) {
@ -2021,15 +2039,34 @@ class Data extends EventEmitter {
} }
cb(null, Object.keys(services).reduce((acc, serviceName) => { cb(null, Object.keys(services).reduce((acc, serviceName) => {
const environment = Get(services, `${serviceName}.environment`, {});
const labels = Get(services, `${serviceName}.labels`, {});
const ports = Get(services, `${serviceName}.ports`, []);
const image = Get(services, `${serviceName}.image`, '');
const toKeyValue = (v) => {
return Object.keys(v).map((key) => {
return {
id: Uuid(),
name: key,
value: v[key]
};
});
};
return acc.concat([{ return acc.concat([{
id: Uuid(), id: Uuid(),
hash: Uuid(), hash: Uuid(),
name: serviceName, name: serviceName,
slug: ParamCase(serviceName), slug: ParamCase(serviceName),
instances: [], instances: [],
package: {}, config: {
active: true, id: Uuid(),
image: services[serviceName].image environment: toKeyValue(environment),
image: image,
labels: toKeyValue(labels),
ports: ports
}
}]); }]);
}, [])); }, []));
}); });

View File

@ -69,12 +69,10 @@ exports.fromService = function ({ service, instances, packages }) {
deploymentGroupId: service.deployment_group_id, deploymentGroupId: service.deployment_group_id,
name: service.name, name: service.name,
slug: service.slug, slug: service.slug,
environment: service.environment || [],
instances, instances,
currentMetrics: [],
connections: service.service_dependency_ids, connections: service.service_dependency_ids,
package: packages ? exports.fromPackage(packages) : {}, parent: service.parent_id,
parent: service.parent_id || '', config: service.config ? service.config : undefined,
status: service.status, status: service.status,
hasPlan: service.has_plan hasPlan: service.has_plan
}; };
@ -88,15 +86,14 @@ exports.toService = function (clientService) {
deployment_group_id: clientService.deploymentGroupId, deployment_group_id: clientService.deploymentGroupId,
name: clientService.name, name: clientService.name,
slug: clientService.slug, slug: clientService.slug,
environment: clientService.environment,
instance_ids: clientService.instances ? instance_ids: clientService.instances ?
clientService.instances.map((instance) => { clientService.instances.map((instance) => {
return instance.id; return instance.id;
}) : }) :
undefined, undefined,
service_dependency_ids: clientService.connections, service_dependency_ids: clientService.connections,
package_id: clientService.package ? clientService.package.id : undefined,
parent_id: clientService.parent ? clientService.parent : undefined, parent_id: clientService.parent ? clientService.parent : undefined,
config: clientService.config ? clientService.config : undefined,
status: clientService.status, status: clientService.status,
has_plan: clientService.hasPlan has_plan: clientService.hasPlan
}); });
@ -133,6 +130,7 @@ exports.toManifest = function (clientManifest) {
created: clientManifest.created || Date.now(), created: clientManifest.created || Date.now(),
type: clientManifest.type, type: clientManifest.type,
format: clientManifest.format, format: clientManifest.format,
environment: clientManifest.environment,
raw: clientManifest.raw, raw: clientManifest.raw,
json: clientManifest.json || Yamljs.parse(clientManifest.raw) json: clientManifest.json || Yamljs.parse(clientManifest.raw)
}; };
@ -145,6 +143,7 @@ exports.fromManifest = function (manifest) {
created: manifest.created, created: manifest.created,
type: manifest.type, type: manifest.type,
format: manifest.format, format: manifest.format,
environment: manifest.environment,
raw: manifest.raw, raw: manifest.raw,
json: manifest.json json: manifest.json
}; };

View File

@ -123,8 +123,8 @@ acorn@^4.0.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3: acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3:
version "5.0.3" version "5.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75"
add-stream@^1.0.0: add-stream@^1.0.0:
version "1.0.0" version "1.0.0"
@ -403,8 +403,8 @@ arr-exclude@^1.0.0:
resolved "https://registry.yarnpkg.com/arr-exclude/-/arr-exclude-1.0.0.tgz#dfc7c2e552a270723ccda04cf3128c8cbfe5c631" resolved "https://registry.yarnpkg.com/arr-exclude/-/arr-exclude-1.0.0.tgz#dfc7c2e552a270723ccda04cf3128c8cbfe5c631"
arr-flatten@^1.0.1: arr-flatten@^1.0.1:
version "1.0.3" version "1.1.0"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
arr-union@^3.0.0: arr-union@^3.0.0:
version "3.1.0" version "3.1.0"
@ -497,6 +497,10 @@ ast-types@0.9.0:
version "0.9.0" version "0.9.0"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.0.tgz#c8721c8747ae4d5b29b929e99c5317b4e8745623" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.0.tgz#c8721c8747ae4d5b29b929e99c5317b4e8745623"
ast-types@0.9.6:
version "0.9.6"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
async-each@^1.0.0: async-each@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@ -2902,6 +2906,10 @@ deep-extend@~0.4.0:
version "0.4.2" version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
deep-get-set@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/deep-get-set/-/deep-get-set-1.1.0.tgz#47bba2008a3fde9c753dcbe61a36241606d9836f"
deep-is@~0.1.3: deep-is@~0.1.3:
version "0.1.3" version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@ -2986,8 +2994,8 @@ diff-match-patch@^1.0.0:
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048"
diff@3.x.x, diff@^3.0.0, diff@^3.0.1, diff@^3.2.0: diff@3.x.x, diff@^3.0.0, diff@^3.0.1, diff@^3.2.0:
version "3.2.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9"
diffie-hellman@^5.0.0: diffie-hellman@^5.0.0:
version "5.0.2" version "5.0.2"
@ -3329,7 +3337,7 @@ eslint-import-resolver-node@^0.3.1:
debug "^2.6.8" debug "^2.6.8"
resolve "^1.2.0" resolve "^1.2.0"
eslint-module-utils@^2.0.0: eslint-module-utils@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449"
dependencies: dependencies:
@ -3352,15 +3360,15 @@ eslint-plugin-hapi@4.x.x:
no-arrowception "1.x.x" no-arrowception "1.x.x"
eslint-plugin-import@^2.3.0: eslint-plugin-import@^2.3.0:
version "2.6.1" version "2.7.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.6.1.tgz#f580be62bb809421d46e338372764afcc9f59bf6" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f"
dependencies: dependencies:
builtin-modules "^1.1.1" builtin-modules "^1.1.1"
contains-path "^0.1.0" contains-path "^0.1.0"
debug "^2.6.8" debug "^2.6.8"
doctrine "1.5.0" doctrine "1.5.0"
eslint-import-resolver-node "^0.3.1" eslint-import-resolver-node "^0.3.1"
eslint-module-utils "^2.0.0" eslint-module-utils "^2.1.1"
has "^1.0.1" has "^1.0.1"
lodash.cond "^4.3.0" lodash.cond "^4.3.0"
minimatch "^3.0.3" minimatch "^3.0.3"
@ -3498,7 +3506,7 @@ esprima@^2.6.0, esprima@~2.7.1:
version "2.7.3" version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^3.1.1: esprima@^3.1.1, esprima@~3.1.0:
version "3.1.3" version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@ -4437,6 +4445,10 @@ hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
hoist-non-react-statics@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.0.0.tgz#843180515e0281952b08f41c620ca74870c7e354"
home-or-tmp@^2.0.0: home-or-tmp@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@ -5385,8 +5397,8 @@ json5@0.5.x, json5@^0.5.0, json5@^0.5.1:
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
jsonfile@^3.0.0: jsonfile@^3.0.0:
version "3.0.0" version "3.0.1"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.0.tgz#92e7c7444e5ffd5fa32e6a9ae8b85034df8347d0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
optionalDependencies: optionalDependencies:
graceful-fs "^4.1.6" graceful-fs "^4.1.6"
@ -5522,8 +5534,8 @@ lerna-wizard@ramitos/lerna-wizard#7bcdc11:
inquirer "^3.0.2" inquirer "^3.0.2"
lerna@^2.0.0-rc.5: lerna@^2.0.0-rc.5:
version "2.0.0-rc.5" version "2.0.0"
resolved "https://registry.yarnpkg.com/lerna/-/lerna-2.0.0-rc.5.tgz#b59d168caaac6e3443078c1bce194208c9aa3090" resolved "https://registry.yarnpkg.com/lerna/-/lerna-2.0.0.tgz#49a72fe70e06aebfd7ea23efb2ab41abe60ebeea"
dependencies: dependencies:
async "^1.5.0" async "^1.5.0"
chalk "^1.1.1" chalk "^1.1.1"
@ -5706,6 +5718,10 @@ lodash.difference@^4.3.0, lodash.difference@^4.4.0, lodash.difference@^4.5.0:
version "4.5.0" version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
lodash.differenceby@^4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/lodash.differenceby/-/lodash.differenceby-4.8.0.tgz#cfd59e94353af5de51da5d302ca4ebff33faac57"
lodash.find@^4.6.0: lodash.find@^4.6.0:
version "4.6.0" version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
@ -7250,13 +7266,13 @@ rc@1.1.7, rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-apollo@^1.4.2: react-apollo@^1.4.2:
version "1.4.2" version "1.4.3"
resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.4.2.tgz#e8ee035310b564fd1b42ee7e4f116086b5b06834" resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-1.4.3.tgz#be18bfe7f6609263f3ff623308f88108152a7573"
dependencies: dependencies:
apollo-client "^1.4.0" apollo-client "^1.4.0"
graphql-anywhere "^3.0.0" graphql-anywhere "^3.0.0"
graphql-tag "^2.0.0" graphql-tag "^2.0.0"
hoist-non-react-statics "^1.2.0" hoist-non-react-statics "^2.0.0"
invariant "^2.2.1" invariant "^2.2.1"
lodash.flatten "^4.2.0" lodash.flatten "^4.2.0"
lodash.isequal "^4.1.1" lodash.isequal "^4.1.1"
@ -7351,6 +7367,12 @@ react-router@^4.1.1:
prop-types "^15.5.4" prop-types "^15.5.4"
warning "^3.0.0" warning "^3.0.0"
react-simple-table@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-simple-table/-/react-simple-table-1.0.1.tgz#941390bd68eca63d028c1873bd90772a21143b9c"
dependencies:
deep-get-set "^1.0.0"
react-styled-flexboxgrid@^2.0.1: react-styled-flexboxgrid@^2.0.1:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/react-styled-flexboxgrid/-/react-styled-flexboxgrid-2.0.3.tgz#308a8bbc80b1737a65f4ccf35d02afe20932a2f2" resolved "https://registry.yarnpkg.com/react-styled-flexboxgrid/-/react-styled-flexboxgrid-2.0.3.tgz#308a8bbc80b1737a65f4ccf35d02afe20932a2f2"
@ -7529,7 +7551,7 @@ readline2@^1.0.1:
is-fullwidth-code-point "^1.0.0" is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5" mute-stream "0.0.5"
recast@0.11.12, recast@^0.11.5: recast@0.11.12:
version "0.11.12" version "0.11.12"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6"
dependencies: dependencies:
@ -7538,6 +7560,15 @@ recast@0.11.12, recast@^0.11.5:
private "~0.1.5" private "~0.1.5"
source-map "~0.5.0" source-map "~0.5.0"
recast@^0.11.5:
version "0.11.23"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
dependencies:
ast-types "0.9.6"
esprima "~3.1.0"
private "~0.1.5"
source-map "~0.5.0"
rechoir@^0.6.2: rechoir@^0.6.2:
version "0.6.2" version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@ -8763,6 +8794,12 @@ supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3:
dependencies: dependencies:
has-flag "^1.0.0" has-flag "^1.0.0"
supports-color@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.1.0.tgz#92cc14bb3dad8928ca5656c33e19a19f20af5c7a"
dependencies:
has-flag "^2.0.0"
svg-tags@^1.0.0: svg-tags@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
@ -9502,17 +9539,18 @@ vfile-location@^2.0.0:
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.1.tgz#0bf8816f732b0f8bd902a56fda4c62c8e935dc52" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.1.tgz#0bf8816f732b0f8bd902a56fda4c62c8e935dc52"
vfile-reporter@^3.0.0: vfile-reporter@^3.0.0:
version "3.0.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-3.0.0.tgz#fe50714e373e0d2940510038a99bd609bdc8209f" resolved "https://registry.yarnpkg.com/vfile-reporter/-/vfile-reporter-3.1.0.tgz#a9b398c5e6dcbc8a9a08e6cf425f092e86a37000"
dependencies: dependencies:
chalk "^1.1.0"
log-symbols "^1.0.2"
plur "^2.0.0"
repeat-string "^1.5.0" repeat-string "^1.5.0"
string-width "^1.0.0" string-width "^1.0.0"
strip-ansi "^3.0.1" supports-color "^4.1.0"
trim "0.0.1"
unist-util-stringify-position "^1.0.0" unist-util-stringify-position "^1.0.0"
vfile-statistics "^1.0.0"
vfile-statistics@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/vfile-statistics/-/vfile-statistics-1.0.0.tgz#003d356c0f3e0233f3a2271c65e2acee5ed4d0f8"
vfile@^2.0.0: vfile@^2.0.0:
version "2.1.0" version "2.1.0"