Skip to content

Commit 26f3a38

Browse files
authored
Merge pull request #23 from nocode-js/develop
0.7.0.
2 parents f2b6cf8 + 1ea297c commit 26f3a38

File tree

61 files changed

+645
-253
lines changed

Some content is hidden

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

61 files changed

+645
-253
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 0.7.0
2+
3+
* The step validator has two parameters from now: `step` and `parentSequence`.
4+
* Added new editing restrictions: `isDraggable` and `isDeletable`.
5+
6+
#### Breaking Changes
7+
8+
* Refactored step components by introducing the `StepContext` interface.
9+
* Renamed `.sqd-step-start-stop*` CSS selectors to `.sqd-root-start-stop*`.
10+
111
## 0.6.0
212

313
Fixed support for touchpad.

README.md

+14-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Features:
2929
* [📐 Simple Flow](https://nocode-js.github.io/sequential-workflow-designer/examples/simple-flow.html)
3030
* [🌻 Rendering Test](https://nocode-js.github.io/sequential-workflow-designer/examples/rendering-test.html)
3131
* [🚄 Stress Test](https://nocode-js.github.io/sequential-workflow-designer/examples/stress-test.html)
32+
* [🚪 Editing Restrictions](https://nocode-js.github.io/sequential-workflow-designer/examples/editing-restrictions.html)
3233

3334
Pro:
3435

@@ -75,10 +76,10 @@ Add the below code to your head section in HTML document.
7576
```html
7677
<head>
7778
...
78-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.6.0/css/designer.css" rel="stylesheet">
79-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.6.0/css/designer-light.css" rel="stylesheet">
80-
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.6.0/css/designer-dark.css" rel="stylesheet">
81-
<script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.6.0/dist/index.umd.js"></script>
79+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.7.0/css/designer.css" rel="stylesheet">
80+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.7.0/css/designer-light.css" rel="stylesheet">
81+
<link href="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.7.0/css/designer-dark.css" rel="stylesheet">
82+
<script src="https://cdn.jsdelivr.net/npm/sequential-workflow-designer@0.7.0/dist/index.umd.js"></script>
8283
```
8384

8485
Call the designer by:
@@ -131,12 +132,20 @@ const configuration = {
131132
},
132133

133134
steps: {
135+
// all properties in this section are optional
136+
134137
iconUrlProvider: (componentType, type) => {
135138
return `icon-${componentType}-${type}.svg`;
136139
},
137-
validator: (step) => {
140+
validator: (step, sourceSequence) => {
138141
return /^[a-z]+$/.test(step.name);
139142
},
143+
isDraggable: (step, parentSequence) => {
144+
return step.name !== 'y';
145+
},
146+
isDeletable: (step, parentSequence) => {
147+
return step.properties['isDeletable'];
148+
},
140149
canInsertStep: (step, targetSequence, targetIndex) => {
141150
return targetSequence.length < 5;
142151
},

angular/designer/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sequential-workflow-designer-angular",
33
"description": "Angular wrapper for Sequential Workflow Designer component.",
4-
"version": "0.6.0",
4+
"version": "0.7.0",
55
"author": "N4NO.com",
66
"license": "MIT",
77
"repository": {
@@ -11,7 +11,7 @@
1111
"peerDependencies": {
1212
"@angular/common": "^15.1.0",
1313
"@angular/core": "^15.1.0",
14-
"sequential-workflow-designer": "^0.6.0"
14+
"sequential-workflow-designer": "^0.7.0"
1515
},
1616
"dependencies": {
1717
"tslib": "^2.3.0"

demos/angular-app/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
"rxjs": "~7.8.0",
2626
"tslib": "^2.3.0",
2727
"zone.js": "~0.12.0",
28-
"sequential-workflow-designer": "^0.6.0",
29-
"sequential-workflow-designer-angular": "^0.6.0"
28+
"sequential-workflow-designer": "^0.7.0",
29+
"sequential-workflow-designer-angular": "^0.7.0"
3030
},
3131
"devDependencies": {
3232
"@angular-devkit/build-angular": "^15.1.1",

demos/react-app/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"dependencies": {
66
"react": "^18.2.0",
77
"react-dom": "^18.2.0",
8-
"sequential-workflow-designer": "^0.6.0",
9-
"sequential-workflow-designer-react": "^0.6.0"
8+
"sequential-workflow-designer": "^0.7.0",
9+
"sequential-workflow-designer-react": "^0.7.0"
1010
},
1111
"devDependencies": {
1212
"@types/jest": "^29.2.5",

designer/css/designer-dark.css

+3-3
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@
113113
fill: #FFF;
114114
}
115115

116-
/* dark > .sqd-step-start-stop */
116+
/* dark > .sqd-root-start-stop */
117117

118-
.sqd-theme-dark .sqd-step-start-stop-circle {
118+
.sqd-theme-dark .sqd-root-start-stop-circle {
119119
fill: #2C18DF;
120120
}
121-
.sqd-theme-dark .sqd-step-start-stop-icon {
121+
.sqd-theme-dark .sqd-root-start-stop-icon {
122122
fill: #FFF;
123123
}
124124

designer/css/designer-light.css

+3-3
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@
113113
fill: #FFF;
114114
}
115115

116-
/* light > .sqd-step-start-stop */
116+
/* light > .sqd-root-start-stop */
117117

118-
.sqd-theme-light .sqd-step-start-stop-circle {
118+
.sqd-theme-light .sqd-root-start-stop-circle {
119119
fill: #2C18DF;
120120
}
121-
.sqd-theme-light .sqd-step-start-stop-icon {
121+
.sqd-theme-light .sqd-root-start-stop-icon {
122122
fill: #FFF;
123123
}
124124

designer/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sequential-workflow-designer",
33
"description": "Customizable no-code component for building flow-based programming applications.",
4-
"version": "0.6.0",
4+
"version": "0.7.0",
55
"main": "./lib/index.mjs",
66
"types": "./lib/index.d.ts",
77
"repository": {
@@ -54,4 +54,4 @@
5454
"lowcode",
5555
"flow"
5656
]
57-
}
57+
}

designer/src/behaviors/click-behavior-resolver.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ export class ClickBehaviorResolver {
2424

2525
switch (result.action.type) {
2626
case ClickBehaviorType.selectStep: {
27-
const isDragDisabled = forceDisableDrag || this.state.isDragDisabled;
27+
const isDragDisabled =
28+
forceDisableDrag ||
29+
this.state.isDragDisabled ||
30+
!this.designerContext.definitionModifier.isDraggable(result.component.step, result.component.parentSequence);
2831
return SelectStepBehavior.create(result.component, isDragDisabled, this.designerContext);
2932
}
3033

designer/src/behaviors/drag-step-behavior-view.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ describe('DragStepView', () => {
77

88
const step = createStepStub();
99
const configuration = createDesignerConfigurationStub();
10-
const context = createComponentContextStub();
10+
const componentContext = createComponentContextStub();
1111

12-
const component = DragStepView.create(step, configuration, context);
12+
const component = DragStepView.create(step, configuration, componentContext);
1313

1414
expect(component).toBeDefined();
1515
expect(appendChildSpy).toHaveBeenCalled();

designer/src/behaviors/drag-step-behavior-view.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { Dom } from '../core/dom';
22
import { Vector } from '../core/vector';
3-
import { Sequence, Step } from '../definition';
3+
import { Step } from '../definition';
44
import { DesignerConfiguration } from '../designer-configuration';
5-
import { ComponentContext } from '../workspace/component-context';
5+
import { ComponentContext } from '../component-context';
6+
import { StepContext } from '../designer-extension';
67

78
const SAFE_OFFSET = 10;
89

910
export class DragStepView {
10-
public static create(step: Step, configuration: DesignerConfiguration, context: ComponentContext): DragStepView {
11+
public static create(step: Step, configuration: DesignerConfiguration, componentContext: ComponentContext): DragStepView {
1112
const theme = configuration.theme || 'light';
1213
const layer = Dom.element('div', {
1314
class: `sqd-drag sqd-theme-${theme}`
@@ -17,8 +18,15 @@ export class DragStepView {
1718
const canvas = Dom.svg('svg');
1819
layer.appendChild(canvas);
1920

20-
const fakeSequence: Sequence = [];
21-
const stepComponent = context.stepComponentFactory.create(canvas, step, fakeSequence, context);
21+
const fakeStepContext: StepContext = {
22+
parentSequence: [],
23+
step,
24+
depth: 0,
25+
position: 0,
26+
isInputConnected: true,
27+
isOutputConnected: true
28+
};
29+
const stepComponent = componentContext.stepComponentFactory.create(canvas, fakeStepContext, componentContext);
2230

2331
Dom.attrs(canvas, {
2432
width: stepComponent.view.width + SAFE_OFFSET * 2,

designer/src/component-context.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { StepsConfiguration } from './designer-configuration';
2+
import { PlaceholderController } from './designer-extension';
3+
import { Services } from './services';
4+
import { StepComponentFactory } from './workspace/step-component-factory';
5+
import { StepExtensionResolver } from './workspace/step-extension-resolver';
6+
7+
export class ComponentContext {
8+
public static create(
9+
configuration: StepsConfiguration,
10+
stepExtensionResolver: StepExtensionResolver,
11+
services: Services
12+
): ComponentContext {
13+
const placeholderController = services.placeholderController.create();
14+
const stepComponentFactory = new StepComponentFactory(stepExtensionResolver);
15+
return new ComponentContext(configuration, placeholderController, stepComponentFactory, services);
16+
}
17+
18+
private constructor(
19+
public readonly configuration: StepsConfiguration,
20+
public readonly placeholderController: PlaceholderController,
21+
public readonly stepComponentFactory: StepComponentFactory,
22+
public readonly services: Services
23+
) {}
24+
}

designer/src/control-bar/control-bar.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ export class ControlBar implements UiComponent {
104104
}
105105

106106
private refreshDeleteButtonVisibility() {
107-
const isHidden = !this.state.selectedStepId || this.state.isReadonly;
107+
const isHidden =
108+
!this.state.selectedStepId || this.state.isReadonly || !this.definitionModifier.isDeletable(this.state.selectedStepId);
108109
this.view.setIsDeleteButtonHidden(isHidden);
109110
}
110111
}

designer/src/definition-modifier.ts

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ export class DefinitionModifier {
1111
private readonly configuration: DesignerConfiguration
1212
) {}
1313

14+
public isDeletable(stepId: string): boolean {
15+
if (this.configuration.steps.isDeletable) {
16+
const result = this.stepsTraverser.getParentSequence(this.state.definition, stepId);
17+
return this.configuration.steps.isDeletable(result.step, result.parentSequence);
18+
}
19+
return true;
20+
}
21+
1422
public tryDelete(stepId: string): boolean {
1523
const result = this.stepsTraverser.getParentSequence(this.state.definition, stepId);
1624

@@ -42,6 +50,10 @@ export class DefinitionModifier {
4250
return true;
4351
}
4452

53+
public isDraggable(step: Step, parentSequence: Sequence): boolean {
54+
return this.configuration.steps.isDraggable ? this.configuration.steps.isDraggable(step, parentSequence) : true;
55+
}
56+
4557
public tryMove(sourceSequence: Sequence, step: Step, targetSequence: Sequence, targetIndex: number): boolean {
4658
const canMoveStep = this.configuration.steps.canMoveStep
4759
? this.configuration.steps.canMoveStep(sourceSequence, step, targetSequence, targetIndex)

designer/src/designer-configuration.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ export interface ToolboxGroupConfiguration {
2727

2828
export interface StepsConfiguration {
2929
canInsertStep?: (step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
30+
isDraggable?: (step: Step, parentSequence: Sequence) => boolean;
3031
canMoveStep?: (sourceSequence: Sequence, step: Step, targetSequence: Sequence, targetIndex: number) => boolean;
32+
isDeletable?: (step: Step, parentSequence: Sequence) => boolean;
3133
canDeleteStep?: (step: Step, parentSequence: Sequence) => boolean;
3234

3335
iconUrlProvider?: StepIconUrlProvider;
@@ -36,7 +38,7 @@ export interface StepsConfiguration {
3638

3739
export type StepIconUrlProvider = (componentType: ComponentType, type: string) => string | null;
3840

39-
export type StepValidator = (step: Step) => boolean;
41+
export type StepValidator = (step: Step, parentSequence: Sequence) => boolean;
4042

4143
export interface EditorsConfiguration {
4244
isHidden?: boolean;

designer/src/designer-context.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BehaviorController } from './behaviors/behavior-controller';
2+
import { ComponentContext } from './component-context';
23
import { ObjectCloner } from './core/object-cloner';
34
import { StepsTraverser } from './core/steps-traverser';
45
import { Definition } from './definition';
@@ -8,7 +9,6 @@ import { DesignerState } from './designer-state';
89
import { HistoryController } from './history-controller';
910
import { LayoutController } from './layout-controller';
1011
import { Services } from './services';
11-
import { ComponentContext } from './workspace';
1212
import { StepExtensionResolver } from './workspace/step-extension-resolver';
1313
import { WorkspaceController, WorkspaceControllerWrapper } from './workspace/workspace-controller';
1414

@@ -37,7 +37,7 @@ export class DesignerContext {
3737
historyController = HistoryController.create(state, definitionModifier, configuration);
3838
}
3939

40-
const componentContext = ComponentContext.create(configuration.steps, stepExtensionResolver);
40+
const componentContext = ComponentContext.create(configuration.steps, stepExtensionResolver, services);
4141

4242
return new DesignerContext(
4343
state,

designer/src/designer-extension.ts

+40-2
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
1+
import { ComponentContext } from './component-context';
12
import { Vector } from './core';
23
import { Branches, ComponentType, Sequence, Step } from './definition';
34
import { DesignerContext } from './designer-context';
4-
import { ComponentContext, StepComponent } from './workspace';
5+
import { StepComponent, Component } from './workspace';
56

67
export interface DesignerExtension {
78
steps?: StepExtension[];
89
uiComponents?: UiComponentExtension[];
910
wheelController?: WheelControllerExtension;
11+
placeholderController?: PlaceholderControllerExtension;
12+
rootComponent?: RootComponentExtension;
1013
}
1114

1215
// StepExtension
1316

1417
export interface StepExtension<S extends Step = Step> {
1518
componentType: ComponentType;
16-
createComponent(parentElement: SVGElement, step: S, parentSequence: Sequence, componentContext: ComponentContext): StepComponent;
19+
createComponent(parentElement: SVGElement, stepContext: StepContext<S>, componentContext: ComponentContext): StepComponent;
1720
getChildren(step: S): StepChildren | null;
1821
}
1922

23+
export interface StepContext<S extends Step = Step> {
24+
parentSequence: Sequence;
25+
step: S;
26+
depth: number;
27+
position: number;
28+
isInputConnected: boolean;
29+
isOutputConnected: boolean;
30+
}
31+
2032
export interface StepChildren {
2133
type: StepChildrenType;
2234
sequences: Sequence | Branches;
@@ -51,3 +63,29 @@ export interface UiComponentExtension {
5163
export interface UiComponent {
5264
destroy(): void;
5365
}
66+
67+
// RootComponentExtension
68+
69+
export interface RootComponentExtension {
70+
create(
71+
parentElement: SVGElement,
72+
sequence: Sequence,
73+
parentSequencePlaceIndicator: SequencePlaceIndicator | null,
74+
context: ComponentContext
75+
): Component;
76+
}
77+
78+
export interface SequencePlaceIndicator {
79+
sequence: Sequence;
80+
index: number;
81+
}
82+
83+
// PlaceholderController
84+
85+
export interface PlaceholderControllerExtension {
86+
create(): PlaceholderController;
87+
}
88+
89+
export interface PlaceholderController {
90+
canCreate(sequence: Sequence, index: number): boolean;
91+
}

designer/src/designer.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ export class Designer {
164164

165165
e.preventDefault();
166166
e.stopPropagation();
167-
this.definitionModifier.tryDelete(this.state.selectedStepId);
167+
168+
const isDeletable = this.definitionModifier.isDeletable(this.state.selectedStepId);
169+
if (isDeletable) {
170+
this.definitionModifier.tryDelete(this.state.selectedStepId);
171+
}
168172
}
169173
}

designer/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './core';
2+
export * from './component-context';
23
export * from './workspace';
34
export * from './definition';
45
export * from './designer-configuration';

0 commit comments

Comments
 (0)