├── .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 | 
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 | 
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 |
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 |
--------------------------------------------------------------------------------