From 3cb29e4b0d6df471c20cf608435449d74061c379 Mon Sep 17 00:00:00 2001 From: Andreas Litt Date: Sun, 11 Nov 2018 22:55:07 +0100 Subject: [PATCH 1/5] POC: add ink and draw simple counter with it --- package.json | 3 ++ src/commands/stack/apply.js | 2 + src/commands/stack/destroy.js | 2 + src/commands/stack/plan.js | 2 + src/logging.js | 14 +++---- src/visualization.js | 45 +++++++++++++++++++++++ yarn.lock | 69 +++++++++++++++++++++++++++++++++-- 7 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 src/visualization.js diff --git a/package.json b/package.json index 9c1d8b7..11b3df2 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,12 @@ "@oclif/plugin-help": "^2", "chalk": "^2.4.1", "hcl2json": "^0.2.3", + "ink": "^0.5.1", + "ink-redux": "^1.0.0", "lodash": "^4.17.11", "log4js": "^3.0.6", "mustache": "^3.0.0", + "redux": "^4.0.1", "underscore.string": "^3.3.5" }, "devDependencies": { diff --git a/src/commands/stack/apply.js b/src/commands/stack/apply.js index 33d8c7a..f19f50b 100644 --- a/src/commands/stack/apply.js +++ b/src/commands/stack/apply.js @@ -7,6 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("terrastack"); const applyLogging = require("../../logging.js"); +const applyVisualization = require("../../visualization.js"); class ApplyCommand extends Command { async run() { @@ -14,6 +15,7 @@ class ApplyCommand extends Command { const stack = require(process.cwd() + "/stack.js"); const terrastack = new Terrastack(stack); applyLogging(terrastack); + applyVisualization(terrastack); (async () => { await terrastack.apply(); })(); diff --git a/src/commands/stack/destroy.js b/src/commands/stack/destroy.js index fc93bfd..18feb6b 100644 --- a/src/commands/stack/destroy.js +++ b/src/commands/stack/destroy.js @@ -7,6 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("terrastack"); const applyLogging = require("../../logging.js"); +const applyVisualization = require("../../visualization.js"); class DestroyCommand extends Command { async run() { @@ -14,6 +15,7 @@ class DestroyCommand extends Command { const stack = require(process.cwd() + "/stack.js"); const terrastack = new Terrastack(stack); applyLogging(terrastack); + applyVisualization(terrastack); (async () => { await terrastack.destroy(); })(); diff --git a/src/commands/stack/plan.js b/src/commands/stack/plan.js index 5a809bd..2018f78 100644 --- a/src/commands/stack/plan.js +++ b/src/commands/stack/plan.js @@ -7,6 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("terrastack"); const applyLogging = require("../../logging.js"); +const applyVisualization = require("../../visualization.js"); class PlanCommand extends Command { async run() { @@ -14,6 +15,7 @@ class PlanCommand extends Command { const stack = require(process.cwd() + "/stack.js"); const terrastack = new Terrastack(stack); applyLogging(terrastack); + applyVisualization(terrastack); (async () => { await terrastack.plan(); })(); diff --git a/src/logging.js b/src/logging.js index d88f9b0..c6ba6c3 100644 --- a/src/logging.js +++ b/src/logging.js @@ -29,14 +29,14 @@ const applyLogger = base => { buffer.push(output); }); - base.events.on("component:**", function(component) { - console.log(`${component.name}: ${this.event}`); - }); + // base.events.on("component:**", function(component) { + // console.log(`${component.name}: ${this.event}`); + // }); - base.events.on("error", function(component) { - console.log(chalk.red.bold.underline(`Error: ${component.name}`)); - console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); - }); + // base.events.on("error", function(component) { + // console.log(chalk.red.bold.underline(`Error: ${component.name}`)); + // console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); + // }); }; module.exports = applyLogger; diff --git a/src/visualization.js b/src/visualization.js new file mode 100644 index 0000000..6128de9 --- /dev/null +++ b/src/visualization.js @@ -0,0 +1,45 @@ +const { h, render, Component } = require("ink"); +const { Provider, connect } = require("ink-redux"); +const { createStore } = require("redux"); + +const store = createStore((state = 0, action) => { + switch (action.type) { + case "INCREMENT": + return state + 1; + default: + return state; + } +}); + +const applyVisualization = base => { + let buffer = []; + + base.events.on("component:added", function(component) { + store.dispatch({ type: "INCREMENT" }); + }); + + base.events.on("output:*", function(_component, output) { + buffer.push(output); + }); + + base.events.on("error", function(component) { + // console.log(chalk.red.bold.underline(`Error: ${component.name}`)); + // console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); + }); + + render(h(Provider, { store }, h(ConnectedCounter))); +}; + +class Counter extends Component { + render(props) { + return `Component Counter: ${props.counter}`; + } +} + +const mapStateToProps = state => ({ + counter: state +}); + +const ConnectedCounter = connect(mapStateToProps)(Counter); + +module.exports = applyVisualization; diff --git a/yarn.lock b/yarn.lock index 1159242..d981402 100644 --- a/yarn.lock +++ b/yarn.lock @@ -760,7 +760,7 @@ clean-stack@^1.3.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31" integrity sha1-noIVAa6XmYbEax1m0tQy2y/UrjE= -cli-cursor@^2.1.0: +cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= @@ -2003,7 +2003,7 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^3.2.0: +indent-string@^3.1.0, indent-string@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= @@ -2026,6 +2026,24 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +ink-redux@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ink-redux/-/ink-redux-1.0.0.tgz#d4bbae9ab769f56eb2949973a07ab726c13d9d1d" + integrity sha512-2rftDFr4m75x/ea0QYlXFxO+RdNKnCMSkgLVkpXGmJ3QGssI1WbVTxRtsY3Cwem4yxQTOGkywG8U7X8cR/JCBg== + +ink@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/ink/-/ink-0.5.1.tgz#fc989c6c82f30f4667e711310b5134e8f7f2b17a" + integrity sha512-y+mE4HJ6rml4MQfLnKylTBinhtv3OmbBDaUKj2pNKti/1oLQGBhIMGDhpjy3kp4ILUV5+/TZBtlxbsEeO7e6SA== + dependencies: + arrify "^1.0.1" + chalk "^2.0.1" + indent-string "^3.1.0" + is-equal-shallow "^0.1.3" + lodash.flattendeep "^4.4.0" + log-update "^2.1.0" + prop-types "^15.5.10" + inquirer@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" @@ -2949,6 +2967,11 @@ lodash.camelcase@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= +lodash.flattendeep@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" + integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -2999,6 +3022,15 @@ lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +log-update@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" + integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= + dependencies: + ansi-escapes "^3.0.0" + cli-cursor "^2.0.0" + wrap-ansi "^3.0.1" + log4js@^3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.6.tgz#e6caced94967eeeb9ce399f9f8682a4b2b28c8ff" @@ -3010,7 +3042,7 @@ log4js@^3.0.6: rfdc "^1.1.2" streamroller "0.7.0" -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -3349,7 +3381,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -3669,6 +3701,14 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" +prop-types@^15.5.10: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -3789,6 +3829,14 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +redux@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5" + integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -4340,6 +4388,11 @@ supports-hyperlinks@^1.0.1: has-flag "^2.0.0" supports-color "^5.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" @@ -4716,6 +4769,14 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" + integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-4.0.0.tgz#b3570d7c70156159a2d42be5cc942e957f7b1131" From 5865fc06128d1c550281a8275f37c6347400ed5e Mon Sep 17 00:00:00 2001 From: Andreas Litt Date: Mon, 12 Nov 2018 23:23:59 +0100 Subject: [PATCH 2/5] WIP: implement boxes layout with (broken) spinner --- package.json | 2 + src/visualization.js | 133 +++++++++++++++++++++++++++++++++++++++---- yarn.lock | 60 ++++++++++++++++++- 3 files changed, 182 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 11b3df2..086acaf 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "chalk": "^2.4.1", "hcl2json": "^0.2.3", "ink": "^0.5.1", + "ink-box": "^0.1.0", "ink-redux": "^1.0.0", + "ink-spinner": "^2.0.0", "lodash": "^4.17.11", "log4js": "^3.0.6", "mustache": "^3.0.0", diff --git a/src/visualization.js b/src/visualization.js index 6128de9..15ae286 100644 --- a/src/visualization.js +++ b/src/visualization.js @@ -1,11 +1,35 @@ -const { h, render, Component } = require("ink"); +const { h, render, renderToString, Color, Component, Text } = require("ink"); const { Provider, connect } = require("ink-redux"); const { createStore } = require("redux"); +const Box = require("ink-box"); +const Spinner = require("ink-spinner"); +const log4js = require("log4js"); +const PropTypes = require("prop-types"); + +const store = createStore((state = {}, action) => { + if (action.component == undefined) { + return state; + } + + let layer = action.component._layer; + let name = action.component.name; -const store = createStore((state = 0, action) => { switch (action.type) { - case "INCREMENT": - return state + 1; + case "ADDED": + if (state[layer] == undefined) { + state[layer] = {}; + } + state[layer][name] = "added"; + return state; + case "START": + state[layer][name] = "start"; + return state; + case "SUCCESS": + state[layer][name] = "success"; + return state; + case "FAILED": + state[layer][name] = "failed"; + return state; default: return state; } @@ -15,7 +39,19 @@ const applyVisualization = base => { let buffer = []; base.events.on("component:added", function(component) { - store.dispatch({ type: "INCREMENT" }); + store.dispatch({ type: "ADDED", component: component }); + }); + + base.events.on("component:*:start", function(component) { + store.dispatch({ type: "START", component: component }); + }); + + base.events.on("component:*:success", function(component) { + store.dispatch({ type: "SUCCESS", component: component }); + }); + + base.events.on("component:*:failed", function(component) { + store.dispatch({ type: "FAILED", component: component }); }); base.events.on("output:*", function(_component, output) { @@ -27,19 +63,96 @@ const applyVisualization = base => { // console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); }); - render(h(Provider, { store }, h(ConnectedCounter))); + render(h(Provider, { store }, h(ConnectedStack))); }; -class Counter extends Component { +class Stack extends Component { render(props) { - return `Component Counter: ${props.counter}`; + let entries = []; + for (let layer in props.componentChunks) { + let chunk = props.componentChunks[layer]; + let rowEntries = []; + for (let name in chunk) { + let state = chunk[name]; + rowEntries.push(h(StackComponent, { name, state })); + } + entries.push(h(Row, {}, ...rowEntries)); + } + return h("div", {}, ...entries); } } +const StackComponent = props => { + let state = h("span", {}, "□"); + switch (props.state) { + case "start": + state = h(Spinner); + break; + case "success": + state = h(Color, { green: true }, "✔"); + break; + case "failed": + state = h(Color, { red: true }, "✖"); + break; + } + return h( + Box, + { borderStyle: "round", padding: { left: 1, right: 1 } }, + state, + h(Text, { bold: true }, ` ${props.name}`) + ); +}; + +class Row extends Component { + constructor(props) { + super(props); + + this.switchFrame = this.switchFrame.bind(this); + } + + render(props) { + log4js.getLogger("vis").info(props); + let renderedChilds = []; + for (const child of props.children) { + let childRows = renderToString(child).split("\n"); + renderedChilds.push(childRows); + } + + let rows = []; + let maxRows = Math.max(...renderedChilds.map(r => r.length)); + + for (const row of Array(maxRows).keys()) { + // TODO handle elements which are not the same height + rows.push(renderedChilds.map(c => c[row]).join(props.separator)); + } + + return h("div", {}, rows.join("\n")); + } + + componentDidMount() { + this.timer = setInterval(this.switchFrame, 100); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + switchFrame() { + this.forceUpdate(); + } +} + +Row.propTypes = { + children: PropTypes.node +}; +Row.defaultProps = { + separator: " " +}; + const mapStateToProps = state => ({ - counter: state + componentChunks: state }); -const ConnectedCounter = connect(mapStateToProps)(Counter); +const ConnectedStack = connect(mapStateToProps)(Stack); module.exports = applyVisualization; diff --git a/yarn.lock b/yarn.lock index d981402..bf5d072 100644 --- a/yarn.lock +++ b/yarn.lock @@ -175,6 +175,13 @@ ajv@^6.0.1, ajv@^6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= + dependencies: + string-width "^2.0.0" + ansi-escapes@^3.0.0, ansi-escapes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" @@ -551,6 +558,19 @@ block-stream@*: dependencies: inherits "~2.0.0" +boxen@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -668,7 +688,7 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= -camelcase@^4.1.0: +camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -760,6 +780,11 @@ clean-stack@^1.3.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-1.3.0.tgz#9e821501ae979986c46b1d66d2d432db2fd4ae31" integrity sha1-noIVAa6XmYbEax1m0tQy2y/UrjE= +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= + cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -767,6 +792,11 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" +cli-spinners@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== + cli-ux@^4.8.2: version "4.9.0" resolved "https://registry.yarnpkg.com/cli-ux/-/cli-ux-4.9.0.tgz#03e235c63c81614811f2400bb46ba140575b27c2" @@ -2026,11 +2056,28 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +ink-box@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ink-box/-/ink-box-0.1.0.tgz#b83222ad6f89b4d7f948e3e2a4b827d7755ee122" + integrity sha512-JNMn/CygaSnyrUmm1nDEH8u7kFWqf1qA9rHWUbKpW1n1CCsjVF2fRDQSrdiZCj8ZCsinxMB0JgSnvh9xSbyn6w== + dependencies: + boxen "^1.3.0" + prop-types "^15.6.1" + ink-redux@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ink-redux/-/ink-redux-1.0.0.tgz#d4bbae9ab769f56eb2949973a07ab726c13d9d1d" integrity sha512-2rftDFr4m75x/ea0QYlXFxO+RdNKnCMSkgLVkpXGmJ3QGssI1WbVTxRtsY3Cwem4yxQTOGkywG8U7X8cR/JCBg== +ink-spinner@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ink-spinner/-/ink-spinner-2.0.0.tgz#621c751ab8cd1fb2a77bcb1896cfc49c23950f3b" + integrity sha512-ptUejHyUpR0CFeq1n2T711yu1KhqadfZO1bg2ROawU1JVvFQjCWmXK/rX/T0ZzjsctEkqFaJ+Dm01QoWLkR9Lg== + dependencies: + cli-spinners "^1.0.0" + object.omit "^2.0.1" + prop-types "^15.5.10" + ink@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/ink/-/ink-0.5.1.tgz#fc989c6c82f30f4667e711310b5134e8f7f2b17a" @@ -3415,7 +3462,7 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.2" es-abstract "^1.5.1" -object.omit@^2.0.0: +object.omit@^2.0.0, object.omit@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= @@ -3701,7 +3748,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.5.10: +prop-types@^15.5.10, prop-types@^15.6.1: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== @@ -4455,6 +4502,13 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + test-exclude@^4.2.1: version "4.2.3" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" From 3555238ed528c56dfb56e601724f5adb4a65ee43 Mon Sep 17 00:00:00 2001 From: Sebastian Korfmann Date: Tue, 27 Nov 2018 00:03:49 +0100 Subject: [PATCH 3/5] Adapt it to ink#next with actual React --- .gitignore | 1 + package.json | 18 +- src/commands/stack/apply.js | 2 +- src/commands/stack/destroy.js | 2 +- src/commands/stack/plan.js | 2 +- src/component/index.js | 4 +- src/ui/components/row.js | 51 ++++ src/ui/components/spinner.js | 44 +++ src/ui/components/stack-component.js | 24 ++ src/ui/components/stack.js | 44 +++ src/ui/index.js | 82 ++++++ src/ui/store.js | 36 +++ src/visualization.js | 158 ----------- yarn.lock | 395 ++++++++++++++++++++++++++- 14 files changed, 687 insertions(+), 176 deletions(-) create mode 100644 src/ui/components/row.js create mode 100644 src/ui/components/spinner.js create mode 100644 src/ui/components/stack-component.js create mode 100644 src/ui/components/stack.js create mode 100644 src/ui/index.js create mode 100644 src/ui/store.js delete mode 100644 src/visualization.js diff --git a/.gitignore b/.gitignore index 9bb37b3..902e9c1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /dist /tmp node_modules +build/** diff --git a/package.json b/package.json index 111acd9..ab8c607 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,18 @@ "lodash": "^4.17.11", "log4js": "^3.0.6", "mustache": "^3.0.0", + "prop-types": "^15.6.2", + "react": "^16.6.3", + "react-redux": "^5.1.1", "recursive-copy": "^2.0.9", "redux": "^4.0.1", "underscore.string": "^3.3.5" }, "devDependencies": { + "@babel/cli": "^7.1.5", + "@babel/core": "^7.1.6", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/preset-react": "^7.0.0", "@oclif/dev-cli": "^1", "eslint": "^5.5", "eslint-config-oclif": "^3.1", @@ -48,7 +55,7 @@ "license": "MPL-2.0", "main": "src/index.js", "oclif": { - "commands": "./src/commands", + "commands": "./build/commands", "bin": "terrastack", "plugins": [ "@oclif/plugin-help" @@ -59,8 +66,17 @@ } } }, + "babel": { + "plugins": [ + "@babel/plugin-transform-modules-commonjs" + ], + "presets": [ + "@babel/preset-react" + ] + }, "repository": "terrastackio/terrastack-cli", "scripts": { + "build": "babel src --out-dir build", "postpack": "rm -f oclif.manifest.json npm-shrinkwrap.json", "prepack": "oclif-dev manifest && oclif-dev readme && npm shrinkwrap", "test": "jest", diff --git a/src/commands/stack/apply.js b/src/commands/stack/apply.js index f747e7f..448a644 100644 --- a/src/commands/stack/apply.js +++ b/src/commands/stack/apply.js @@ -7,7 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("../../orchestration/terrastack"); const applyLogging = require("../../logging.js"); -const applyVisualization = require("../../visualization.js"); +const { applyVisualization } = require("../../ui"); class ApplyCommand extends Command { async run() { diff --git a/src/commands/stack/destroy.js b/src/commands/stack/destroy.js index b72e8e5..388fd77 100644 --- a/src/commands/stack/destroy.js +++ b/src/commands/stack/destroy.js @@ -7,7 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("../../orchestration/terrastack"); const applyLogging = require("../../logging.js"); -const applyVisualization = require("../../visualization.js"); +const { applyVisualization } = require("../../ui"); class DestroyCommand extends Command { async run() { diff --git a/src/commands/stack/plan.js b/src/commands/stack/plan.js index 966595e..8006d0e 100644 --- a/src/commands/stack/plan.js +++ b/src/commands/stack/plan.js @@ -7,7 +7,7 @@ const { Command, flags } = require("@oclif/command"); const { Terrastack } = require("../../orchestration/terrastack"); const applyLogging = require("../../logging.js"); -const applyVisualization = require("../../visualization.js"); +const { applyVisualization } = require("../../ui"); class PlanCommand extends Command { async run() { diff --git a/src/component/index.js b/src/component/index.js index 33b4ccb..ec15708 100644 --- a/src/component/index.js +++ b/src/component/index.js @@ -18,13 +18,13 @@ const initComponent = (name, version, description) => { fs.writeFileSync(".terrastack/component/index.js", files.compononentJs); fs.writeFileSync(".terrastack/@types/index.d.ts", files.compononentTypes); - const package = Object.assign( + const packageJSON = Object.assign( {}, { name, version, description }, packageDefaults ); - fs.writeFileSync("package.json", JSON.stringify(package, null, 2)); + fs.writeFileSync("package.json", JSON.stringify(packageJSON, null, 2)); console.log("Successfully wrapped component"); }; diff --git a/src/ui/components/row.js b/src/ui/components/row.js new file mode 100644 index 0000000..4418414 --- /dev/null +++ b/src/ui/components/row.js @@ -0,0 +1,51 @@ +const log4js = require("log4js"); +const PropTypes = require("prop-types"); +import { Component } from "react"; + +class Row extends Component { + constructor(props) { + super(props); + + this.switchFrame = this.switchFrame.bind(this); + } + + render(props) { + log4js.getLogger("vis").info(props); + let renderedChilds = []; + for (const child of props.children) { + let childRows = renderToString(child).split("\n"); + renderedChilds.push(childRows); + } + + let rows = []; + let maxRows = Math.max(...renderedChilds.map(r => r.length)); + + for (const row of Array(maxRows).keys()) { + // TODO handle elements which are not the same height + rows.push(renderedChilds.map(c => c[row]).join(props.separator)); + } + + return h("div", {}, rows.join("\n")); + } + + componentDidMount() { + this.timer = setInterval(this.switchFrame, 100); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + switchFrame() { + this.forceUpdate(); + } +} + +Row.propTypes = { + children: PropTypes.node +}; +Row.defaultProps = { + separator: " " +}; + +module.exports = { Row }; diff --git a/src/ui/components/spinner.js b/src/ui/components/spinner.js new file mode 100644 index 0000000..f48d540 --- /dev/null +++ b/src/ui/components/spinner.js @@ -0,0 +1,44 @@ +import { Component } from "react"; +import spinners from "cli-spinners"; + +class Spinner extends Component { + constructor(props) { + super(props); + + this.state = { frame: 0 }; + this.switchFrame = this.switchFrame.bind(this); + } + + getSpinner() { + return spinners.dots; + } + + render() { + const spinner = this.getSpinner(); + return spinner.frames[this.state.frame]; + } + + componentDidMount() { + const spinner = this.getSpinner(); + + this.timer = setInterval(this.switchFrame, spinner.interval); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + switchFrame() { + const { frame } = this.state; + + const spinner = this.getSpinner(); + const isLastFrame = frame === spinner.frames.length - 1; + const nextFrame = isLastFrame ? 0 : frame + 1; + + this.setState({ + frame: nextFrame + }); + } +} + +module.exports = { Spinner }; diff --git a/src/ui/components/stack-component.js b/src/ui/components/stack-component.js new file mode 100644 index 0000000..5c2d1e2 --- /dev/null +++ b/src/ui/components/stack-component.js @@ -0,0 +1,24 @@ +import React, { Component } from "react"; +import { Box, Text } from "@terrastack/ink"; + +class StackComponent extends Component { + render() { + return ( + + + {this.props.item.name} - {this.props.item.status} + + + ); + } + + color() { + if (this.props.item.status === "success") { + return "green"; + } else { + return "white"; + } + } +} + +module.exports = { StackComponent }; diff --git a/src/ui/components/stack.js b/src/ui/components/stack.js new file mode 100644 index 0000000..523ab1e --- /dev/null +++ b/src/ui/components/stack.js @@ -0,0 +1,44 @@ +import React, { Component } from "react"; +import { StackComponent } from "./stack-component"; +import { connect } from "react-redux"; +import { Box } from "@terrastack/ink"; +import _ from "lodash"; + +class Row extends Component { + render() { + return {this.props.children}; + } +} + +class Stack extends Component { + render() { + if (_.isEmpty(this.props.rows)) { + return "Nothing to see"; + } else { + const elements = this.props.rows.map((row, index) => ( + + {row.map(item => ( + + ))} + + )); + + return elements; + } + } +} + +const mapStateToProps = state => { + const rows = Object.keys(state).map(layerIndex => { + const layer = state[layerIndex]; + return Object.keys(layer).map(name => { + return { + name, + status: layer[name] + }; + }); + }); + return { rows }; +}; + +module.exports = { Stack: connect(mapStateToProps)(Stack) }; diff --git a/src/ui/index.js b/src/ui/index.js new file mode 100644 index 0000000..8ed0a5e --- /dev/null +++ b/src/ui/index.js @@ -0,0 +1,82 @@ +import { render, Box } from "@terrastack/ink"; +// import store from "./store"; +import { Stack } from "./components/stack"; +import React from "react"; +import { Provider } from "react-redux"; + +const { createStore } = require("redux"); + +const store = createStore((state = {}, action) => { + if (action.component == undefined) { + return state; + } + + let layer = action.component._layer; + let name = action.component.name; + let newState = {}; + switch (action.type) { + case "ADDED": + if (state[layer] == undefined) { + state[layer] = {}; + } + newState = Object.assign({}, state); + newState[layer][name] = "added"; + return newState; + case "START": + if (state[layer] == undefined) { + state[layer] = {}; + } + newState = Object.assign({}, state); + newState[layer][name] = "start"; + return newState; + case "SUCCESS": + newState = Object.assign({}, state); + newState[layer][name] = "success"; + return newState; + case "FAILED": + newState = Object.assign({}, state); + newState[layer][name] = "failed"; + return newState; + default: + return state; + } +}); + +const applyVisualization = base => { + let buffer = []; + + base.events.on("component:added", function(component) { + store.dispatch({ type: "ADDED", component: component }); + }); + + base.events.on("component:*:start", function(component) { + store.dispatch({ type: "START", component: component }); + }); + + base.events.on("component:*:success", function(component) { + store.dispatch({ type: "SUCCESS", component: component }); + }); + + base.events.on("component:*:failed", function(component) { + store.dispatch({ type: "FAILED", component: component }); + }); + + base.events.on("output:*", function(_component, output) { + buffer.push(output); + }); + + base.events.on("error", function(component) { + // console.log(chalk.red.bold.underline(`Error: ${component.name}`)); + // console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); + }); + + render( + + + + ); +}; + +module.exports = { + applyVisualization +}; diff --git a/src/ui/store.js b/src/ui/store.js new file mode 100644 index 0000000..3f93be6 --- /dev/null +++ b/src/ui/store.js @@ -0,0 +1,36 @@ +const { createStore } = require("redux"); + +const store = createStore((state = {}, action) => { + if (action.component == undefined) { + return state; + } + + let layer = action.component._layer; + let name = action.component.name; + + switch (action.type) { + case "ADDED": + if (state[layer] == undefined) { + state[layer] = {}; + } + state[layer][name] = "added"; + return state; + case "START": + if (state[layer] == undefined) { + state[layer] = {}; + } + + state[layer][name] = "start"; + return state; + case "SUCCESS": + state[layer][name] = "success"; + return state; + case "FAILED": + state[layer][name] = "failed"; + return state; + default: + return state; + } +}); + +module.exports = store; diff --git a/src/visualization.js b/src/visualization.js deleted file mode 100644 index 15ae286..0000000 --- a/src/visualization.js +++ /dev/null @@ -1,158 +0,0 @@ -const { h, render, renderToString, Color, Component, Text } = require("ink"); -const { Provider, connect } = require("ink-redux"); -const { createStore } = require("redux"); -const Box = require("ink-box"); -const Spinner = require("ink-spinner"); -const log4js = require("log4js"); -const PropTypes = require("prop-types"); - -const store = createStore((state = {}, action) => { - if (action.component == undefined) { - return state; - } - - let layer = action.component._layer; - let name = action.component.name; - - switch (action.type) { - case "ADDED": - if (state[layer] == undefined) { - state[layer] = {}; - } - state[layer][name] = "added"; - return state; - case "START": - state[layer][name] = "start"; - return state; - case "SUCCESS": - state[layer][name] = "success"; - return state; - case "FAILED": - state[layer][name] = "failed"; - return state; - default: - return state; - } -}); - -const applyVisualization = base => { - let buffer = []; - - base.events.on("component:added", function(component) { - store.dispatch({ type: "ADDED", component: component }); - }); - - base.events.on("component:*:start", function(component) { - store.dispatch({ type: "START", component: component }); - }); - - base.events.on("component:*:success", function(component) { - store.dispatch({ type: "SUCCESS", component: component }); - }); - - base.events.on("component:*:failed", function(component) { - store.dispatch({ type: "FAILED", component: component }); - }); - - base.events.on("output:*", function(_component, output) { - buffer.push(output); - }); - - base.events.on("error", function(component) { - // console.log(chalk.red.bold.underline(`Error: ${component.name}`)); - // console.log(`Recent output: ${_.takeRight(buffer, 50).join("")}`); - }); - - render(h(Provider, { store }, h(ConnectedStack))); -}; - -class Stack extends Component { - render(props) { - let entries = []; - for (let layer in props.componentChunks) { - let chunk = props.componentChunks[layer]; - let rowEntries = []; - for (let name in chunk) { - let state = chunk[name]; - rowEntries.push(h(StackComponent, { name, state })); - } - entries.push(h(Row, {}, ...rowEntries)); - } - return h("div", {}, ...entries); - } -} - -const StackComponent = props => { - let state = h("span", {}, "□"); - switch (props.state) { - case "start": - state = h(Spinner); - break; - case "success": - state = h(Color, { green: true }, "✔"); - break; - case "failed": - state = h(Color, { red: true }, "✖"); - break; - } - return h( - Box, - { borderStyle: "round", padding: { left: 1, right: 1 } }, - state, - h(Text, { bold: true }, ` ${props.name}`) - ); -}; - -class Row extends Component { - constructor(props) { - super(props); - - this.switchFrame = this.switchFrame.bind(this); - } - - render(props) { - log4js.getLogger("vis").info(props); - let renderedChilds = []; - for (const child of props.children) { - let childRows = renderToString(child).split("\n"); - renderedChilds.push(childRows); - } - - let rows = []; - let maxRows = Math.max(...renderedChilds.map(r => r.length)); - - for (const row of Array(maxRows).keys()) { - // TODO handle elements which are not the same height - rows.push(renderedChilds.map(c => c[row]).join(props.separator)); - } - - return h("div", {}, rows.join("\n")); - } - - componentDidMount() { - this.timer = setInterval(this.switchFrame, 100); - } - - componentWillUnmount() { - clearInterval(this.timer); - } - - switchFrame() { - this.forceUpdate(); - } -} - -Row.propTypes = { - children: PropTypes.node -}; -Row.defaultProps = { - separator: " " -}; - -const mapStateToProps = state => ({ - componentChunks: state -}); - -const ConnectedStack = connect(mapStateToProps)(Stack); - -module.exports = applyVisualization; diff --git a/yarn.lock b/yarn.lock index 8ef8f8d..2a666fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,23 @@ # yarn lockfile v1 +"@babel/cli@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.1.5.tgz#4ccf0a8cdabeefdd8ce955384530f050935bc4d7" + integrity sha512-zbO/DtTnaDappBflIU3zYEgATLToRDmW5uN/EGH1GXaes7ydfjqmAoK++xmJIA+8HfDw7UyPZNdM8fhGhfmMhw== + dependencies: + commander "^2.8.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + output-file-sync "^2.0.0" + slash "^2.0.0" + source-map "^0.5.0" + optionalDependencies: + chokidar "^2.0.3" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" @@ -9,6 +26,109 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/core@^7.1.6": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.1.6.tgz#3733cbee4317429bc87c62b29cf8587dba7baeb3" + integrity sha512-Hz6PJT6e44iUNpAn8AoyAs6B3bl60g7MJQaI0rZEar6ECzh6+srYO1xlIdssio34mPaUtAb1y+XlkkSJzok3yw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.1.6" + "@babel/helpers" "^7.1.5" + "@babel/parser" "^7.1.6" + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.6" + "@babel/types" "^7.1.6" + convert-source-map "^1.1.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.10" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.1.6": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.1.6.tgz#001303cf87a5b9d093494a4bf251d7b5d03d3999" + integrity sha512-brwPBtVvdYdGxtenbQgfCdDPmtkmUBZPjUoK5SXJEBuHaA5BCubh9ly65fzXz7R6o5rA76Rs22ES8Z+HCc0YIQ== + dependencies: + "@babel/types" "^7.1.6" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-builder-react-jsx@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0.tgz#fa154cb53eb918cf2a9a7ce928e29eb649c5acdb" + integrity sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw== + dependencies: + "@babel/types" "^7.0.0" + esutils "^2.0.0" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" + integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + lodash "^4.17.10" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== + +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helpers@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.1.5.tgz#68bfc1895d685f2b8f1995e788dbfe1f6ccb1996" + integrity sha512-2jkcdL02ywNBry1YNFAH/fViq4fXG0vdckHqeJk+75fpQ2OH+Az6076tX/M0835zA45E0Cqa6pV5Kiv9YOqjEg== + dependencies: + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.5" + "@babel/types" "^7.1.5" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -18,6 +138,110 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.1.2", "@babel/parser@^7.1.6": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.6.tgz#16e97aca1ec1062324a01c5a6a7d0df8dd189854" + integrity sha512-dWP6LJm9nKT6ALaa+bnL247GHHMWir3vSlZ2+IHgHgktZQx0L3Uvq2uAWcuzIe+fujRsYWBW2q622C5UvGK9iQ== + +"@babel/plugin-syntax-jsx@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.0.0.tgz#034d5e2b4e14ccaea2e4c137af7e4afb39375ffd" + integrity sha512-PdmL2AoPsCLWxhIr3kG2+F9v4WH06Q3z+NoGVpQgnUNGcagXHq5sB3OXxkSahKq9TLdNMN/AJzFYSOo8UKDMHg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-commonjs@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" + integrity sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + +"@babel/plugin-transform-react-display-name@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0.tgz#93759e6c023782e52c2da3b75eca60d4f10533ee" + integrity sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-react-jsx-self@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.0.0.tgz#a84bb70fea302d915ea81d9809e628266bb0bc11" + integrity sha512-pymy+AK12WO4safW1HmBpwagUQRl9cevNX+82AIAtU1pIdugqcH+nuYP03Ja6B+N4gliAaKWAegIBL/ymALPHA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + +"@babel/plugin-transform-react-jsx-source@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.0.0.tgz#28e00584f9598c0dd279f6280eee213fa0121c3c" + integrity sha512-OSeEpFJEH5dw/TtxTg4nijl4nHBbhqbKL94Xo/Y17WKIf2qJWeIk/QeXACF19lG1vMezkxqruwnTjVizaW7u7w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + +"@babel/plugin-transform-react-jsx@^7.0.0": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.1.6.tgz#e6188e7d2a2dcd2796d45a87f8b0a8c906f57d1a" + integrity sha512-iU/IUlPEYDRwuqLwqVobzPAZkBOQoZ9xRTBmj6ANuk5g/Egn/zdNGnXlSoKeNmKoYVeIRxx5GZhWmMhLik8dag== + dependencies: + "@babel/helper-builder-react-jsx" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-jsx" "^7.0.0" + +"@babel/preset-react@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.0.0.tgz#e86b4b3d99433c7b3e9e91747e2653958bc6b3c0" + integrity sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + +"@babel/runtime@^7.1.2": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.5.tgz#4170907641cf1f61508f563ece3725150cc6fe39" + integrity sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA== + dependencies: + regenerator-runtime "^0.12.0" + +"@babel/template@^7.1.0", "@babel/template@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" + integrity sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.1.2" + "@babel/types" "^7.1.2" + +"@babel/traverse@^7.1.5", "@babel/traverse@^7.1.6": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.6.tgz#c8db9963ab4ce5b894222435482bd8ea854b7b5c" + integrity sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.1.6" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.1.6" + "@babel/types" "^7.1.6" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.5", "@babel/types@^7.1.6": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.6.tgz#0adb330c3a281348a190263aceb540e10f04bcce" + integrity sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -351,6 +575,11 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -569,6 +798,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +binary-extensions@^1.0.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== + bl@^1.0.0: version "1.2.2" resolved "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -594,7 +828,7 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -braces@^2.3.1: +braces@^2.3.0, braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== @@ -744,6 +978,26 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + chownr@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -882,6 +1136,11 @@ combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@^2.8.1: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" @@ -907,7 +1166,7 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.4.0, convert-source-map@^1.5.1: +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== @@ -1003,7 +1262,7 @@ debug@^3.1.0: dependencies: ms "^2.1.1" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== @@ -1421,7 +1680,7 @@ estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= -esutils@^2.0.2: +esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= @@ -1749,12 +2008,17 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.2.1" +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.3: +fsevents@^1.2.2, fsevents@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== @@ -1836,7 +2100,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -1848,6 +2112,11 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" + integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== + globals@^11.7.0: version "11.8.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.8.0.tgz#c1ef45ee9bed6badf0663c5cb90e8d1adec1321d" @@ -1992,6 +2261,13 @@ has@^1.0.1: dependencies: function-bind "^1.1.1" +hoist-non-react-statics@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.1.0.tgz#42414ccdfff019cd2168168be998c7b3bd5245c0" + integrity sha512-MYcYuROh7SBM69xHGqXEwQqDux34s9tz+sCnxJmN18kgWh6JFdTw/5YdZtqsOdZJXddE/wUpCzfEdDrJj8p0Iw== + dependencies: + react-is "^16.3.2" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -2092,7 +2368,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -2152,6 +2428,13 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -2330,7 +2613,7 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" -is-plain-obj@^1.0.0: +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= @@ -2880,6 +3163,11 @@ jsesc@^1.3.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -2915,6 +3203,13 @@ json5@^0.5.1: resolved "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3030,6 +3325,11 @@ lodash.camelcase@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -3569,6 +3869,15 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +output-file-sync@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-2.0.1.tgz#f53118282f5f553c2799541792b723a4c71430c0" + integrity sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ== + dependencies: + graceful-fs "^4.1.11" + is-plain-obj "^1.1.0" + mkdirp "^0.5.1" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -3786,7 +4095,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -prop-types@^15.6.2: +prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== @@ -3875,6 +4184,16 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^16.3.2, react-is@^16.6.0: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0" + integrity sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA== + +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + react-reconciler@^0.17.0: version "0.17.2" resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.17.2.tgz#cabe8cb403793f6462842e07b525c3b61c4f5cde" @@ -3885,6 +4204,29 @@ react-reconciler@^0.17.0: prop-types "^15.6.2" scheduler "^0.11.2" +react-redux@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.1.tgz#88e368682c7fa80e34e055cd7ac56f5936b0f52f" + integrity sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg== + dependencies: + "@babel/runtime" "^7.1.2" + hoist-non-react-statics "^3.1.0" + invariant "^2.2.4" + loose-envify "^1.1.0" + prop-types "^15.6.1" + react-is "^16.6.0" + react-lifecycles-compat "^3.0.0" + +react@^16.6.3: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react/-/react-16.6.3.tgz#25d77c91911d6bbdd23db41e70fb094cc1e0871c" + integrity sha512-zCvmH2vbEolgKxtqXL2wmGCUxUyNheYn/C+PD1YAjfxHC54+MhdruyhO7QieQrYsYeTxrn93PM2y0jRH1zEExw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.11.2" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -3902,7 +4244,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2.0.1, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -3915,6 +4257,15 @@ readable-stream@^2.0.1, readable-stream@^2.0.6, readable-stream@^2.3.0, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + realpath-native@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.2.tgz#cd51ce089b513b45cf9b1516c82989b51ccc6560" @@ -3958,6 +4309,11 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -4087,7 +4443,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.8.1: +resolve@^1.3.2, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== @@ -4246,6 +4602,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slice-ansi@1.0.0, slice-ansi@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" @@ -4321,7 +4682,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -4618,6 +4979,11 @@ to-fast-properties@^1.0.3: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -4731,6 +5097,11 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" From eb1dd71e2f15455a629e5bb8f633b40c123f75ce Mon Sep 17 00:00:00 2001 From: Sebastian Korfmann Date: Wed, 28 Nov 2018 23:38:57 +0100 Subject: [PATCH 4/5] Initial State / Better layout --- package.json | 2 +- src/ui/components/row.js | 51 ---------------- src/ui/components/stack-component.js | 26 +++++--- src/ui/components/stack.js | 78 ++++++++++++++++++++---- src/ui/index.js | 67 ++++++++------------- src/ui/store.js | 88 ++++++++++++++++++---------- 6 files changed, 169 insertions(+), 143 deletions(-) delete mode 100644 src/ui/components/row.js diff --git a/package.json b/package.json index ab8c607..256921f 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ }, "repository": "terrastackio/terrastack-cli", "scripts": { - "build": "babel src --out-dir build", + "build": "babel src --out-dir build --copy-files", "postpack": "rm -f oclif.manifest.json npm-shrinkwrap.json", "prepack": "oclif-dev manifest && oclif-dev readme && npm shrinkwrap", "test": "jest", diff --git a/src/ui/components/row.js b/src/ui/components/row.js deleted file mode 100644 index 4418414..0000000 --- a/src/ui/components/row.js +++ /dev/null @@ -1,51 +0,0 @@ -const log4js = require("log4js"); -const PropTypes = require("prop-types"); -import { Component } from "react"; - -class Row extends Component { - constructor(props) { - super(props); - - this.switchFrame = this.switchFrame.bind(this); - } - - render(props) { - log4js.getLogger("vis").info(props); - let renderedChilds = []; - for (const child of props.children) { - let childRows = renderToString(child).split("\n"); - renderedChilds.push(childRows); - } - - let rows = []; - let maxRows = Math.max(...renderedChilds.map(r => r.length)); - - for (const row of Array(maxRows).keys()) { - // TODO handle elements which are not the same height - rows.push(renderedChilds.map(c => c[row]).join(props.separator)); - } - - return h("div", {}, rows.join("\n")); - } - - componentDidMount() { - this.timer = setInterval(this.switchFrame, 100); - } - - componentWillUnmount() { - clearInterval(this.timer); - } - - switchFrame() { - this.forceUpdate(); - } -} - -Row.propTypes = { - children: PropTypes.node -}; -Row.defaultProps = { - separator: " " -}; - -module.exports = { Row }; diff --git a/src/ui/components/stack-component.js b/src/ui/components/stack-component.js index 5c2d1e2..1839988 100644 --- a/src/ui/components/stack-component.js +++ b/src/ui/components/stack-component.js @@ -4,19 +4,29 @@ import { Box, Text } from "@terrastack/ink"; class StackComponent extends Component { render() { return ( - - - {this.props.item.name} - {this.props.item.status} - + + {this.props.item.name} ); } color() { - if (this.props.item.status === "success") { - return "green"; - } else { - return "white"; + switch (this.props.item.status) { + case "start": + return "cyan"; + case "success": + return "green"; + case "diff": + return "yellow"; + case "failed": + return "red"; + default: + return "white"; } } } diff --git a/src/ui/components/stack.js b/src/ui/components/stack.js index 523ab1e..d78c534 100644 --- a/src/ui/components/stack.js +++ b/src/ui/components/stack.js @@ -1,12 +1,62 @@ import React, { Component } from "react"; import { StackComponent } from "./stack-component"; import { connect } from "react-redux"; -import { Box } from "@terrastack/ink"; +import { Box, Text } from "@terrastack/ink"; import _ from "lodash"; class Row extends Component { render() { - return {this.props.children}; + return ( + + {this.props.children} + + ); + } +} + +class Header extends Component { + render() { + return ( + + Stack: {this.props.stack.name} + + ); + } +} + +class Footer extends Component { + render() { + if (_.isEmpty(this.props.issues)) return " "; + const issues = this.props.issues.map(issue => { + return `${issue.component.name}: ${issue.reason}`; + }); + return ( + + + Note: {issues.join(",")} + + + ); + } +} + +class Logs extends Component { + render() { + if (_.isEmpty(this.props.issues)) return " "; + const issues = this.props.issues.map(issue => { + return `${issue.component.name}: ${issue.reason}`; + }); + return ( + + + Note: {issues.join(",")} + + + ); } } @@ -16,29 +66,35 @@ class Stack extends Component { return "Nothing to see"; } else { const elements = this.props.rows.map((row, index) => ( - + + + Step: {index} + {row.map(item => ( ))} )); - return elements; + return ( + +
+ {elements} +