Skip to content
This repository was archived by the owner on Mar 7, 2020. It is now read-only.

POC: add ink and draw simple counter with it #5

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/dist
/tmp
node_modules
build/**
20 changes: 19 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,25 @@
"@oclif/config": "^1",
"@oclif/plugin-help": "^2",
"@terrastack/hcl2json-wasm": "^1",
"@terrastack/ink": "^2.0.0",
"chalk": "^2.4.1",
"es6-template-strings": "^2.0.1",
"eventemitter2": "^5.0.1",
"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",
Expand All @@ -46,7 +55,7 @@
"license": "MPL-2.0",
"main": "src/index.js",
"oclif": {
"commands": "./src/commands",
"commands": "./build/commands",
"bin": "terrastack",
"plugins": [
"@oclif/plugin-help"
Expand All @@ -57,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",
Expand Down
2 changes: 2 additions & 0 deletions src/commands/stack/apply.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
const { Command, flags } = require("@oclif/command");
const { Terrastack } = require("../../orchestration/terrastack");
const applyLogging = require("../../logging.js");
const { applyVisualization } = require("../../ui");

class ApplyCommand extends Command {
async run() {
const { flags } = this.parse(ApplyCommand);
const stack = require(process.cwd() + "/stack.js");
const terrastack = new Terrastack(stack);
applyLogging(terrastack);
applyVisualization(terrastack);
(async () => {
await terrastack.apply();
})();
Expand Down
2 changes: 2 additions & 0 deletions src/commands/stack/destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
const { Command, flags } = require("@oclif/command");
const { Terrastack } = require("../../orchestration/terrastack");
const applyLogging = require("../../logging.js");
const { applyVisualization } = require("../../ui");

class DestroyCommand extends Command {
async run() {
const { flags } = this.parse(DestroyCommand);
const stack = require(process.cwd() + "/stack.js");
const terrastack = new Terrastack(stack);
applyLogging(terrastack);
applyVisualization(terrastack);
(async () => {
await terrastack.destroy();
})();
Expand Down
2 changes: 2 additions & 0 deletions src/commands/stack/plan.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
const { Command, flags } = require("@oclif/command");
const { Terrastack } = require("../../orchestration/terrastack");
const applyLogging = require("../../logging.js");
const { applyVisualization } = require("../../ui");

class PlanCommand extends Command {
async run() {
const { flags } = this.parse(PlanCommand);
const stack = require(process.cwd() + "/stack.js");
const terrastack = new Terrastack(stack);
applyLogging(terrastack);
applyVisualization(terrastack);
(async () => {
await terrastack.plan();
})();
Expand Down
4 changes: 2 additions & 2 deletions src/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
};

Expand Down
14 changes: 7 additions & 7 deletions src/logging.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
51 changes: 51 additions & 0 deletions src/ui/components/row.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const log4js = require("log4js");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole file is not used anymore, or?
(Can't verify it properly on my phone 😅)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to check, not sure :)

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 };
44 changes: 44 additions & 0 deletions src/ui/components/spinner.js
Original file line number Diff line number Diff line change
@@ -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 };
24 changes: 24 additions & 0 deletions src/ui/components/stack-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { Component } from "react";
import { Box, Text } from "@terrastack/ink";

class StackComponent extends Component {
render() {
return (
<Box border={1} borderColor={this.color()}>
<Text>
{this.props.item.name} - {this.props.item.status}
</Text>
</Box>
);
}

color() {
if (this.props.item.status === "success") {
return "green";
} else {
return "white";
}
}
}

module.exports = { StackComponent };
44 changes: 44 additions & 0 deletions src/ui/components/stack.js
Original file line number Diff line number Diff line change
@@ -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 <Box>{this.props.children}</Box>;
}
}

class Stack extends Component {
render() {
if (_.isEmpty(this.props.rows)) {
return "Nothing to see";
} else {
const elements = this.props.rows.map((row, index) => (
<Row key={index}>
{row.map(item => (
<StackComponent key={item.name} item={item} />
))}
</Row>
));

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) };
82 changes: 82 additions & 0 deletions src/ui/index.js
Original file line number Diff line number Diff line change
@@ -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 = [];

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can publish the initial state here? Or somehow fill it in the state directly?

IMHO: It make sense to move the initial state publishing to the clinic, as it is not needed anywhere else..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thought about something similar. We could just get the resolved stack and set it as initial state.

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(
<Provider store={store}>
<Stack />
</Provider>
);
};

module.exports = {
applyVisualization
};
Loading