Skip to content

Commit 0d9c597

Browse files
authored
0.3.2. (#8)
1 parent dfef511 commit 0d9c597

32 files changed

+416
-68
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.3.2
2+
3+
* The `StepModel` interface has two new properties: `category` and `description`. The category is used to group steps in the toolbox. The description is used to display an additional information about a step in the editor.
4+
* The `PropertyModel` interface has one new property: `hint`. The hint is used to display an additional information about a property in the editor.
5+
16
## 0.3.1
27

38
Added new value model: boolean (`booleanValueModel({ ... })`).

demos/webpack-app/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
"sequential-workflow-model": "^0.1.3",
1919
"sequential-workflow-designer": "^0.13.2",
2020
"sequential-workflow-machine": "^0.2.0",
21-
"sequential-workflow-editor-model": "^0.3.1",
22-
"sequential-workflow-editor": "^0.3.1"
21+
"sequential-workflow-editor-model": "^0.3.2",
22+
"sequential-workflow-editor": "^0.3.2"
2323
},
2424
"devDependencies": {
2525
"ts-loader": "^9.4.2",

demos/webpack-app/src/playground/app.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { editorProvider } from './editor-provider';
33
import { AppState, AppStorage } from './storage';
44
import { Playground } from './playground';
55
import { executeMachine } from './machine/machine-executor';
6-
import { MyDefinition, definitionModel } from './model/definition-model';
6+
import { MyDefinition } from './model/definition-model';
77
import { defaultAppState } from './default-state';
88

99
import 'sequential-workflow-designer/css/designer.css';
@@ -33,12 +33,7 @@ export class App {
3333
}
3434
},
3535
toolbox: {
36-
groups: [
37-
{
38-
name: 'Steps',
39-
steps: Object.keys(definitionModel.steps).map(stepType => editorProvider.activateStep(stepType))
40-
}
41-
]
36+
groups: editorProvider.getToolboxGroups()
4237
},
4338
undoStackSize: 10,
4439
definitionWalker

demos/webpack-app/src/playground/model/calculate-step-model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ export interface CalculateStep extends Step {
2222
}
2323

2424
export const calculateStepModel = createStepModel<CalculateStep>('calculate', 'task', step => {
25+
step.category('Values');
26+
step.description('Calculate value from two numbers. Result is stored in variable.');
27+
2528
const val = dynamicValueModel({
2629
models: [
2730
numberValueModel({}),

demos/webpack-app/src/playground/model/convert-value-step-model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export interface ConvertValueStep extends Step {
1111
}
1212

1313
export const convertValueStepModel = createStepModel<ConvertValueStep>('convertValue', 'task', step => {
14+
step.category('Values');
15+
step.description('Convert value from one variable to another.');
16+
1417
step.property('source')
1518
.value(
1619
nullableAnyVariableValueModel({

demos/webpack-app/src/playground/model/if-step-model.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export interface IfStep extends BranchedStep {
2323
}
2424

2525
export const ifStepModel = createBranchedStepModel<IfStep>('if', 'switch', step => {
26+
step.category('Logic');
27+
step.description('Check condition and execute different branches.');
28+
2629
const ab = dynamicValueModel({
2730
models: [
2831
numberValueModel({}),
@@ -34,17 +37,18 @@ export const ifStepModel = createBranchedStepModel<IfStep>('if', 'switch', step
3437
]
3538
});
3639

37-
step.property('a').value(ab).label('A');
40+
step.property('a').value(ab).label('A').hint('Left side of comparison.');
3841

3942
step.property('operator')
4043
.label('Operator')
4144
.value(
4245
choiceValueModel({
4346
choices: ['==', '===', '!=', '!==', '>', '>=', '<', '<=']
4447
})
45-
);
48+
)
49+
.hint('Comparison operator.\nStep supports strict and non-strict operators.');
4650

47-
step.property('b').value(ab).label('B');
51+
step.property('b').value(ab).label('B').hint('Right side of comparison.');
4852

4953
step.branches().value(
5054
branchesValueModel({

demos/webpack-app/src/playground/model/loop-step-model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export interface LoopStep extends SequentialStep {
2828
}
2929

3030
export const loopStepModel = createSequentialStepModel('loop', 'container', step => {
31+
step.category('Logic');
32+
step.description('Loop over a range of numbers.');
33+
3134
step.property('from')
3235
.label('From')
3336
.value(

demos/webpack-app/src/playground/model/root-model.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MyDefinition } from './definition-model';
33

44
export const rootModel = createRootModel<MyDefinition>(root => {
55
root.property('inputs')
6+
.hint('Variables passed to the workflow from the outside.')
67
.value(variableDefinitionsValueModel({}))
78
.dependentProperty('outputs')
89
.customValidator({
@@ -11,7 +12,9 @@ export const rootModel = createRootModel<MyDefinition>(root => {
1112
return inputs.variables.length > 0 ? null : 'At least one input is required';
1213
}
1314
});
14-
root.property('outputs').value(variableDefinitionsValueModel({})).label('Outputs');
15+
16+
root.property('outputs').hint('Variables returned from the workflow.').value(variableDefinitionsValueModel({})).label('Outputs');
17+
1518
root.sequence().value(
1619
sequenceValueModel({
1720
sequence: []

demos/webpack-app/src/playground/model/set-string-value-step-model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export interface SetStringValueStep extends Step {
1919
}
2020

2121
export const setStringValueStepModel = createStepModel<SetStringValueStep>('setStringValue', 'task', step => {
22+
step.category('Values');
23+
2224
step.property('variable')
2325
.value(
2426
nullableVariableValueModel({

editor/css/editor.css

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,23 @@
88
.swe-editor {
99
margin: 10px 0 0;
1010
font-size: 13px;
11-
line-height: 1.3em;
11+
line-height: 1.3rem;
12+
}
13+
.swe-editor-header {
14+
padding: 0 10px 5px;
15+
}
16+
.swe-editor-header-title {
17+
margin: 0;
18+
padding: 5px 0 10px;
19+
font-size: 1.4rem;
20+
line-height: 1.3rem;
21+
white-space: nowrap;
22+
text-overflow: ellipsis;
23+
overflow: hidden;
24+
}
25+
.swe-editor-header-description {
26+
margin: 0 0 10px;
27+
color: #666;
1228
}
1329

1430
/* properties */
@@ -24,14 +40,44 @@
2440
}
2541
.swe-property-header-label {
2642
display: block;
27-
flex: 1;
2843
padding: 0;
2944
margin: 0;
3045
font-size: 1.05rem;
46+
line-height: 1.3rem;
47+
}
48+
.swe-property-header-hint-toggle {
49+
display: block;
50+
width: 18px;
51+
height: 18px;
52+
margin: 0 8px;
53+
background: #ddd;
54+
border-radius: 50% 50%;
55+
text-align: center;
56+
font-size: 11px;
57+
cursor: pointer;
58+
}
59+
.swe-property-header-hint-toggle:hover {
60+
background: #eee;
61+
}
62+
.swe-property-header-hint-toggle-icon {
63+
width: 70%;
64+
height: 70%;
65+
margin: 15%;
66+
}
67+
.swe-property-header-hint-toggle-icon path {
68+
fill: #777;
3169
}
3270
.swe-property-header-control {
71+
flex: 1;
3372
text-align: right;
3473
}
74+
.swe-property-hint-text {
75+
margin: 0 0 10px;
76+
padding: 6px 10px;
77+
border-radius: 5px;
78+
background: #eee;
79+
border: 1px solid #ddd;
80+
}
3581
.swe-validation-error-text {
3682
margin: 0 0 10px;
3783
padding: 6px 10px;

editor/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sequential-workflow-editor",
3-
"version": "0.3.1",
3+
"version": "0.3.2",
44
"type": "module",
55
"main": "./lib/esm/index.js",
66
"types": "./lib/index.d.ts",
@@ -46,11 +46,11 @@
4646
"prettier:fix": "prettier --write ./src ./css"
4747
},
4848
"dependencies": {
49-
"sequential-workflow-editor-model": "^0.3.1",
49+
"sequential-workflow-editor-model": "^0.3.2",
5050
"sequential-workflow-model": "^0.1.3"
5151
},
5252
"peerDependencies": {
53-
"sequential-workflow-editor-model": "^0.3.1",
53+
"sequential-workflow-editor-model": "^0.3.2",
5454
"sequential-workflow-model": "^0.1.3"
5555
},
5656
"devDependencies": {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { inputComponent } from './input-component';
2+
3+
describe('InputComponent', () => {
4+
it('triggers onChanged event when new character is added to field', () => {
5+
let count = 0;
6+
7+
const input = inputComponent('Foo');
8+
input.onChanged.subscribe(value => {
9+
expect(value).toBe('FooB');
10+
count++;
11+
});
12+
13+
(input.view as HTMLInputElement).value = 'FooB';
14+
input.view.dispatchEvent(new Event('input'));
15+
16+
expect(count).toBe(1);
17+
});
18+
19+
it('renders input[type=text] by default', () => {
20+
const input = inputComponent('x');
21+
expect(input.view.getAttribute('type')).toBe('text');
22+
});
23+
24+
it('renders input[type=number] when configuration is set', () => {
25+
const input = inputComponent('x', { type: 'number' });
26+
expect(input.view.getAttribute('type')).toBe('number');
27+
});
28+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { SimpleEvent } from 'sequential-workflow-editor-model';
2+
import { Component } from './component';
3+
import { Html } from '../core';
4+
5+
export interface InputComponent extends Component {
6+
onChanged: SimpleEvent<string>;
7+
}
8+
9+
export interface InputConfiguration {
10+
type?: 'text' | 'number';
11+
placeholder?: string;
12+
}
13+
14+
export function inputComponent(value: string, configuration?: InputConfiguration): InputComponent {
15+
const onChanged = new SimpleEvent<string>();
16+
17+
const view = Html.element('input', {
18+
class: 'swe-input swe-stretched',
19+
type: configuration?.type ?? 'text'
20+
});
21+
if (configuration?.placeholder) {
22+
view.setAttribute('placeholder', configuration.placeholder);
23+
}
24+
view.value = value;
25+
view.addEventListener('input', () => {
26+
onChanged.forward(view.value);
27+
});
28+
29+
return {
30+
view,
31+
onChanged
32+
};
33+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { appendMultilineText } from './append-multiline-text';
2+
3+
describe('appendMultilineText()', () => {
4+
let parent: HTMLElement;
5+
6+
beforeEach(() => {
7+
parent = document.createElement('div');
8+
});
9+
10+
it('appends correctly if passed text with \\n', () => {
11+
appendMultilineText(parent, 'Hello\nWorld\nNow');
12+
13+
expect(parent.innerHTML).toBe('Hello<br>World<br>Now');
14+
});
15+
16+
it('appends correctly if passed text with \\r\\n', () => {
17+
appendMultilineText(parent, 'Hello\r\nWorld\r\nToday');
18+
19+
expect(parent.innerHTML).toBe('Hello<br>World<br>Today');
20+
});
21+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function appendMultilineText(target: HTMLElement, text: string) {
2+
const lines = text.split(/\r?\n/g);
3+
for (let i = 0; i < lines.length; i++) {
4+
if (i > 0) {
5+
target.appendChild(document.createElement('br'));
6+
}
7+
const line = document.createTextNode(lines[i]);
8+
target.appendChild(line);
9+
}
10+
}

editor/src/core/icons.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const ns = 'http://www.w3.org/2000/svg';
2+
3+
export class Icons {
4+
public static help =
5+
'M431-330q1-72 16.5-105t58.5-72q42-38 64.5-70.5T593-647q0-45-30-75t-84-30q-52 0-80 29.5T358-661l-84-37q22-59 74.5-100.5T479-840q100 0 154 55.5T687-651q0 48-20.5 87T601-482q-49 47-59 72t-11 80H431Zm48 250q-29 0-49.5-20.5T409-150q0-29 20.5-49.5T479-220q29 0 49.5 20.5T549-150q0 29-20.5 49.5T479-80Z';
6+
7+
public static createSvg(icon: string, cls: string): SVGElement {
8+
const svg = document.createElementNS(ns, 'svg');
9+
svg.setAttribute('viewBox', '0 -960 960 960');
10+
svg.classList.add(cls);
11+
const path = document.createElementNS(ns, 'path');
12+
path.setAttribute('d', icon);
13+
svg.appendChild(path);
14+
return svg;
15+
}
16+
}

editor/src/editor-header.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Component } from './components/component';
2+
import { Html } from './core';
3+
import { appendMultilineText } from './core/append-multiline-text';
4+
5+
export interface EditorHeaderData {
6+
title: string;
7+
description?: string;
8+
}
9+
10+
export class EditorHeader implements Component {
11+
public static create(data: EditorHeaderData): EditorHeader {
12+
const view = Html.element('div', { class: 'swe-editor-header' });
13+
14+
const title = Html.element('h3', { class: 'swe-editor-header-title' });
15+
title.textContent = data.title;
16+
view.appendChild(title);
17+
18+
if (data.description) {
19+
const description = Html.element('p', { class: 'swe-editor-header-description' });
20+
appendMultilineText(description, data.description);
21+
view.appendChild(description);
22+
}
23+
return new EditorHeader(view);
24+
}
25+
26+
private constructor(public readonly view: HTMLElement) {}
27+
}

editor/src/editor-provider-configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ import { DefinitionWalker } from 'sequential-workflow-model';
44
export interface EditorProviderConfiguration {
55
uidGenerator: UidGenerator;
66
definitionWalker?: DefinitionWalker;
7+
isHeaderHidden?: boolean;
78
}

0 commit comments

Comments
 (0)