Skip to content

Commit 44f8a3c

Browse files
committed
start.
0 parents  commit 44f8a3c

File tree

137 files changed

+11075
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+11075
-0
lines changed

.editorconfig

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = tab
6+
tab_width = 4
7+
insert_final_newline = true
8+
trim_trailing_whitespace = true
9+
10+
[*.ts]
11+
quote_type = single
12+
13+
[*.md]
14+
indent_style = space
15+
max_line_length = off
16+
trim_trailing_whitespace = false

.eslintrc.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"root": true,
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": [
5+
"@typescript-eslint"
6+
],
7+
"extends": [
8+
"eslint:recommended",
9+
"plugin:@typescript-eslint/eslint-recommended",
10+
"plugin:@typescript-eslint/recommended"
11+
],
12+
"rules": {
13+
"no-mixed-spaces-and-tabs": "off"
14+
}
15+
}

.github/workflows/main.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: main
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
push:
7+
branches:
8+
- main
9+
jobs:
10+
build:
11+
name: Build
12+
runs-on: ${{matrix.os}}
13+
strategy:
14+
matrix:
15+
os: [ubuntu-latest]
16+
node: [16]
17+
steps:
18+
- name: Checkout Repo
19+
uses: actions/checkout@v2
20+
- name: Setup Node 16
21+
uses: actions/setup-node@v2
22+
with:
23+
node-version: '16'
24+
- name: Packages
25+
run: bash .github/workflows/packages.sh

.github/workflows/packages.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
set -e
3+
4+
SCRIPT_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)
5+
6+
cd "$SCRIPT_DIR"
7+
yarn install
8+
yarn build
9+
yarn eslint
10+
yarn prettier
11+
yarn test:single

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.yarn/
2+
build/
3+
node_modules/
4+
coverage/
5+
.vscode/
6+
lib/
7+
dist/
8+
yarn-*.log

.prettierrc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"printWidth": 140,
3+
"singleQuote": true,
4+
"trailingComma": "none",
5+
"semi": true,
6+
"useTabs": true,
7+
"arrowParens": "avoid"
8+
}

LICENSE

+746
Large diffs are not rendered by default.

README.md

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Sequential Workflow Editor
2+
3+
Powerful workflow editor builder for sequential workflows. Written in TypeScript. Mainly designed to work with the [Sequential Workflow Designer](https://github.com/nocode-js/sequential-workflow-designer) component. To execute your model you may use the [Sequential Workflow Machine](https://github.com/nocode-js/sequential-workflow-machine) or any other workflow engine. It supports front-end and back-end strict validation of the model. 0 external dependencies.
4+
5+
📝 Check the [documentation](https://nocode-js.com/docs/category/sequential-workflow-editor) for more details.
6+
7+
## 👀 Examples
8+
9+
* [🛠 Playground](./demos/webpack-app/public/playground.html)
10+
11+
## 🚀 Installation
12+
13+
Install the `sequential-workflow-editor-model` package in your front-end project or your common project for front-end and back-end (check [this article](https://nocode-js.com/docs/sequential-workflow-designer/sharing-types-between-frontend-and-backend)):
14+
15+
```
16+
npm i sequential-workflow-editor-model
17+
```
18+
19+
Install the `sequential-workflow-editor` package in your front-end project:
20+
21+
```
22+
npm i sequential-workflow-editor
23+
```
24+
25+
## 🎬 Usage
26+
27+
At the beginning you need to create a model of your workflow for the editor. In this short tutorial let's consider the following workflow:
28+
29+
```ts
30+
import { Definition, Step } from 'sequential-workflow-model';
31+
32+
export interface MyDefinition extends Definition {
33+
properties: {
34+
inputs: VariableDefinitions;
35+
};
36+
}
37+
38+
export interface LogStep extends Step {
39+
type: 'log';
40+
componentType: 'task';
41+
properties: {
42+
message: string;
43+
};
44+
}
45+
```
46+
47+
Now we can create a model for the step:
48+
49+
```ts
50+
import { createStepModel, stringValueModel } from 'sequential-workflow-editor-model';
51+
52+
export const logStepModel = createStepModel<LogStep>('log', 'task', step => {
53+
step.property('message')
54+
.value(
55+
stringValueModel({
56+
minLength: 1
57+
})
58+
)
59+
.label('Message to log');
60+
});
61+
```
62+
63+
If your workflow contains global properties you can create a root model:
64+
65+
```ts
66+
import { createRootModel, variableDefinitionsValueModel } from 'sequential-workflow-editor-model';
67+
68+
export const rootModel = createRootModel<MyDefinition>(root => {
69+
root.property('inputs')
70+
.value(
71+
variableDefinitionsValueModel({})
72+
);
73+
);
74+
```
75+
76+
Now we can create a definition model:
77+
78+
```ts
79+
import { createDefinitionModel } from 'sequential-workflow-editor-model';
80+
81+
export const definitionModel = createDefinitionModel<MyDefinition>(model => {
82+
model.valueTypes(['string', 'number']);
83+
model.root(rootModel);
84+
model.steps([logStepModel]);
85+
});
86+
```
87+
88+
To create an editor provider you need to pass a definition model to the `EditorProvider.create` method. The provider requires a unique identifier generator. You can use the `Uid` class from the `sequential-workflow-designer` package.
89+
90+
```ts
91+
import { EditorProvider } from 'sequential-workflow-editor';
92+
import { Uid } from 'sequential-workflow-designer';
93+
94+
export const editorProvider = EditorProvider.create(definitionModel, {
95+
uidGenerator: Uid.next
96+
});
97+
```
98+
99+
We have everything to attach the editor provider to a designer. For the Sequential Workflow Designer you need to pass the following options:
100+
101+
```ts
102+
import { Designer } from 'sequential-workflow-designer';
103+
104+
const designer: Designer<MyDefinition> = Designer.create(placeholder, startDefinition, {
105+
editors: {
106+
globalEditorProvider: editorProvider.createRootEditorProvider(),
107+
stepEditorProvider: editorProvider.createStepEditorProvider(() => designer.getDefinition())
108+
},
109+
validator: {
110+
step: editorProvider.createStepValidator(),
111+
root: editorProvider.createRootValidator()
112+
},
113+
// ...
114+
});
115+
```
116+
117+
That's it! Check the source code of [our demo](./demos/webpack-app/) to see the final code.
118+
119+
## 💡 License
120+
121+
#### Commercial license
122+
123+
You are creating a closed source application and you are not distributing our library in source form. You may use this project under the terms of the [Commercial License](./LICENSE). To purchase license check the [pricing](https://nocode-js.com/sequential-workflow-editor/pricing).
124+
125+
#### Open source license
126+
127+
If you are developing a freely available software program using a license that aligns with the GNU General Public License version 3, you are permitted to utilize this project while abiding by the provisions outlined in the GPLv3.

demos/webpack-app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
public/builds/

demos/webpack-app/package.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "webpack-app-demo",
3+
"author": "b4rtaz",
4+
"license": "MIT",
5+
"private": true,
6+
"version": "1.0.0",
7+
"scripts": {
8+
"clean": "rm -rf public/build",
9+
"start": "webpack --mode development --watch",
10+
"build": "yarn clean && webpack --mode production",
11+
"eslint": "eslint ./src --ext .ts",
12+
"test:single": "echo \"No tests yet\"",
13+
"prettier": "prettier --check ./src",
14+
"prettier:fix": "prettier --write ./src"
15+
},
16+
"dependencies": {
17+
"xstate": "^4.37.2",
18+
"sequential-workflow-model": "^0.1.3",
19+
"sequential-workflow-designer": "^0.13.0",
20+
"sequential-workflow-machine": "^0.2.0",
21+
"sequential-workflow-editor-model": "^0.1.0",
22+
"sequential-workflow-editor": "^0.1.0"
23+
},
24+
"devDependencies": {
25+
"ts-loader": "^9.4.2",
26+
"style-loader": "^3.3.1",
27+
"css-loader": "^6.7.3",
28+
"typescript": "^4.9.4",
29+
"webpack": "^5.75.0",
30+
"webpack-cli": "^5.0.1",
31+
"prettier": "^2.8.7",
32+
"@typescript-eslint/eslint-plugin": "^5.47.0",
33+
"@typescript-eslint/parser": "^5.47.0",
34+
"eslint": "^8.30.0"
35+
}
36+
}
1.63 KB
Binary file not shown.
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>🛠 Playground - Sequential Workflow Editor</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
7+
<link rel="icon" href="./assets/favicon.ico">
8+
9+
<style>
10+
html, body {margin: 0; padding: 0; width: 100vw; height: 100vh; overflow: hidden; font: 14px/1.3em Arial, Verdana, sans-serif;}
11+
body {display: flex; flex-direction: row;}
12+
#designer {flex: 3;}
13+
#playground {flex: 1; padding: 10px; box-sizing: border-box; background-color: #CCC;}
14+
#playground h2 {margin: 0; padding: 10px 0;}
15+
#playground h4 {margin: 0; padding: 10px 0;}
16+
#playground .variables {padding: 0 5px 5px; background: #BBB; border-radius: 5px;}
17+
#playground .variable-row label {display: block; padding: 5px 0;}
18+
#playground .variable-row input[type=text] {padding: 5px; width: 100%; box-sizing: border-box; border: 1px solid #999; outline: 0; border-radius: 5px;}
19+
#playground .logs {width: 100%; padding: 5px; height: 400px; box-sizing: border-box; border: 1px solid #999; border-radius: 5px; outline: 0;}
20+
</style>
21+
</head>
22+
<body>
23+
<div id="designer"></div>
24+
25+
<div id="playground">
26+
<h2>🛠 Playground</h2>
27+
28+
<h4>Inputs</h4>
29+
<div id="inputs" class="variables"></div>
30+
31+
<h4>Logs</h4>
32+
<textarea id="logs" class="logs"></textarea>
33+
34+
<h4>Outputs</h4>
35+
<div id="outputs" class="variables"></div>
36+
</div>
37+
38+
<script src="./builds/playground.js"></script>
39+
</body>
40+
</html>
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { Designer } from 'sequential-workflow-designer';
2+
import { editorProvider } from './editor-provider';
3+
import { tryReadDefinition, saveDefinition } from './storage';
4+
import { Playground } from './playground';
5+
import { executeMachine } from './machine/machine-executor';
6+
import { MyDefinition, definitionModel } from './model/definition-model';
7+
8+
import 'sequential-workflow-designer/css/designer.css';
9+
import 'sequential-workflow-designer/css/designer-light.css';
10+
import 'sequential-workflow-editor/css/editor.css';
11+
12+
export class App {
13+
public static create(): App {
14+
const placeholder = document.getElementById('designer') as HTMLElement;
15+
16+
const startDefinition: MyDefinition = tryReadDefinition() ?? editorProvider.activateDefinition();
17+
18+
const designer: Designer<MyDefinition> = Designer.create(placeholder, startDefinition, {
19+
controlBar: true,
20+
editors: {
21+
globalEditorProvider: editorProvider.createRootEditorProvider(),
22+
stepEditorProvider: editorProvider.createStepEditorProvider(() => designer.getDefinition())
23+
},
24+
validator: {
25+
step: editorProvider.createStepValidator(),
26+
root: editorProvider.createRootValidator()
27+
},
28+
steps: {},
29+
toolbox: {
30+
groups: [
31+
{
32+
name: 'Steps',
33+
steps: Object.keys(definitionModel.steps).map(stepType => editorProvider.activateStep(stepType))
34+
}
35+
]
36+
}
37+
});
38+
39+
const playground = Playground.create();
40+
const app = new App(designer, playground);
41+
designer.onReady.subscribe(app.execute);
42+
designer.onDefinitionChanged.subscribe(app.execute);
43+
playground.onInputChanged.subscribe(app.execute);
44+
return app;
45+
}
46+
47+
private constructor(private readonly designer: Designer<MyDefinition>, private readonly playground: Playground) {}
48+
49+
private readonly execute = async () => {
50+
this.playground.clearLogs();
51+
52+
const definition = this.designer.getDefinition();
53+
this.playground.updateVariables(definition);
54+
saveDefinition(definition);
55+
56+
try {
57+
const inputVariableValues = this.playground.readInputVariables();
58+
59+
if (!this.designer.isValid()) {
60+
throw new Error('Definition is not valid');
61+
}
62+
63+
const snapshot = await executeMachine(definition, inputVariableValues, statePath => {
64+
this.playground.log(`<state: ${statePath}>`);
65+
});
66+
67+
if (snapshot.unhandledError) {
68+
const error = snapshot.unhandledError as Error;
69+
this.playground.log(`UNHANDLED ERROR: ${error.message}`);
70+
return;
71+
}
72+
73+
definition.properties.outputs.variables.forEach(variable => {
74+
if (snapshot.globalState.$variables.isSet(variable.name)) {
75+
const value = snapshot.globalState.$variables.read(variable.name);
76+
this.playground.setOutputVariable(variable.name, value);
77+
}
78+
});
79+
} catch (e) {
80+
const error = e as Error;
81+
this.playground.log(`FAILED: ${error.message}`);
82+
}
83+
};
84+
}
85+
86+
document.addEventListener('DOMContentLoaded', App.create, false);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { EditorProvider } from 'sequential-workflow-editor';
2+
import { Uid } from 'sequential-workflow-designer';
3+
import { definitionModel } from './model/definition-model';
4+
5+
export const editorProvider = EditorProvider.create(definitionModel, {
6+
uidGenerator: Uid.next
7+
});

0 commit comments

Comments
 (0)