diff --git a/package.json b/package.json
index ced08d5b..c2b684f0 100644
--- a/package.json
+++ b/package.json
@@ -23,8 +23,8 @@
"bootstrap": "lerna bootstrap",
"dev": "redrun -p dev:*",
"dev:ui-toolkit": "lerna run watch --scope joyent-ui-toolkit",
- "dev:cp-frontend": "lerna run start --scope joyent-cp-frontend",
- "dev:gql-mock-server": "lerna run dev --scope joyent-cp-gql-mock-server",
+ "dev:my-joy-beta": "lerna run dev --scope my-joy-beta",
+ "dev:cloudapi-gql": "lerna run dev --scope cloudapi-gql",
"commitmsg": "commitlint -e",
"precommit": "cross-env CI=1 redrun -s lint-staged format-staged",
"postinstall": "lerna run prepublish",
diff --git a/packages/cloudapi-gql/src/api/machines.js b/packages/cloudapi-gql/src/api/machines.js
index 26769a99..aaa3d6b4 100644
--- a/packages/cloudapi-gql/src/api/machines.js
+++ b/packages/cloudapi-gql/src/api/machines.js
@@ -35,8 +35,9 @@ module.exports.start = uuid => request('startMachine', uuid);
module.exports.startFromSnapshot = ctx =>
request('startMachineFromSnapshot', ctx);
module.exports.reboot = ctx => request('rebootMachine', ctx);
-module.exports.resize = ctx => request('', ctx);
-module.exports.rename = ctx => request('', ctx);
+(module.exports.resize = ({ id, package }) =>
+ request.fetch(`/:login/machines/${id}?action=resize?package=${package}`)),
+ (module.exports.rename = ctx => request('', ctx));
module.exports.destroy = ctx => request('deleteMachine', ctx);
module.exports.audit = ({ id }) => request('machineAudit', id);
diff --git a/packages/cloudapi-gql/src/schema/resolvers.js b/packages/cloudapi-gql/src/schema/resolvers.js
index 91ce41ad..f6daa5eb 100644
--- a/packages/cloudapi-gql/src/schema/resolvers.js
+++ b/packages/cloudapi-gql/src/schema/resolvers.js
@@ -4,25 +4,35 @@ const api = require('../api');
const resolvers = {
Query: {
account: () => api.account.get(),
+
keys: (root, { login, name }) =>
name
? api.keys.get({ login, name }).then(key => [key])
: api.keys.list({ login, name }),
+
key: (root, { login, name }) => api.keys.get({ login, name }),
+
users: (root, { id }) =>
id ? api.users.get({ id }).then(user => [user]) : api.users.list(),
+
user: (root, { id }) => api.users.get({ id }),
+
roles: (root, { id, name }) =>
id || name
? api.roles.get({ id, name }).then(role => [role])
: api.roles.list(),
+
role: (root, { id, name }) => api.roles.get({ id, name }),
+
policies: (root, { id }) =>
id
? api.policies.get({ id }).then(policy => [policy])
: api.policies.list(),
+
policy: (root, { id }) => api.policies.get({ id }),
+
config: () => api.config().then(toKeyValue),
+
datacenters: () =>
api.datacenters().then(dcs =>
Object.keys(dcs).map(name => ({
@@ -30,17 +40,23 @@ const resolvers = {
url: dcs[name]
}))
),
+
services: () => api.services().then(toKeyValue),
+
images: (root, { id, ...rest }) =>
id
? api.images.get({ id }).then(image => [image])
: api.images.list(rest),
+
image: (root, { id }) => api.images.get({ id }),
+
packages: (root, { id, ...rest }) =>
id
? api.packages.get({ id }).then(pkg => [pkg])
: api.packages.list(rest),
+
package: (root, { id, name }) => api.packages.get({ id, name }),
+
machines: (root, { id, brand, state, tags, ...rest }) =>
id
? api.machines.get({ id }).then(machine => [machine])
@@ -51,36 +67,45 @@ const resolvers = {
tags: fromKeyValue(tags)
})
),
+
machine: (root, { id }) => api.machines.get({ id }),
+
snapshots: (root, { name, machine }) =>
name
? api.machines.snapshots
.get({ id: machine, name })
.then(snapshot => [snapshot])
: api.machines.snapshots.list({ id: machine }),
+
snapshot: (root, { name, machine }) =>
api.machines.snapshots.get({ name, id: machine }),
+
metadata: (root, { machine, name, ...rest }) =>
name
? api.machines.metadata
.get(Object.assign(rest, { id: machine, key: name }))
.then(value => toKeyValue({ [name]: value }))
: api.machines.metadata.list({ id: machine }).then(toKeyValue),
+
metadataValue: (root, { name, machine }) =>
api.machines.metadata
.get({ key: name, id: machine })
.then(value => toKeyValue({ [name]: value }).shift()),
+
tags: (root, { machine, name }) =>
name
? api.machines.tags
.get({ id: machine, tag: name })
.then(value => toKeyValue({ [name]: value }))
: api.machines.tags.list({ id: machine }).then(toKeyValue),
+
tag: (root, { machine, name }) =>
api.machines.tags
.get({ id: machine, tag: name })
.then(value => toKeyValue({ [name]: value }).shift()),
+
actions: (root, { machine }) => api.machines.audit({ id: machine }),
+
// eslint-disable-next-line camelcase
firewall_rules: (root, { machine, id }) =>
id
@@ -88,15 +113,22 @@ const resolvers = {
: machine
? api.firewall.listByMachine({ id: machine })
: api.firewall.list(),
+
// eslint-disable-next-line camelcase
firewall_rule: (root, { id }) => api.firewall.get({ id }),
+
vlans: (root, { id }) => (id ? api.vlans.get({ id }) : api.vlans.list()),
+
vlan: (root, { id }) => api.vlans.get({ id }),
+
networks: (root, { id, vlan }) =>
id ? api.networks.get({ id, vlan }) : api.networks.list({ vlan }),
+
network: (root, { id, vlan }) => api.networks.get({ id, vlan }),
+
nics: (root, { machine, mac }) =>
mac ? api.nics.get({ machine, mac }) : api.nics.list({ machine }),
+
nic: (root, { machine, mac }) => api.nics.get({ machine, mac })
},
User: {
@@ -104,36 +136,50 @@ const resolvers = {
},
Machine: {
brand: ({ brand }) => (brand ? brand.toUpperCase() : brand),
+
state: ({ state }) => (state ? state.toUpperCase() : state),
+
image: ({ image }) => resolvers.Query.image(null, { id: image }),
+
// eslint-disable-next-line camelcase
primary_ip: ({ primaryIp }) => primaryIp,
+
tags: ({ id }, { name }) =>
resolvers.Query.tags(null, { machine: id, name }),
+
metadata: ({ id }, { name }) =>
resolvers.Query.metadata(null, { machine: id, name }),
+
networks: ({ networks }) =>
Promise.all(networks.map(id => resolvers.Query.network(null, { id }))),
+
// eslint-disable-next-line camelcase
package: root => resolvers.Query.package(null, { name: root.package }),
+
snapshots: ({ id }, { name }) =>
resolvers.Query.snapshots(null, { machine: id, name }),
+
// eslint-disable-next-line camelcase
firewall_rules: ({ id: machine }, { id }) =>
resolvers.Query.firewall_rules(null, { machine, id }),
+
actions: ({ id }) => resolvers.Query.actions(null, { machine: id })
},
Image: {
os: ({ os }) => (os ? os.toUpperCase() : os),
+
state: ({ state }) => (state ? state.toUpperCase() : state),
+
type: ({ type }) => (type ? type.toUpperCase() : type)
},
Action: {
name: ({ action }) => action,
+
parameters: ({ parameters }) => toKeyValue(parameters)
},
Caller: {
type: ({ type }) => (type ? type.toUpperCase() : type),
+
// eslint-disable-next-line camelcase
key_id: ({ keyId }) => keyId
},
@@ -151,8 +197,39 @@ const resolvers = {
compression ? compression.toUpperCase() : compression
},
Mutation: {
+ stopMachine: (root, { id }) =>
+ api.machines.stop(id).then(() => resolvers.Query.machine(null, { id })),
+
+ startMachine: (root, { id }) =>
+ api.machines.start(id).then(() => resolvers.Query.machine(null, { id })),
+
rebootMachine: (root, { id }) =>
- api.machines.reboot(id).then(() => resolvers.Query.machine(null, { id }))
+ api.machines.reboot(id).then(() => resolvers.Query.machine(null, { id })),
+
+ resizeMachine: (root, { id, ...args }) =>
+ api.machines
+ .resize({ id, package: args.package })
+ .then(() => resolvers.Query.machine(null, { id })),
+
+ enableMachineFirewall: (root, { id }) =>
+ api.machines.firewall
+ .enable(id)
+ .then(() => resolvers.Query.machine(null, { id })),
+
+ disableMachineFirewall: (root, { id }) =>
+ api.machines.firewall
+ .disable(id)
+ .then(() => resolvers.Query.machine(null, { id })),
+
+ createMachineSnapshot: (root, { id, name }) =>
+ api.machines.snapshots
+ .create({ id, name })
+ .then(() => resolvers.Query.snapshots(null, { machine: id, name })),
+
+ startMachineFromSnapshot: (root, { id, name }) =>
+ api.machines.snapshots
+ .startFromSnapshot({ id, name })
+ .then(() => resolvers.Query.machine(null, { id }))
}
};
diff --git a/packages/joyent-boilerplate/package.json b/packages/joyent-boilerplate/package.json
index be5c0d64..dc6d7c5f 100644
--- a/packages/joyent-boilerplate/package.json
+++ b/packages/joyent-boilerplate/package.json
@@ -31,7 +31,7 @@
"react-router-dom": "^4.2.2",
"react-styled-flexboxgrid": "^2.0.3",
"redux": "^3.7.2",
- "redux-form": "^7.1.0",
+ "redux-form": "^7.1.1",
"remcalc": "^1.0.9",
"styled-components": "^2.2.1",
"styled-is": "^1.1.0"
@@ -51,7 +51,7 @@
"jest-snapshot": "^21.2.1",
"jest-styled-components": "^4.7.0",
"jest-transform-graphql": "^2.1.0",
- "joyent-react-scripts": "^2.1.1",
+ "joyent-react-scripts": "^2.2.1",
"react-test-renderer": "^16.0.0",
"redrun": "^5.9.18",
"stylelint": "^8.2.0",
diff --git a/packages/my-joy-beta/package.json b/packages/my-joy-beta/package.json
index c13d4881..026301ae 100644
--- a/packages/my-joy-beta/package.json
+++ b/packages/my-joy-beta/package.json
@@ -37,7 +37,7 @@
"react-router-dom": "^4.2.2",
"redux": "^3.7.2",
"redux-actions": "^2.2.1",
- "redux-form": "^7.1.0",
+ "redux-form": "^7.1.1",
"remcalc": "^1.0.9",
"styled-components": "^2.2.1",
"title-case": "^2.1.1"
@@ -57,7 +57,7 @@
"jest-snapshot": "^21.2.1",
"jest-styled-components": "^4.7.0",
"jest-transform-graphql": "^2.1.0",
- "joyent-react-scripts": "^2.1.1",
+ "joyent-react-scripts": "^2.2.1",
"react-test-renderer": "^16.0.0",
"redrun": "^5.9.18",
"serve": "^6.2.0",
diff --git a/packages/my-joy-beta/src/components/instances/create-snapshot.js b/packages/my-joy-beta/src/components/instances/create-snapshot.js
new file mode 100644
index 00000000..279b5f9a
--- /dev/null
+++ b/packages/my-joy-beta/src/components/instances/create-snapshot.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import {
+ FormGroup,
+ FormLabel,
+ Input,
+ Button,
+ Message,
+ MessageTitle,
+ MessageDescription
+} from 'joyent-ui-toolkit';
+
+export default ({
+ submitting = false,
+ error,
+ handleSubmit = () => {},
+ onCancel = () => {}
+}) => {
+ const _error = error &&
+ !submitting && (
+
+ Ooops!
+ {error}
+
+ );
+
+ return (
+
+ );
+};
diff --git a/packages/my-joy-beta/src/components/instances/index.js b/packages/my-joy-beta/src/components/instances/index.js
index d64b6a7f..3f888caf 100644
--- a/packages/my-joy-beta/src/components/instances/index.js
+++ b/packages/my-joy-beta/src/components/instances/index.js
@@ -3,3 +3,5 @@ export { default as List } from './list';
export { default as KeyValue } from './key-value';
export { default as Network } from './network';
export { default as FirewallRule } from './firewall-rule';
+export { default as Resize } from './resize';
+export { default as CreateSnapshot } from './create-snapshot';
diff --git a/packages/my-joy-beta/src/components/instances/list.js b/packages/my-joy-beta/src/components/instances/list.js
index dbd4e7c7..9278ebe8 100644
--- a/packages/my-joy-beta/src/components/instances/list.js
+++ b/packages/my-joy-beta/src/components/instances/list.js
@@ -1,6 +1,7 @@
import React from 'react';
import { Row, Col } from 'react-styled-flexboxgrid';
import forceArray from 'force-array';
+import get from 'lodash.get';
import {
FormGroup,
@@ -14,13 +15,34 @@ import {
import Item from './item';
export default ({
- instances,
+ instances = [],
+ selected = [],
loading,
handleChange = () => null,
onAction = () => null,
handleSubmit,
...rest
}) => {
+ const allowedActions = {
+ stop: selected.some(({ state }) => state === 'RUNNING'),
+ start: selected.some(({ state }) => state !== 'RUNNING'),
+ reboot: true,
+ resize:
+ selected.length === 1 && selected.every(({ brand }) => brand === 'KVM'),
+ enableFw: selected.some(({ firewall_enabled }) => !firewall_enabled),
+ disableFw: selected.some(({ firewall_enabled }) => firewall_enabled),
+ createSnap: true,
+ startSnap:
+ selected.length === 1 &&
+ selected.every(({ snapshots = [] }) => snapshots.length)
+ };
+
+ const handleActions = ({ target }) =>
+ onAction({
+ name: target.value,
+ items: selected
+ });
+
const _instances = forceArray(instances);
const items = _instances.map((instance, i, all) => (
@@ -83,21 +105,46 @@ export default ({
diff --git a/packages/my-joy-beta/src/components/instances/resize.js b/packages/my-joy-beta/src/components/instances/resize.js
new file mode 100644
index 00000000..ce10fa49
--- /dev/null
+++ b/packages/my-joy-beta/src/components/instances/resize.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import ReactJson from 'react-json-view';
+
+export default ({ instance, packages, handleSubmit }) => (
+
+);
diff --git a/packages/my-joy-beta/src/containers/instances/create-snapshot.js b/packages/my-joy-beta/src/containers/instances/create-snapshot.js
new file mode 100644
index 00000000..7bbb1aaf
--- /dev/null
+++ b/packages/my-joy-beta/src/containers/instances/create-snapshot.js
@@ -0,0 +1,94 @@
+import React from 'react';
+import { reduxForm, SubmissionError } from 'redux-form';
+import { connect } from 'react-redux';
+import { compose, graphql } from 'react-apollo';
+import find from 'lodash.find';
+import get from 'lodash.get';
+
+import {
+ Title,
+ ViewContainer,
+ StatusLoader,
+ Message,
+ MessageTitle,
+ MessageDescription
+} from 'joyent-ui-toolkit';
+
+import { CreateSnapshot as InstanceCreateSnapshot } from '@components/instances';
+import CreateSnapshotMutation from '@graphql/create-snapshot.gql';
+import GetInstance from '@graphql/get-instance.gql';
+
+const CreateSnapshot = ({
+ match,
+ instance,
+ loading,
+ error,
+ handleSubmit,
+ handleCancel
+}) => {
+ const _title = Create Snapshot;
+ const _loading = !(loading && !instance) ? null : ;
+
+ const CreateSnapshotForm = reduxForm({
+ form: `create-snapshot-${match.params.instance}`
+ })(InstanceCreateSnapshot);
+
+ const _error = error &&
+ !instance &&
+ !_loading && (
+
+ Ooops!
+
+ An error occurred while loading your instance
+
+
+ );
+
+ const _form = !loading &&
+ !_error && (
+
+ );
+
+ return (
+
+ {_title}
+ {_loading}
+ {_error}
+ {_form}
+
+ );
+};
+
+export default compose(
+ graphql(CreateSnapshotMutation, { name: 'createSnapshot' }),
+ graphql(GetInstance, {
+ options: ({ match }) => ({
+ variables: {
+ name: get(match, 'params.instance')
+ }
+ }),
+ props: ({ data: { loading, error, variables, ...rest } }) => ({
+ instance: find(get(rest, 'machines', []), ['name', variables.name]),
+ loading,
+ error
+ })
+ }),
+ connect(
+ null,
+ (dispatch, { history, location, instance, createSnapshot }) => ({
+ handleCancel: () => history.push(location.pathname.split(/\/\~/).shift()),
+ handleSubmit: ({ name }) =>
+ createSnapshot({
+ variables: { name, id: instance.id }
+ })
+ .catch(error => {
+ throw new SubmissionError({
+ _error: error.graphQLErrors
+ .map(({ message }) => message)
+ .join('\n')
+ });
+ })
+ .then(() => history.push(`/instances/${instance.name}/snapshots`))
+ })
+ )
+)(CreateSnapshot);
diff --git a/packages/my-joy-beta/src/containers/instances/index.js b/packages/my-joy-beta/src/containers/instances/index.js
index 0f040718..ac2c961d 100644
--- a/packages/my-joy-beta/src/containers/instances/index.js
+++ b/packages/my-joy-beta/src/containers/instances/index.js
@@ -5,3 +5,5 @@ export { default as Metadata } from './metadata';
export { default as Networks } from './networks';
export { default as Firewall } from './firewall';
export { default as Snapshots } from './snapshots';
+export { default as Resize } from './resize';
+export { default as CreateSnapshot } from './create-snapshot';
diff --git a/packages/my-joy-beta/src/containers/instances/list.js b/packages/my-joy-beta/src/containers/instances/list.js
index 402c57dc..5e4392eb 100644
--- a/packages/my-joy-beta/src/containers/instances/list.js
+++ b/packages/my-joy-beta/src/containers/instances/list.js
@@ -57,8 +57,6 @@ const List = ({
) : null;
- const handleAction = name => onAction({ name, ids: selected });
-
return (
{_title}
@@ -66,7 +64,8 @@ const List = ({
);
@@ -121,7 +120,8 @@ export default compose(
const selected = Object.keys(form)
.map(name => find(values, ['name', name]))
.filter(Boolean)
- .map(({ id }) => id);
+ .map(({ id }) => find(instances, ['id', id]))
+ .filter(Boolean);
return {
...rest,
@@ -129,27 +129,39 @@ export default compose(
selected
};
},
- (dispatch, { instances, ...ownProps }) => ({
- onAction: ({ name, ids = [] }) => {
+ (dispatch, { stop, start, reboot, history, location }) => ({
+ onAction: ({ name, items = [] }) => {
const types = {
stop: () =>
- Promise.all(ids.map(id => ownProps.stop({ variables: { id } }))),
+ Promise.all(items.map(({ id }) => stop({ variables: { id } }))),
start: () =>
- Promise.all(ids.map(id => ownProps.start({ variables: { id } }))),
+ Promise.all(items.map(({ id }) => start({ variables: { id } }))),
reboot: () =>
- Promise.all(ids.map(id => ownProps.reboot({ variables: { id } }))),
- resize: () => null,
- 'enable-fw': () => null,
- 'disable-fw': () => null,
- 'create-snap': () => null,
- 'start-snap': () => null
+ Promise.all(items.map(({ id }) => reboot({ variables: { id } }))),
+ resize: () =>
+ Promise.resolve(
+ history.push(`/instances/~resize/${items.shift().name}`)
+ ),
+ enableFw: () =>
+ Promise.all(items.map(({ id }) => enableFw({ variables: { id } }))),
+ disableFw: () =>
+ Promise.all(
+ items.map(({ id }) => disableFw({ variables: { id } }))
+ ),
+ createSnap: () =>
+ Promise.resolve(
+ history.push(`/instances/~create-snapshot/${items.shift().name}`)
+ ),
+ startSnap: () =>
+ Promise.resolve(
+ history.push(`/instances/${items.shift().name}/snapshots`)
+ )
};
const clearSelected = () =>
dispatch(
- ids.map(id => {
+ items.map(({ name: field }) => {
const form = 'instance-list';
- const field = get(find(instances, ['id', id]), 'name');
const value = false;
if (!field) {
diff --git a/packages/my-joy-beta/src/containers/instances/resize.js b/packages/my-joy-beta/src/containers/instances/resize.js
new file mode 100644
index 00000000..676f7bbc
--- /dev/null
+++ b/packages/my-joy-beta/src/containers/instances/resize.js
@@ -0,0 +1,77 @@
+import React from 'react';
+import { reduxForm } from 'redux-form';
+import { compose, graphql } from 'react-apollo';
+import forceArray from 'force-array';
+import find from 'lodash.find';
+import get from 'lodash.get';
+
+import {
+ StatusLoader,
+ Title,
+ ViewContainer,
+ Message,
+ MessageTitle,
+ MessageDescription
+} from 'joyent-ui-toolkit';
+
+import { Resize as InstanceResize } from '@components/instances';
+
+import ListPackages from '@graphql/list-packages.gql';
+import ListInstances from '@graphql/list-instances.gql';
+import GetInstance from '@graphql/get-instance.gql';
+
+const Resize = ({ match, loading, error, instance, packages }) => {
+ const ResizeForm = reduxForm({
+ form: `resize-instance-${match.params.instance}`
+ })(InstanceResize);
+
+ const _packages = forceArray(packages);
+
+ const _title = Resize;
+ const _loading = !(loading && (!_packages.length || !instance)) ? null : (
+
+ );
+
+ const _error = !(error && !_loading) ? null : (
+
+ Ooops!
+ An error occurred
+
+ );
+
+ const _resize =
+ _loading || _error ? null : (
+
+ );
+
+ return (
+
+ {_title}
+ {_loading}
+ {_error}
+ {_resize}
+
+ );
+};
+
+export default compose(
+ graphql(GetInstance, {
+ options: ({ match }) => ({
+ variables: {
+ name: get(match, 'params.instance')
+ }
+ }),
+ props: ({ data: { loading, error, variables, ...rest } }) => ({
+ instance: find(get(rest, 'machines', []), ['name', variables.name]),
+ loading,
+ error
+ })
+ }),
+ graphql(ListPackages, {
+ props: ({ data: { packages, loading, error } }) => ({
+ packages: forceArray(packages),
+ loading,
+ error
+ })
+ })
+)(Resize);
diff --git a/packages/my-joy-beta/src/graphql/create-snapshot.gql b/packages/my-joy-beta/src/graphql/create-snapshot.gql
index e44ca6b6..82bb96cf 100644
--- a/packages/my-joy-beta/src/graphql/create-snapshot.gql
+++ b/packages/my-joy-beta/src/graphql/create-snapshot.gql
@@ -1,3 +1,5 @@
mutation createInstanceSnapshot($id: ID!, $name: String) {
- createMachineSnapshot(id: $id, name: $name)
+ createMachineSnapshot(id: $id, name: $name) {
+ name
+ }
}
diff --git a/packages/my-joy-beta/src/graphql/get-instance.gql b/packages/my-joy-beta/src/graphql/get-instance.gql
index cb5658bb..dc2fd961 100644
--- a/packages/my-joy-beta/src/graphql/get-instance.gql
+++ b/packages/my-joy-beta/src/graphql/get-instance.gql
@@ -1,4 +1,4 @@
-query instance($name: String!) {
+query instance($name: String) {
machines(name: $name) {
id
name
@@ -8,5 +8,8 @@ query instance($name: String!) {
created
updated
firewall_enabled
+ package {
+ name
+ }
}
}
diff --git a/packages/my-joy-beta/src/graphql/get-package.gql b/packages/my-joy-beta/src/graphql/get-package.gql
new file mode 100644
index 00000000..2c817f05
--- /dev/null
+++ b/packages/my-joy-beta/src/graphql/get-package.gql
@@ -0,0 +1,14 @@
+query packages($id: ID) {
+ packages(id: $id) {
+ id
+ name
+ memory
+ disk
+ swap
+ lwps
+ vcpus
+ version
+ group
+ description
+ }
+}
diff --git a/packages/my-joy-beta/src/graphql/list-instances.gql b/packages/my-joy-beta/src/graphql/list-instances.gql
index d72aa608..b987d010 100644
--- a/packages/my-joy-beta/src/graphql/list-instances.gql
+++ b/packages/my-joy-beta/src/graphql/list-instances.gql
@@ -13,5 +13,8 @@ query instances {
package {
name
}
+ snapshots {
+ name
+ }
}
}
diff --git a/packages/my-joy-beta/src/graphql/list-packages.gql b/packages/my-joy-beta/src/graphql/list-packages.gql
new file mode 100644
index 00000000..2227496a
--- /dev/null
+++ b/packages/my-joy-beta/src/graphql/list-packages.gql
@@ -0,0 +1,6 @@
+query packages {
+ packages {
+ id
+ name
+ }
+}
diff --git a/packages/my-joy-beta/src/router.js b/packages/my-joy-beta/src/router.js
index d322d3cb..90a6f4d3 100644
--- a/packages/my-joy-beta/src/router.js
+++ b/packages/my-joy-beta/src/router.js
@@ -14,61 +14,109 @@ import {
Metadata as InstanceMetadata,
Networks as InstanceNetworks,
Firewall as InstanceFirewall,
- Snapshots as InstanceSnapshots
+ Snapshots as InstanceSnapshots,
+ Resize as InstanceResize,
+ CreateSnapshot as InstanceCreateSnapshot
} from '@containers/instances';
export default () => (
+ {/* Header */}
+ {/* Breadcrumb */}
-
-
+
+
+ {/* Menu */}
-
-
+
+
-
+ {/* Instances List */}
+
+
+
-
-
-
-
-
-
- (
-
- )}
- />
+ {/* Instance Sections */}
+
+ null} />
+ null}
+ />
+
+
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ {/* Actions */}
+
+
+
+
+
+
} />
diff --git a/packages/my-joyent/package.json b/packages/my-joyent/package.json
index 90fa13fc..d3024bed 100644
--- a/packages/my-joyent/package.json
+++ b/packages/my-joyent/package.json
@@ -31,7 +31,7 @@
"react-router-dom": "^4.2.2",
"react-styled-flexboxgrid": "^2.0.3",
"redux": "^3.7.2",
- "redux-form": "^7.1.0",
+ "redux-form": "^7.1.1",
"remcalc": "^1.0.9",
"styled-components": "^2.2.1",
"styled-is": "^1.1.0",
diff --git a/packages/ui-toolkit/package.json b/packages/ui-toolkit/package.json
index 45fd6988..d4582d94 100644
--- a/packages/ui-toolkit/package.json
+++ b/packages/ui-toolkit/package.json
@@ -46,17 +46,18 @@
"disable-scroll": "^0.3.0",
"file-loader": "^1.1.5",
"fontfaceobserver": "^2.0.13",
+ "joy-react-broadcast": "^0.6.9",
"joyent-manifest-editor": "^1.4.0",
"lodash.difference": "^4.5.0",
"lodash.differenceby": "^4.8.0",
"lodash.isequal": "^4.5.0",
"lodash.isequalwith": "^4.4.0",
"lodash.isstring": "^4.0.1",
+ "moment": "^2.19.0",
"normalized-styled-components": "^1.0.17",
"pascal-case": "^2.0.1",
"polished": "^1.8.0",
"prop-types": "^15.6.0",
- "joy-react-broadcast": "^0.6.9",
"react-bundle": "^1.0.4",
"react-input-range": "^1.2.1",
"react-responsive": "^2.0.0",
@@ -100,10 +101,10 @@
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"react-scripts": "^1.0.14",
- "react-styleguidist": "^6.0.28",
+ "react-styleguidist": "^6.0.29",
"react-test-renderer": "^16.0.0",
"redux": "^3.7.2",
- "redux-form": "^7.1.0",
+ "redux-form": "^7.1.1",
"serve-static": "^1.13.1",
"snapguidist": "^2.1.0",
"style-loader": "^0.19.0",
@@ -121,6 +122,6 @@
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router-dom": "^4.2.2",
- "redux-form": "^7.1.0"
+ "redux-form": "^7.1.1"
}
}
diff --git a/packages/ui-toolkit/src/anchor/index.js b/packages/ui-toolkit/src/anchor/index.js
index de559ffd..f011251c 100644
--- a/packages/ui-toolkit/src/anchor/index.js
+++ b/packages/ui-toolkit/src/anchor/index.js
@@ -27,9 +27,13 @@ const style = css`
`};
`;
-const StyledAnchor = A.extend`${style};`;
+const StyledAnchor = A.extend`
+ ${style};
+`;
-const StyledLink = styled(BaseLink)`${style};`;
+const StyledLink = styled(BaseLink)`
+ ${style};
+`;
/**
* @example ./usage.md
diff --git a/packages/ui-toolkit/src/boxes/index.js b/packages/ui-toolkit/src/boxes/index.js
index 4530d597..7ae2a9ab 100644
--- a/packages/ui-toolkit/src/boxes/index.js
+++ b/packages/ui-toolkit/src/boxes/index.js
@@ -11,9 +11,19 @@ export const tooltipShadow = `0 ${remcalc(2)} ${remcalc(6)} ${remcalc(
export const modalShadow = `0 0 ${remcalc(6)} ${remcalc(1)} rgba(0, 0, 0, 0.1)`;
export const border = {
- checked: css`${remcalc(1)} solid ${props => props.theme.primary};`,
- unchecked: css`${remcalc(1)} solid ${props => props.theme.grey};`,
- confirmed: css`${remcalc(1)} solid ${props => props.theme.grey};`,
- error: css`${remcalc(1)} solid ${props => props.theme.red};`,
- secondary: css`${remcalc(1)} solid ${props => props.theme.secondaryActive};`
+ checked: css`
+ ${remcalc(1)} solid ${props => props.theme.primary};
+ `,
+ unchecked: css`
+ ${remcalc(1)} solid ${props => props.theme.grey};
+ `,
+ confirmed: css`
+ ${remcalc(1)} solid ${props => props.theme.grey};
+ `,
+ error: css`
+ ${remcalc(1)} solid ${props => props.theme.red};
+ `,
+ secondary: css`
+ ${remcalc(1)} solid ${props => props.theme.secondaryActive};
+ `
};
diff --git a/packages/ui-toolkit/src/button/index.js b/packages/ui-toolkit/src/button/index.js
index edb69a49..00d6e243 100644
--- a/packages/ui-toolkit/src/button/index.js
+++ b/packages/ui-toolkit/src/button/index.js
@@ -202,7 +202,7 @@ const Button = props => {
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
const children = loading ? (
-
+
) : (
props.children
);
diff --git a/packages/ui-toolkit/src/topology/node/info.js b/packages/ui-toolkit/src/topology/node/info.js
index 22c01e9e..1e79387f 100644
--- a/packages/ui-toolkit/src/topology/node/info.js
+++ b/packages/ui-toolkit/src/topology/node/info.js
@@ -61,12 +61,9 @@ const GraphNodeInfo = ({ data, pos }) => {
const healthy = (
);
diff --git a/yarn.lock b/yarn.lock
index 623bcf4c..91cf6239 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -392,7 +392,7 @@ apollo-server-core@^1.1.6:
dependencies:
apollo-tracing "^0.0.7"
-apollo-server-hapi@^1.1.3:
+apollo-server-hapi@^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/apollo-server-hapi/-/apollo-server-hapi-1.1.6.tgz#97bdc483afe908e28aa0ae9a3ee7744d581bc3bf"
dependencies:
@@ -1767,7 +1767,7 @@ babel-preset-jest@^21.2.0:
babel-plugin-jest-hoist "^21.2.0"
babel-plugin-syntax-object-rest-spread "^6.13.0"
-babel-preset-joyent-portal@^3.0.1:
+babel-preset-joyent-portal@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/babel-preset-joyent-portal/-/babel-preset-joyent-portal-3.2.0.tgz#0801746916568886beba5c2911ce1c55ec142320"
dependencies:
@@ -4363,11 +4363,7 @@ escope@^3.6.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
-eslint-config-joyent-portal@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/eslint-config-joyent-portal/-/eslint-config-joyent-portal-3.0.0.tgz#269e3e0b88abba96adc3a6dc0bbf604a6ae89356"
-
-eslint-config-joyent-portal@^3.0.0:
+eslint-config-joyent-portal@3.1.0, eslint-config-joyent-portal@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/eslint-config-joyent-portal/-/eslint-config-joyent-portal-3.1.0.tgz#7a77270d118627e59461db29d35639cf146d1dfc"
@@ -5832,7 +5828,7 @@ graphql-tools@^1.1.0:
optionalDependencies:
"@types/graphql" "^0.9.0"
-graphql-tools@^2.2.1:
+graphql-tools@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-2.4.0.tgz#183d7e509e1ebd07d51db05fdeb181e7126f7ecb"
dependencies:
@@ -7492,7 +7488,7 @@ joy-react-broadcast@^0.6.9:
prop-types "^15.5.6"
warning "^3.0.0"
-joyent-manifest-editor@^1.3.0:
+joyent-manifest-editor@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/joyent-manifest-editor/-/joyent-manifest-editor-1.4.0.tgz#0c02efe6c02b0386a5b209ae4ddcc3492b9c22ac"
dependencies:
@@ -7500,7 +7496,7 @@ joyent-manifest-editor@^1.3.0:
prop-types "^15.6.0"
react-codemirror "^1.0.0"
-joyent-react-scripts@^2.0.2:
+joyent-react-scripts@^2.2.1:
version "2.3.0"
resolved "https://registry.yarnpkg.com/joyent-react-scripts/-/joyent-react-scripts-2.3.0.tgz#9e48f93d67284b8149dc73b35ccdfc11d27131d9"
dependencies:
@@ -8913,7 +8909,7 @@ normalize-url@^1.4.0:
query-string "^4.1.0"
sort-keys "^1.0.0"
-normalized-styled-components@^1.0.14:
+normalized-styled-components@^1.0.17:
version "1.0.17"
resolved "https://registry.yarnpkg.com/normalized-styled-components/-/normalized-styled-components-1.0.17.tgz#fd3a82e00b87d0c89d973f795cdaa7b5025ebb8a"
dependencies:
@@ -10462,7 +10458,7 @@ react-styled-flexboxgrid@^2.0.3:
dependencies:
lodash.isinteger "^4.0.4"
-react-styleguidist@^6.0.28:
+react-styleguidist@^6.0.29:
version "6.0.30"
resolved "https://registry.yarnpkg.com/react-styleguidist/-/react-styleguidist-6.0.30.tgz#988a09282f8af43749e44602349ec524dc1f07a0"
dependencies:
@@ -10780,7 +10776,7 @@ reduce-css-calc@^1.2.6:
math-expression-evaluator "^1.2.14"
reduce-function-call "^1.0.1"
-reduce-css-calc@^2.0.5:
+reduce-css-calc@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.1.tgz#f4ecd7a00ec3e5683773f208067ad7da117b9db0"
dependencies:
@@ -10806,7 +10802,7 @@ redux-actions@^2.2.1:
lodash-es "^4.17.4"
reduce-reducers "^0.1.0"
-redux-form@^7.1.0:
+redux-form@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-7.1.1.tgz#4d9ab1d9c03beb3a8b5f8e5d0f398cff4209081f"
dependencies:
@@ -11375,7 +11371,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^2.0.0"
inherits "^2.0.1"
-rnd-id@^1.0.8:
+rnd-id@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/rnd-id/-/rnd-id-1.1.1.tgz#aaa11c650cf4105eeb1025eecf185db89071afb6"
dependencies:
@@ -12225,11 +12221,11 @@ styled-components@^2.2.1:
stylis "^3.2.1"
supports-color "^3.2.3"
-styled-is@^1.0.15:
+styled-is@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/styled-is/-/styled-is-1.1.0.tgz#0cf8d32098fe6559eb0ec889790cc6c84f1f497f"
-stylelint-config-joyent-portal@^2.0.0:
+stylelint-config-joyent-portal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stylelint-config-joyent-portal/-/stylelint-config-joyent-portal-2.0.1.tgz#9d9242807749db394b9b9c3da7bc48b9b818a16e"
dependencies:
@@ -13019,7 +13015,7 @@ unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.1.3.tgz#ec268e731b9d277a79a5b5aa0643990e405d600b"
-unitcalc@^1.1.0:
+unitcalc@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unitcalc/-/unitcalc-1.1.1.tgz#a57e1c9dd61f251d2fad0c1d19f8577255cf080a"
dependencies: