From 6f10428b0f17b2cb8ab54724897e9731cb2d974e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Ramos?= Date: Wed, 11 Oct 2017 17:59:59 +0100 Subject: [PATCH] feat: instances list actions --- package.json | 4 +- packages/cloudapi-gql/src/api/machines.js | 5 +- packages/cloudapi-gql/src/schema/resolvers.js | 79 ++++++++++- packages/joyent-boilerplate/package.json | 4 +- packages/my-joy-beta/package.json | 4 +- .../components/instances/create-snapshot.js | 41 ++++++ .../src/components/instances/index.js | 2 + .../src/components/instances/list.js | 69 ++++++++-- .../src/components/instances/resize.js | 8 ++ .../containers/instances/create-snapshot.js | 94 +++++++++++++ .../src/containers/instances/index.js | 2 + .../src/containers/instances/list.js | 44 +++--- .../src/containers/instances/resize.js | 77 +++++++++++ .../src/graphql/create-snapshot.gql | 4 +- .../my-joy-beta/src/graphql/get-instance.gql | 5 +- .../my-joy-beta/src/graphql/get-package.gql | 14 ++ .../src/graphql/list-instances.gql | 3 + .../my-joy-beta/src/graphql/list-packages.gql | 6 + packages/my-joy-beta/src/router.js | 130 ++++++++++++------ packages/my-joyent/package.json | 2 +- packages/ui-toolkit/package.json | 9 +- packages/ui-toolkit/src/anchor/index.js | 8 +- packages/ui-toolkit/src/boxes/index.js | 20 ++- packages/ui-toolkit/src/button/index.js | 2 +- packages/ui-toolkit/src/topology/node/info.js | 9 +- yarn.lock | 32 ++--- 26 files changed, 561 insertions(+), 116 deletions(-) create mode 100644 packages/my-joy-beta/src/components/instances/create-snapshot.js create mode 100644 packages/my-joy-beta/src/components/instances/resize.js create mode 100644 packages/my-joy-beta/src/containers/instances/create-snapshot.js create mode 100644 packages/my-joy-beta/src/containers/instances/resize.js create mode 100644 packages/my-joy-beta/src/graphql/get-package.gql create mode 100644 packages/my-joy-beta/src/graphql/list-packages.gql 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 ( +
+ {_error} + + Name (optional) + + + + +
+ ); +}; 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: