├── .travis.yml ├── src ├── .eslintrc ├── index.test.js ├── css │ ├── state-machine-render.css │ └── graph-0.1.5.css └── index.js ├── .eslintignore ├── aws-sfn-graph.png ├── example ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.css │ ├── index.js │ ├── App.test.js │ └── App.js ├── .prettierrc ├── README.md ├── .eslintrc └── package.json ├── .editorconfig ├── .prettierrc ├── lib ├── Makefile ├── package.json ├── README.md └── index.css ├── .gitignore ├── .eslintrc ├── README.md └── package.json /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | .snapshots/ 5 | *.min.js -------------------------------------------------------------------------------- /aws-sfn-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tptshepo/aws-sfn-graph/HEAD/aws-sfn-graph.png -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tptshepo/aws-sfn-graph/HEAD/example/public/favicon.ico -------------------------------------------------------------------------------- /example/src/App.css: -------------------------------------------------------------------------------- 1 | /* Sizing CSS */ 2 | html, 3 | body { 4 | /* height: 100%; */ 5 | margin: 0px; 6 | padding: 0px; 7 | overflow-y: hidden; 8 | } 9 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | ReactDOM.render(, document.getElementById('root')) 6 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | // import { ExampleComponent } from '.' 2 | 3 | describe('ExampleComponent', () => { 4 | it('is truthy', () => { 5 | // expect(ExampleComponent).toBeTruthy() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /example/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "jsxSingleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always", 9 | "trailingComma": "none" 10 | } 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | This example was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | It is linked to the aws-sfn-graph package in the parent directory for development purposes. 4 | 5 | You can run `yarn install` and then `yarn start` to test your package. 6 | -------------------------------------------------------------------------------- /example/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div') 7 | ReactDOM.render(, div) 8 | ReactDOM.unmountComponentAtNode(div) 9 | }) 10 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: deploy build set_version 2 | 3 | VERSION := $(shell node -p "require('./package.json').version") 4 | NEW_VERSION := $(shell semver $(VERSION) -i patch) 5 | 6 | set_version: 7 | npm --no-git-tag-version --allow-same-version version $(NEW_VERSION) 8 | 9 | deploy: set_version 10 | npm publish 11 | 12 | .DEFAULT_GOAL := deploy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | 4 | # dependencies 5 | node_modules 6 | 7 | # builds 8 | build 9 | dist 10 | .rpt2_cache 11 | 12 | # misc 13 | .DS_Store 14 | .env 15 | .env.local 16 | .env.development.local 17 | .env.test.local 18 | .env.production.local 19 | 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | aws-sfn-graph 13 | 14 | 15 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@tshepomgaga/aws-sfn-graph", 3 | "version": "0.0.6", 4 | "main": "index.js", 5 | "private": false, 6 | "engines": { 7 | "node": ">=6.0" 8 | }, 9 | "publishConfig": { 10 | "access": "public" 11 | }, 12 | "engineStrict": true, 13 | "preferGlobal": true, 14 | "description": "Visualise the AWS Step Functions ASL JSON.", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/tptshepo/aws-sfn-graph.git" 18 | }, 19 | "keywords": [ 20 | "aws", 21 | "graph", 22 | "workflow" 23 | ], 24 | "author": "Tshepo Mgaga", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/tptshepo/aws-sfn-graph/issues" 28 | }, 29 | "homepage": "https://github.com/tptshepo/aws-sfn-graph#readme" 30 | } 31 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react", 6 | "plugin:prettier/recommended", 7 | "prettier/standard", 8 | "prettier/react" 9 | ], 10 | "globals": { 11 | "globalThis": false 12 | }, 13 | "env": { 14 | "node": true 15 | }, 16 | "parserOptions": { 17 | "ecmaVersion": 2020, 18 | "ecmaFeatures": { 19 | "legacyDecorators": true, 20 | "jsx": true 21 | } 22 | }, 23 | "settings": { 24 | "react": { 25 | "version": "16" 26 | } 27 | }, 28 | "rules": { 29 | "space-before-function-paren": 0, 30 | "react/prop-types": 0, 31 | "react/jsx-handler-names": 0, 32 | "react/jsx-fragments": 0, 33 | "react/no-unused-prop-types": 0, 34 | "import/export": 0 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "standard", 5 | "standard-react", 6 | "plugin:prettier/recommended", 7 | "prettier/standard", 8 | "prettier/react" 9 | ], 10 | "globals": { 11 | "globalThis": false 12 | }, 13 | "env": { 14 | "node": true 15 | }, 16 | "parserOptions": { 17 | "ecmaVersion": 2020, 18 | "ecmaFeatures": { 19 | "legacyDecorators": true, 20 | "jsx": true 21 | } 22 | }, 23 | "settings": { 24 | "react": { 25 | "version": "16" 26 | } 27 | }, 28 | "rules": { 29 | "space-before-function-paren": 0, 30 | "react/prop-types": 0, 31 | "react/jsx-handler-names": 0, 32 | "react/jsx-fragments": 0, 33 | "react/no-unused-prop-types": 0, 34 | "import/export": 0 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Step Functions Graph 2 | 3 | React library to visualise the AWS Step Functions ASL JSON. 4 | 5 | ## Install 6 | 7 | ```bash 8 | npm install --save aws-sfn-graph 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```jsx 14 | import React from 'react' 15 | 16 | import AWSSfnGraph from '@tshepomgaga/aws-sfn-graph'; 17 | import '@tshepomgaga/aws-sfn-graph/index.css'; 18 | 19 | const aslData = { 20 | Comment: 21 | 'A Hello World example of the Amazon States Language using Pass states', 22 | StartAt: 'Hello', 23 | States: { 24 | Hello: { 25 | Type: 'Pass', 26 | Result: 'Hello', 27 | Next: 'World' 28 | }, 29 | World: { 30 | Type: 'Pass', 31 | Result: 'World', 32 | End: true 33 | } 34 | } 35 | } 36 | 37 | const App = () => { 38 | return ( 39 | 45 | ) 46 | } 47 | 48 | export default App 49 | ``` 50 | 51 | ## Results 52 | 53 | 54 | 55 | ![alt text](https://github.com/tptshepo/aws-sfn-graph/blob/master/aws-sfn-graph.png?raw=true) 56 | 57 | ## License 58 | 59 | MIT © [tptshepo](https://github.com/tptshepo) 60 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # AWS Step Functions Graph 2 | 3 | React library to visualise the AWS Step Functions ASL JSON. 4 | 5 | ## Install 6 | 7 | ```bash 8 | npm install --save aws-sfn-graph 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```jsx 14 | import React from 'react' 15 | 16 | import AWSSfnGraph from '@tshepomgaga/aws-sfn-graph'; 17 | import '@tshepomgaga/aws-sfn-graph/index.css'; 18 | 19 | const aslData = { 20 | Comment: 21 | 'A Hello World example of the Amazon States Language using Pass states', 22 | StartAt: 'Hello', 23 | States: { 24 | Hello: { 25 | Type: 'Pass', 26 | Result: 'Hello', 27 | Next: 'World' 28 | }, 29 | World: { 30 | Type: 'Pass', 31 | Result: 'World', 32 | End: true 33 | } 34 | } 35 | } 36 | 37 | const App = () => { 38 | return ( 39 | 45 | ) 46 | } 47 | 48 | export default App 49 | ``` 50 | 51 | ## Results 52 | 53 | 54 | 55 | ![alt text](https://github.com/tptshepo/aws-sfn-graph/blob/master/aws-sfn-graph.png?raw=true) 56 | 57 | 58 | ## License 59 | 60 | MIT © [tptshepo](https://github.com/tptshepo) 61 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-sfn-graph-example", 3 | "homepage": ".", 4 | "version": "0.0.0", 5 | "private": true, 6 | "scripts": { 7 | "start": "node ../node_modules/react-scripts/bin/react-scripts.js start", 8 | "build": "node ../node_modules/react-scripts/bin/react-scripts.js build", 9 | "test": "node ../node_modules/react-scripts/bin/react-scripts.js test", 10 | "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject" 11 | }, 12 | "dependencies": { 13 | "react": "link:../node_modules/react", 14 | "react-dom": "link:../node_modules/react-dom", 15 | "react-scripts": "link:../node_modules/react-scripts", 16 | "aws-sfn-graph": "link:.." 17 | }, 18 | "devDependencies": { 19 | "@babel/plugin-syntax-object-rest-spread": "^7.8.3", 20 | "eslint": "^6.8.0", 21 | "eslint-config-prettier": "^6.7.0", 22 | "eslint-config-standard": "^14.1.0", 23 | "eslint-config-standard-react": "^9.2.0", 24 | "eslint-plugin-import": "^2.18.2", 25 | "eslint-plugin-node": "^11.0.0", 26 | "eslint-plugin-prettier": "^3.1.1", 27 | "eslint-plugin-promise": "^4.2.1", 28 | "eslint-plugin-react": "^7.17.0", 29 | "eslint-plugin-standard": "^4.0.1", 30 | "prettier": "^2.0.4" 31 | }, 32 | "eslintConfig": { 33 | "extends": "react-app" 34 | }, 35 | "browserslist": [ 36 | ">0.2%", 37 | "not dead", 38 | "not ie <= 11", 39 | "not op_mini all" 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /src/css/state-machine-render.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --editor-background: #fff; 3 | --btnLightOutlineColor: #b8b8b8; 4 | --btnLightIconColor: #616161; 5 | } 6 | 7 | .workflowgraph { 8 | /* background-color: #f9f9f9; */ 9 | display: flex; 10 | align-items: stretch; 11 | justify-content: center; 12 | } 13 | 14 | .graph-buttons-container { 15 | position: absolute; 16 | left: 2rem; 17 | top: 2rem; 18 | display: flex; 19 | flex-direction: column; 20 | z-index: 1000; 21 | } 22 | 23 | .graph-buttons-container button { 24 | background-color: var(--editor-background); 25 | border: 1px solid var(--btnLightOutlineColor); 26 | border-radius: 2px; 27 | display: flex; 28 | align-items: center; 29 | justify-content: center; 30 | text-decoration: none; 31 | cursor: pointer; 32 | width: 38px; 33 | height: 30px; 34 | margin-bottom: 10px; 35 | } 36 | 37 | .graph-buttons-container button svg { 38 | width: 14px; 39 | height: 14px; 40 | stroke-width: 2px; 41 | } 42 | 43 | .graph-buttons-container button:active { 44 | opacity: 0.7; 45 | } 46 | 47 | .graph-buttons-container button path { 48 | stroke-width: 2px; 49 | } 50 | 51 | .graph-buttons-container button line, 52 | .graph-buttons-container button path, 53 | .graph-buttons-container button circle { 54 | stroke: var(--btnLightIconColor); 55 | fill: transparent; 56 | } 57 | 58 | .graph-buttons-container button circle:nth-child(2) { 59 | fill: var(--btnLightIconColor); 60 | } 61 | 62 | .graph-buttons-container button:focus { 63 | outline: none; 64 | } 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-sfn-graph", 3 | "version": "1.0.0", 4 | "description": "Visualise the AWS Step Functions ASL JSON.", 5 | "author": "tptshepo", 6 | "license": "MIT", 7 | "repository": "tptshepo/aws-sfn-graph", 8 | "source": "src/index.js", 9 | "main": "dist/index.js", 10 | "module": "dist/index.modern.js", 11 | "engines": { 12 | "node": ">=10" 13 | }, 14 | "scripts": { 15 | "build": "microbundle-crl --format modern --css-modules false && cp dist/index.modern.css lib/index.css && cp dist/index.modern.js lib/index.js && cp dist/index.modern.js.map lib/index.js.map", 16 | "start": "microbundle-crl watch --format modern --css-modules false", 17 | "prepare": "run-s build", 18 | "test": "run-s test:unit test:lint test:build", 19 | "test:build": "run-s build", 20 | "test:lint": "eslint .", 21 | "test:unit": "cross-env CI=1 react-scripts test --env=jsdom", 22 | "test:watch": "react-scripts test --env=jsdom", 23 | "predeploy": "cd example && yarn install && yarn run build", 24 | "deploy": "gh-pages -d example/build" 25 | }, 26 | "peerDependencies": { 27 | "react": "^16.0.0" 28 | }, 29 | "devDependencies": { 30 | "microbundle-crl": "^0.13.10", 31 | "babel-eslint": "^10.0.3", 32 | "cross-env": "^7.0.2", 33 | "eslint": "^6.8.0", 34 | "eslint-config-prettier": "^6.7.0", 35 | "eslint-config-standard": "^14.1.0", 36 | "eslint-config-standard-react": "^9.2.0", 37 | "eslint-plugin-import": "^2.18.2", 38 | "eslint-plugin-node": "^11.0.0", 39 | "eslint-plugin-prettier": "^3.1.1", 40 | "eslint-plugin-promise": "^4.2.1", 41 | "eslint-plugin-react": "^7.17.0", 42 | "eslint-plugin-standard": "^4.0.1", 43 | "prettier": "^2.0.4", 44 | "gh-pages": "^2.2.0", 45 | "npm-run-all": "^4.1.5", 46 | "react": "^16.13.1", 47 | "react-dom": "^16.13.1", 48 | "react-scripts": "^3.4.1" 49 | }, 50 | "files": [ 51 | "dist" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import AWSSfnGraph from 'aws-sfn-graph' 3 | import 'aws-sfn-graph/src/css/graph-0.1.5.css' 4 | import 'aws-sfn-graph/src/css/state-machine-render.css' 5 | import React, { useState } from 'react' 6 | import './App.css' 7 | 8 | const aslData = { 9 | Comment: 10 | 'A Hello World example of the Amazon States Language using Pass states', 11 | StartAt: 'Hello', 12 | States: { 13 | Hello: { 14 | Type: 'Pass', 15 | Result: 'Hello', 16 | Next: 'World' 17 | }, 18 | World: { 19 | Type: 'Pass', 20 | Result: 'World', 21 | End: true 22 | } 23 | } 24 | } 25 | 26 | const aslDataError = `{ 27 | "Comment": "A Hello World example of the Amazon States Language using Pass states", 28 | "StartAt": "Hello", 29 | "States": { 30 | "Hello": { 31 | "Type": "Pass", 32 | "Result": "Hello", 33 | "Next": "Hello2" 34 | }, 35 | "Hello2": { 36 | "Type": "Pass", 37 | "Result": "Hello", 38 | "Next": "World" 39 | }, 40 | "World": { 41 | "Type": "Pass", 42 | "Result": "World", 43 | "End": true 44 | } 45 | } 46 | }` 47 | 48 | const App = () => { 49 | const [data, setData] = useState(aslData) 50 | 51 | // useEffect(() => { 52 | // setTimeout(() => setData(aslData), 3000) 53 | // setTimeout(() => setData(aslDataError), 6000) 54 | // }, []) 55 | 56 | const width = 600 57 | const height = 600 58 | 59 | return ( 60 | <> 61 |
62 |
63 |
One of three columns
64 |
65 |
68 | 74 |
75 |
76 |
One of three columns
77 |
78 |
79 | 80 | ) 81 | } 82 | 83 | export default App 84 | -------------------------------------------------------------------------------- /lib/index.css: -------------------------------------------------------------------------------- 1 | .workflowgraph{position:relative;padding:10px}.workflowgraph svg{overflow:hidden;margin:auto;display:block;width:100%;height:100%}.workflowgraph .node>.shape{stroke:#555;stroke-width:.6px;fill:#fff}.workflowgraph .node.state.Container>.shape,.workflowgraph .node.state.NotYetStarted>.shape{stroke-dasharray:5 2}.workflowgraph .node.state.Failed>.shape,.workflowgraph rect.legend.Failed{fill:#de322f}.workflowgraph .node.state.CaughtError>.shape,.workflowgraph rect.legend.CaughtError{fill:orange}.workflowgraph .node.state.Succeeded>.shape,.workflowgraph rect.legend.Succeeded{fill:#2bd62e}.workflowgraph .node.state.InProgress>.shape,.workflowgraph rect.legend.InProgress{fill:#53c9ed}.workflowgraph .node.state.Cancelled>.shape,.workflowgraph rect.legend.Cancelled{fill:#ddd}.workflowgraph .node.anchor>.shape{fill:#ffda75}.workflowgraph .node.selected>.shape,.workflowgraph .node.state.hovered:not(.selected):not(.NotYetStarted)>.shape{stroke:#555;stroke-width:2px}.workflowgraph .node.state.Container.Failed>.shape{fill:#ee9592}.workflowgraph .node.state.Container.CaughtError>.shape{fill:#ffd27f}.workflowgraph .node.state.Container.Succeeded>.shape{fill:#91ea9a}.workflowgraph .node.state.Container.InProgress>.shape{fill:#a9e4f7}.workflowgraph .node.state.Container.Cancelled>.shape{fill:#eee}.workflowgraph marker{fill:#555}.workflowgraph path{stroke:#555;background-color:#555;stroke-width:1px}.workflowgraph .node.anchor,.workflowgraph .node.state.NotYetStarted{cursor:default}.workflowgraph .node.state{cursor:pointer}.workflowgraph tspan .label{font-weight:400;font-size:12px;text-shadow:none}.workflowgraph .tooltip{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:300px;text-align:center;background-color:#f1faff;border:1px solid #007dbc;border-radius:2px;color:#16191f;padding:14px;font-family:Arial,Helvetica,sans-serif;font-size:14px;opacity:0;pointer-events:none} 2 | :root{--editor-background:#fff;--btnLightOutlineColor:#b8b8b8;--btnLightIconColor:#616161}.workflowgraph{display:flex;align-items:stretch;justify-content:center}.graph-buttons-container{position:absolute;left:2rem;top:2rem;display:flex;flex-direction:column;z-index:1000}.graph-buttons-container button{background-color:var(--editor-background);border:1px solid var(--btnLightOutlineColor);border-radius:2px;display:flex;align-items:center;justify-content:center;text-decoration:none;cursor:pointer;width:38px;height:30px;margin-bottom:10px}.graph-buttons-container button svg{width:14px;height:14px;stroke-width:2px}.graph-buttons-container button:active{opacity:.7}.graph-buttons-container button path{stroke-width:2px}.graph-buttons-container button circle,.graph-buttons-container button line,.graph-buttons-container button path{stroke:var(--btnLightIconColor);fill:transparent}.graph-buttons-container button circle:nth-child(2){fill:var(--btnLightIconColor)}.graph-buttons-container button:focus{outline:none} -------------------------------------------------------------------------------- /src/css/graph-0.1.5.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | .workflowgraph { 3 | position: relative; 4 | padding: 10px; 5 | } 6 | .workflowgraph svg { 7 | overflow: hidden; 8 | margin: auto; 9 | display: block; 10 | width: 100%; 11 | height: 100%; 12 | } 13 | .workflowgraph .node > .shape { 14 | stroke: #555; 15 | stroke-width: 0.6px; 16 | fill: #fff; 17 | } 18 | .workflowgraph .node.state.Container > .shape, 19 | .workflowgraph .node.state.NotYetStarted > .shape { 20 | stroke-dasharray: 5 2; 21 | } 22 | .workflowgraph .node.state.Failed > .shape, 23 | .workflowgraph rect.legend.Failed { 24 | fill: #de322f; 25 | } 26 | .workflowgraph .node.state.CaughtError > .shape, 27 | .workflowgraph rect.legend.CaughtError { 28 | fill: orange; 29 | } 30 | .workflowgraph .node.state.Succeeded > .shape, 31 | .workflowgraph rect.legend.Succeeded { 32 | fill: #2bd62e; 33 | } 34 | .workflowgraph .node.state.InProgress > .shape, 35 | .workflowgraph rect.legend.InProgress { 36 | fill: #53c9ed; 37 | } 38 | .workflowgraph .node.state.Cancelled > .shape, 39 | .workflowgraph rect.legend.Cancelled { 40 | fill: #ddd; 41 | } 42 | .workflowgraph .node.anchor > .shape { 43 | fill: #ffda75; 44 | } 45 | .workflowgraph .node.selected > .shape, 46 | .workflowgraph .node.state.hovered:not(.selected):not(.NotYetStarted) > .shape { 47 | stroke: #555; 48 | stroke-width: 2px; 49 | } 50 | .workflowgraph .node.state.Container.Failed > .shape { 51 | fill: #ee9592; 52 | } 53 | .workflowgraph .node.state.Container.CaughtError > .shape { 54 | fill: #ffd27f; 55 | } 56 | .workflowgraph .node.state.Container.Succeeded > .shape { 57 | fill: #91ea9a; 58 | } 59 | .workflowgraph .node.state.Container.InProgress > .shape { 60 | fill: #a9e4f7; 61 | } 62 | .workflowgraph .node.state.Container.Cancelled > .shape { 63 | fill: #eee; 64 | } 65 | .workflowgraph marker { 66 | fill: #555; 67 | } 68 | .workflowgraph path { 69 | stroke: #555; 70 | background-color: #555; 71 | stroke-width: 1px; 72 | } 73 | .workflowgraph .node.anchor, 74 | .workflowgraph .node.state.NotYetStarted { 75 | cursor: default; 76 | } 77 | .workflowgraph .node.state { 78 | cursor: pointer; 79 | } 80 | .workflowgraph tspan .label { 81 | font-weight: 400; 82 | font-size: 12px; 83 | text-shadow: none; 84 | } 85 | /* #header { 86 | text-align: left; 87 | padding: 5px; 88 | } */ 89 | /* #textholder { 90 | line-height: 30px; 91 | height: 300px; 92 | width: 600; 93 | float: left; 94 | padding: 10px; 95 | } */ 96 | 97 | .workflowgraph .tooltip { 98 | position: absolute; 99 | top: 50%; 100 | left: 50%; 101 | transform: translate(-50%, -50%); 102 | width: 300px; 103 | text-align: center; 104 | background-color: #f1faff; 105 | border: 1px solid #007dbc; 106 | border-radius: 2px; 107 | color: #16191f; 108 | padding: 14px; 109 | font-family: Arial, Helvetica, sans-serif; 110 | font-size: 14px; 111 | opacity: 0; 112 | pointer-events: none; 113 | } 114 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react' 2 | import './css/graph-0.1.5.css' 3 | import './css/state-machine-render.css' 4 | import './lib/sfn-0.1.5' 5 | 6 | const aslError = { 7 | Comment: 'Error state', 8 | StartAt: 'Error found in state definition', 9 | States: { 10 | 'Error found in state definition': { 11 | Type: 'Pass', 12 | Result: 'World', 13 | End: true 14 | } 15 | } 16 | } 17 | 18 | const aslTypeError = { 19 | Comment: 'Error state', 20 | StartAt: 'Type error found in state definition', 21 | States: { 22 | 'Type error found in state definition': { 23 | Type: 'Pass', 24 | Result: 'World', 25 | End: true 26 | } 27 | } 28 | } 29 | 30 | const aslEmpty = { 31 | Comment: 'Error state', 32 | StartAt: 'State definition not found', 33 | States: { 34 | 'State definition not found': { 35 | Type: 'Pass', 36 | Result: 'World', 37 | End: true 38 | } 39 | } 40 | } 41 | 42 | const AWSSfnGraph = (props) => { 43 | const { data, width, height, onError, hideToolbar = false } = props 44 | 45 | const containerId = useRef() 46 | const [graph, setGraph] = useState(null) 47 | 48 | useEffect(() => { 49 | renderStateMachine(data) 50 | }, [data, width, height]) 51 | 52 | const handleCenter = (e) => { 53 | e.preventDefault() 54 | renderStateMachine(data) 55 | } 56 | 57 | const handleZoomIn = (e) => { 58 | e.preventDefault() 59 | if (graph) { 60 | graph.zoomIn() 61 | } 62 | } 63 | 64 | const handleZoomOut = (e) => { 65 | e.preventDefault() 66 | if (graph) { 67 | graph.zoomOut() 68 | } 69 | } 70 | 71 | const renderStateMachine = (renderData, errorRender = false) => { 72 | try { 73 | const options = { 74 | width, 75 | height, 76 | resizeHeight: false, 77 | hideTooltip: true 78 | } 79 | let json 80 | // console.log('renderData type:', typeof renderData) 81 | // console.log('renderData data:', renderData) 82 | 83 | if (!renderData) { 84 | renderStateMachine(aslEmpty, true) 85 | return 86 | } 87 | 88 | if (typeof renderData === 'string') { 89 | if (renderData.trim().length === 0) { 90 | renderStateMachine(aslEmpty, true) 91 | return 92 | } 93 | json = JSON.parse(renderData) 94 | } else if (typeof renderData === 'object') { 95 | json = renderData 96 | } else { 97 | renderStateMachine(aslTypeError, true) 98 | return 99 | } 100 | 101 | const sfnGraph = new globalThis.sfn.StateMachineGraph( 102 | json, 103 | containerId.current, 104 | options 105 | ) 106 | setGraph(sfnGraph) 107 | sfnGraph.render() 108 | } catch (e) { 109 | if (onError) { 110 | onError(e) 111 | } 112 | if (!errorRender) { 113 | renderStateMachine(aslError, true) 114 | } 115 | } 116 | } 117 | 118 | return ( 119 |
120 |
121 | 122 |
123 | {hideToolbar ? ( 124 |
125 | ) : ( 126 |
127 | 137 | 147 | 156 | 166 |
167 | )} 168 |
169 | ) 170 | } 171 | 172 | AWSSfnGraph.displayName = 'AWSSfnGraph' 173 | 174 | export default AWSSfnGraph 175 | --------------------------------------------------------------------------------