Skip to content

Commit f23b57e

Browse files
authored
Merge pull request #16 from nocode-js/develop
0.5.1.
2 parents 7327ed7 + b90a07c commit f23b57e

21 files changed

+174
-84
lines changed

CHANGELOG.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.5.1
2+
3+
* Fixed calculation of label width in the switch step.
4+
* Added an exclamation mark to the warning icon.
5+
16
## 0.5.0
27

38
* Fixed losing the disabled state during dragging.
@@ -82,7 +87,7 @@ const config = {
8287

8388
#### Editor's Context
8489

85-
We've changed an approach how the editors should notify the designer about changes in the definition. We've deleted `revalidate()` and `notifiyDefinitionChanged()` methods from the `Designer` class. Instead of this, now editors receive an editor's context.
90+
We've changed an approach how the editors should notify the designer about changes in the definition. We've deleted `revalidate()` and `notifyDefinitionChanged()` methods from the `Designer` class. Instead of this, now editors receive an editor's context.
8691

8792
```ts
8893
interface StepEditorContext {
@@ -111,7 +116,7 @@ const config = {
111116
};
112117
```
113118

114-
#### Type Requirments
119+
#### Type Requirements
115120

116121
The `type` of a step cannot contain special characters from now. Check [the type validator](src/core/type-validator.ts).
117122

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ To import the package:
5151
import { Designer } from 'sequential-workflow-designer';
5252
```
5353

54-
If you use [css-loader](https://webpack.js.org/loaders/css-loader/) or similar, you can add CSS files to your boundle:
54+
If you use [css-loader](https://webpack.js.org/loaders/css-loader/) or similar, you can add CSS files to your bundle:
5555

5656
```ts
5757
import 'sequential-workflow-designer/css/designer.css';
@@ -73,10 +73,10 @@ Add the below code to your head section in HTML document.
7373
```html
7474
<head>
7575
...
76-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.0/css/designer.css" rel="stylesheet">
77-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.0/css/designer-light.css" rel="stylesheet">
78-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.0/css/designer-dark.css" rel="stylesheet">
79-
<script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.0/dist/index.umd.js"></script>
76+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.1/css/designer.css" rel="stylesheet">
77+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.1/css/designer-light.css" rel="stylesheet">
78+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.1/css/designer-dark.css" rel="stylesheet">
79+
<script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.5.1/dist/index.umd.js"></script>
8080
```
8181

8282
Call the designer by:

designer/css/designer-dark.css

+3
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,6 @@
162162
.sqd-theme-dark .sqd-validation-error {
163163
fill: #FFA200;
164164
}
165+
.sqd-theme-dark .sqd-validation-error-icon-path {
166+
fill: #000;
167+
}

designer/css/designer-light.css

+3
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,6 @@
162162
.sqd-theme-light .sqd-validation-error {
163163
fill: #FFA200;
164164
}
165+
.sqd-theme-light .sqd-validation-error-icon-path {
166+
fill: #000;
167+
}

designer/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sequential-workflow-designer",
3-
"version": "0.5.0",
3+
"version": "0.5.1",
44
"main": "./lib/index.mjs",
55
"types": "./lib/index.d.ts",
66
"repository": {

designer/src/core/icons.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export class Icons {
2525
public static options =
2626
'm19.4 44-1-6.3q-.95-.35-2-.95t-1.85-1.25l-5.9 2.7L4 30l5.4-3.95q-.1-.45-.125-1.025Q9.25 24.45 9.25 24q0-.45.025-1.025T9.4 21.95L4 18l4.65-8.2 5.9 2.7q.8-.65 1.85-1.25t2-.9l1-6.35h9.2l1 6.3q.95.35 2.025.925Q32.7 11.8 33.45 12.5l5.9-2.7L44 18l-5.4 3.85q.1.5.125 1.075.025.575.025 1.075t-.025 1.05q-.025.55-.125 1.05L44 30l-4.65 8.2-5.9-2.7q-.8.65-1.825 1.275-1.025.625-2.025.925l-1 6.3ZM24 30.5q2.7 0 4.6-1.9 1.9-1.9 1.9-4.6 0-2.7-1.9-4.6-1.9-1.9-4.6-1.9-2.7 0-4.6 1.9-1.9 1.9-1.9 4.6 0 2.7 1.9 4.6 1.9 1.9 4.6 1.9Z';
2727
public static expand = 'm24 30.75-12-12 2.15-2.15L24 26.5l9.85-9.85L36 18.8Z';
28+
public static alert =
29+
'M24 42q-1.45 0-2.475-1.025Q20.5 39.95 20.5 38.5q0-1.45 1.025-2.475Q22.55 35 24 35q1.45 0 2.475 1.025Q27.5 37.05 27.5 38.5q0 1.45-1.025 2.475Q25.45 42 24 42Zm-3.5-12V6h7v24Z';
2830

2931
public static appendPath(parent: SVGElement, pathClassName: string, d: string, size: number): SVGGElement {
3032
const g = Dom.svg('g');

designer/src/core/steps-traverser.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ContainerStep, Step, SwitchStep, TaskStep } from '../definition';
2-
import { StepExtensionsResolver } from '../workspace/step-extensions-resolver';
2+
import { StepExtensionResolver } from '../workspace/step-extension-resolver';
33
import { StepsTraverser } from './steps-traverser';
44

55
describe('StepsTraverser', () => {
@@ -49,7 +49,7 @@ describe('StepsTraverser', () => {
4949
let traverser: StepsTraverser;
5050

5151
beforeAll(() => {
52-
const extensions = StepExtensionsResolver.resolve([]);
52+
const extensions = StepExtensionResolver.create([]);
5353
traverser = new StepsTraverser(extensions);
5454
});
5555

designer/src/core/steps-traverser.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Branches, Definition, Sequence, Step } from '../definition';
22
import { StepChildrenType, StepChildren } from '../designer-configuration';
3-
import { StepExtensionDictionary } from '../workspace/component-context';
3+
import { StepExtensionResolver } from '../workspace/step-extension-resolver';
44

55
export interface StepWithParentSequence {
66
step: Step;
@@ -22,14 +22,11 @@ export interface StepWithParentAndChildSequences {
2222
}
2323

2424
export class StepsTraverser {
25-
public constructor(private readonly stepExtensions: StepExtensionDictionary) {}
25+
public constructor(private readonly stepExtensionResolver: StepExtensionResolver) {}
2626

2727
private getChildren(step: Step): StepChildren | null {
28-
const extension = this.stepExtensions[step.componentType];
29-
if (!extension) {
30-
throw new Error(`Not supported component type: ${step.componentType}`);
31-
}
32-
return extension.getChildren(step);
28+
const stepExtension = this.stepExtensionResolver.resolve(step.componentType);
29+
return stepExtension.getChildren(step);
3330
}
3431

3532
private find(

designer/src/designer-context.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import { DesignerConfiguration } from './designer-configuration';
77
import { DesignerState } from './designer-state';
88
import { HistoryController } from './history-controller';
99
import { LayoutController } from './layout-controller';
10-
import { StepExtensionDictionary } from './workspace/component-context';
10+
import { StepExtensionResolver } from './workspace/step-extension-resolver';
1111
import { WorkspaceController, WorkspaceControllerWrapper } from './workspace/workspace-controller';
1212

1313
export class DesignerContext {
1414
public static create(
1515
parent: HTMLElement,
1616
startDefinition: Definition,
1717
configuration: DesignerConfiguration,
18-
stepExtensions: StepExtensionDictionary
18+
stepExtensionResolver: StepExtensionResolver
1919
): DesignerContext {
2020
const definition = ObjectCloner.deepClone(startDefinition);
2121

@@ -26,7 +26,7 @@ export class DesignerContext {
2626
const state = new DesignerState(definition, isReadonly, isMobile, isMobile);
2727
const workspaceController = new WorkspaceControllerWrapper();
2828
const behaviorController = new BehaviorController();
29-
const stepsTraverser = new StepsTraverser(stepExtensions);
29+
const stepsTraverser = new StepsTraverser(stepExtensionResolver);
3030
const definitionModifier = new DefinitionModifier(stepsTraverser, state, configuration);
3131

3232
let historyController: HistoryController | undefined = undefined;

designer/src/designer.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { DesignerState } from './designer-state';
77
import { DefinitionModifier } from './definition-modifier';
88
import { WorkspaceController } from './workspace/workspace-controller';
99
import { ComponentContext } from './workspace/component-context';
10-
import { StepExtensionsResolver } from './workspace/step-extensions-resolver';
10+
import { StepExtensionResolver } from './workspace/step-extension-resolver';
1111
import { StepOrName, StepsTraverser } from './core/steps-traverser';
1212

1313
export class Designer {
@@ -19,10 +19,10 @@ export class Designer {
1919
* @returns An instance of a designer.
2020
*/
2121
public static create(placeholder: HTMLElement, startDefinition: Definition, configuration: DesignerConfiguration): Designer {
22-
const stepExtensions = StepExtensionsResolver.resolve(configuration.extensions);
22+
const stepExtensionResolver = StepExtensionResolver.create(configuration.extensions);
2323

24-
const designerContext = DesignerContext.create(placeholder, startDefinition, configuration, stepExtensions);
25-
const componentContext = ComponentContext.create(configuration.steps, stepExtensions);
24+
const designerContext = DesignerContext.create(placeholder, startDefinition, configuration, stepExtensionResolver);
25+
const componentContext = ComponentContext.create(configuration.steps, stepExtensionResolver);
2626

2727
const view = DesignerView.create(placeholder, designerContext, componentContext, designerContext.layoutController, configuration);
2828
const designer = new Designer(

designer/src/test-tools/stubs.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Definition, Step } from '../definition';
22
import { DesignerConfiguration } from '../designer-configuration';
33
import { DesignerContext } from '../designer-context';
44
import { ComponentContext } from '../workspace/component-context';
5-
import { StepExtensionsResolver } from '../workspace/step-extensions-resolver';
5+
import { StepExtensionResolver } from '../workspace/step-extension-resolver';
66

77
export function createDesignerConfigurationStub(): DesignerConfiguration {
88
return {
@@ -36,11 +36,11 @@ export function createDefinitionStub(): Definition {
3636

3737
export function createDesignerContextStub(): DesignerContext {
3838
const parent = document.createElement('div');
39-
const extensions = StepExtensionsResolver.resolve([]);
40-
return DesignerContext.create(parent, createDefinitionStub(), createDesignerConfigurationStub(), extensions);
39+
const resolver = StepExtensionResolver.create([]);
40+
return DesignerContext.create(parent, createDefinitionStub(), createDesignerConfigurationStub(), resolver);
4141
}
4242

4343
export function createComponentContextStub(): ComponentContext {
44-
const extensions = StepExtensionsResolver.resolve([]);
45-
return ComponentContext.create(createDesignerConfigurationStub().steps, extensions);
44+
const resolver = StepExtensionResolver.create([]);
45+
return ComponentContext.create(createDesignerConfigurationStub().steps, resolver);
4646
}

designer/src/workspace/common-views/validation-error-view.spec.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,21 @@ import { Dom } from '../../core/dom';
22
import { ValidationErrorView } from './validation-error-view';
33

44
describe('ValidationErrorView', () => {
5-
it('create() creates view', () => {
5+
it('shows and hides view', () => {
66
const parent = Dom.svg('svg');
7-
ValidationErrorView.create(parent, 10, 10);
8-
expect(parent.children.length).not.toEqual(0);
7+
const view = ValidationErrorView.create(parent, 10, 10);
8+
9+
expect(parent.children.length).toEqual(0);
10+
11+
view.setIsHidden(false);
12+
expect(parent.children.length).toEqual(1);
13+
const g = parent.children[0];
14+
15+
view.setIsHidden(false);
16+
expect(parent.children.length).toEqual(1);
17+
expect(parent.children[0]).toEqual(g);
18+
19+
view.setIsHidden(true);
20+
expect(parent.children.length).toEqual(0);
921
});
1022
});
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,41 @@
1+
import { Icons } from '../../core';
12
import { Dom } from '../../core/dom';
23

3-
const SIZE = 20;
4+
const SIZE = 22;
5+
const ICON_SIZE = 12;
46

57
export class ValidationErrorView {
68
public static create(parent: SVGElement, x: number, y: number): ValidationErrorView {
7-
const g = Dom.svg('g', {
8-
class: 'sqd-hidden'
9-
});
10-
Dom.translate(g, x, y);
11-
12-
const circle = Dom.svg('path', {
13-
class: 'sqd-validation-error',
14-
d: `M 0 ${-SIZE / 2} l ${SIZE / 2} ${SIZE} l ${-SIZE} 0 Z`
15-
});
16-
17-
g.appendChild(circle);
18-
parent.appendChild(g);
19-
return new ValidationErrorView(g);
9+
return new ValidationErrorView(parent, x, y);
2010
}
2111

22-
public constructor(private readonly g: SVGElement) {}
12+
private g?: SVGElement;
13+
14+
public constructor(private readonly parent: SVGElement, private readonly x: number, private readonly y: number) {}
2315

2416
public setIsHidden(isHidden: boolean) {
25-
Dom.toggleClass(this.g, isHidden, 'sqd-hidden');
17+
if (isHidden) {
18+
if (this.g) {
19+
this.parent.removeChild(this.g);
20+
this.g = undefined;
21+
}
22+
} else if (!this.g) {
23+
this.g = Dom.svg('g');
24+
Dom.translate(this.g, this.x, this.y);
25+
26+
const halfOfSize = SIZE / 2;
27+
const circle = Dom.svg('path', {
28+
class: 'sqd-validation-error',
29+
d: `M 0 ${-halfOfSize} l ${halfOfSize} ${SIZE} l ${-SIZE} 0 Z`
30+
});
31+
this.g.appendChild(circle);
32+
33+
const icon = Icons.appendPath(this.g, 'sqd-validation-error-icon-path', Icons.alert, ICON_SIZE);
34+
const offsetX = (SIZE - ICON_SIZE) * 0.5;
35+
const offsetY = offsetX * 1.5; // 0.5 * 1.5 = 0.75
36+
Dom.translate(icon, -halfOfSize + offsetX, -halfOfSize + offsetY);
37+
38+
this.parent.appendChild(this.g);
39+
}
2640
}
2741
}

designer/src/workspace/component-context.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { StepExtension, StepsConfiguration } from '../designer-configuration';
1+
import { StepsConfiguration } from '../designer-configuration';
22
import { StepComponentFactory } from './step-component-factory';
3-
4-
export type StepExtensionDictionary = Record<string, StepExtension>;
3+
import { StepExtensionResolver } from './step-extension-resolver';
54

65
export class ComponentContext {
7-
public static create(configuration: StepsConfiguration, stepExtensions: StepExtensionDictionary): ComponentContext {
8-
return new ComponentContext(configuration, new StepComponentFactory(stepExtensions));
6+
public static create(configuration: StepsConfiguration, stepExtensionResolver: StepExtensionResolver): ComponentContext {
7+
return new ComponentContext(configuration, new StepComponentFactory(stepExtensionResolver));
98
}
109

1110
private constructor(public readonly configuration: StepsConfiguration, public readonly stepComponentFactory: StepComponentFactory) {}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { Sequence, Step } from '../definition';
22
import { StepComponent } from './component';
3-
import { ComponentContext, StepExtensionDictionary } from './component-context';
3+
import { ComponentContext } from './component-context';
4+
import { StepExtensionResolver } from './step-extension-resolver';
45

56
export class StepComponentFactory {
6-
public constructor(private readonly extensions: StepExtensionDictionary) {}
7+
public constructor(private readonly stepExtensionResolver: StepExtensionResolver) {}
78

89
public create(parentElement: SVGElement, step: Step, parentSequence: Sequence, context: ComponentContext): StepComponent {
9-
const extension = this.extensions[step.componentType];
10-
if (!extension) {
11-
throw new Error(`Unknown component type: ${step.componentType}`);
12-
}
13-
return extension.createComponent(parentElement, step, parentSequence, context);
10+
const stepExtension = this.stepExtensionResolver.resolve(step.componentType);
11+
return stepExtension.createComponent(parentElement, step, parentSequence, context);
1412
}
1513
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Step } from '../definition';
2+
import { StepComponent } from './component';
3+
import { DesignerExtension, StepExtension } from '../designer-configuration';
4+
import { StepExtensionResolver } from './step-extension-resolver';
5+
6+
class OwnTaskStepExtension implements StepExtension<Step> {
7+
public readonly componentType = 'task';
8+
9+
public createComponent(): StepComponent {
10+
throw new Error('Not implemented');
11+
}
12+
public getChildren() {
13+
return null;
14+
}
15+
}
16+
17+
const ownTaskStepExtension = new OwnTaskStepExtension();
18+
19+
class OwnTaskDesignerExtension implements DesignerExtension {
20+
public readonly name: string = 'test';
21+
public steps: StepExtension<Step>[] = [ownTaskStepExtension];
22+
}
23+
24+
describe('StepExtensionsResolver', () => {
25+
describe('default resolver', () => {
26+
const resolver = StepExtensionResolver.create([]);
27+
28+
it('resolves task', () => {
29+
expect(resolver.resolve('task')).toBeDefined();
30+
});
31+
32+
it('resolves switch', () => {
33+
expect(resolver.resolve('switch')).toBeDefined();
34+
});
35+
36+
it('resolves container', () => {
37+
expect(resolver.resolve('container')).toBeDefined();
38+
});
39+
});
40+
41+
it('can replace default extension', () => {
42+
const resolver = StepExtensionResolver.create([new OwnTaskDesignerExtension()]);
43+
44+
expect(resolver.resolve('task')).toEqual(ownTaskStepExtension);
45+
});
46+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ComponentType, Step } from '../definition';
2+
import { DesignerExtension, StepExtension } from '../designer-configuration';
3+
import { ContainerStepExtension } from './container-step/container-step-extension';
4+
import { SwitchStepExtension } from './switch-step/switch-step-extension';
5+
import { TaskStepExtension } from './task-step/task-step-extension';
6+
7+
type StepExtensionDictionary = Record<string, StepExtension>;
8+
9+
export class StepExtensionResolver {
10+
public static create(extensions: DesignerExtension[] | undefined): StepExtensionResolver {
11+
const dict: StepExtensionDictionary = {};
12+
dict['task'] = new TaskStepExtension();
13+
dict['switch'] = new SwitchStepExtension();
14+
dict['container'] = new ContainerStepExtension();
15+
if (extensions) {
16+
for (const extension of extensions) {
17+
extension.steps.forEach(stepExt => (dict[stepExt.componentType] = stepExt));
18+
}
19+
}
20+
return new StepExtensionResolver(dict);
21+
}
22+
23+
private constructor(private readonly dict: StepExtensionDictionary) {}
24+
25+
public resolve(componentType: ComponentType): StepExtension<Step> {
26+
const extension = this.dict[componentType];
27+
if (!extension) {
28+
throw new Error(`Not supported component type: ${componentType}`);
29+
}
30+
return extension;
31+
}
32+
}

0 commit comments

Comments
 (0)