Skip to content

Commit c4940c6

Browse files
authored
0.9.0. (#19)
* 0.9.0.
1 parent 160adc9 commit c4940c6

37 files changed

+301
-68
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.9.0
2+
3+
* Improved validation for the `boolean` value model.
4+
* Improved validation for the `branches` value model.
5+
* Internal changes preparing for the upcoming pro version.
6+
17
## 0.8.0
28

39
Updated the `sequential-workflow-model` dependency to the version `0.2.0`.

demos/webpack-app/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"dependencies": {
1717
"xstate": "^4.38.2",
1818
"sequential-workflow-model": "^0.2.0",
19-
"sequential-workflow-designer": "^0.14.1",
19+
"sequential-workflow-designer": "^0.16.0",
2020
"sequential-workflow-machine": "^0.4.0",
21-
"sequential-workflow-editor-model": "^0.8.0",
22-
"sequential-workflow-editor": "^0.8.0"
21+
"sequential-workflow-editor-model": "^0.9.0",
22+
"sequential-workflow-editor": "^0.9.0"
2323
},
2424
"devDependencies": {
2525
"ts-loader": "^9.4.2",

editor/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sequential-workflow-editor",
3-
"version": "0.8.0",
3+
"version": "0.9.0",
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.8.0",
49+
"sequential-workflow-editor-model": "^0.9.0",
5050
"sequential-workflow-model": "^0.2.0"
5151
},
5252
"peerDependencies": {
53-
"sequential-workflow-editor-model": "^0.8.0",
53+
"sequential-workflow-editor-model": "^0.9.0",
5454
"sequential-workflow-model": "^0.2.0"
5555
},
5656
"devDependencies": {
@@ -79,4 +79,4 @@
7979
"lowcode",
8080
"flow"
8181
]
82-
}
82+
}

editor/src/components/dynamic-list-component.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ export interface DynamicListComponent<TItem> extends Component {
88
add(item: TItem): void;
99
}
1010

11-
export interface DynamicListComponentConfiguration {
11+
export interface DynamicListComponentConfiguration<TItem> {
1212
emptyMessage?: string;
13+
canDelete?: (item: TItem) => string | null;
1314
}
1415

1516
export interface DynamicListItemComponent<TItem> extends Component {
@@ -22,7 +23,7 @@ export function dynamicListComponent<TItem>(
2223
initialItems: TItem[],
2324
itemComponentFactory: (item: TItem) => DynamicListItemComponent<TItem>,
2425
context: ValueContext,
25-
configuration?: DynamicListComponentConfiguration
26+
configuration?: DynamicListComponentConfiguration<TItem>
2627
): DynamicListComponent<TItem> {
2728
const onChanged = new SimpleEvent<TItem[]>();
2829
const items = [...initialItems];
@@ -38,6 +39,14 @@ export function dynamicListComponent<TItem>(
3839
}
3940

4041
function onItemDeleted(index: number) {
42+
if (configuration && configuration.canDelete) {
43+
const error = configuration.canDelete(items[index]);
44+
if (error) {
45+
window.alert(error);
46+
return;
47+
}
48+
}
49+
4150
items.splice(index, 1);
4251
forward();
4352
reloadList();

editor/src/components/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export * from './button-component';
2+
export * from './component';
3+
export * from './dynamic-list-component';
4+
export * from './input-component';
5+
export * from './prepended-input-component';
6+
export * from './row-component';
7+
export * from './select-component';
8+
export * from './textarea-component';
9+
export * from './validation-error-component';
10+
export * from './value-editor-container-component';

editor/src/core/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1+
export * from './append-multiline-text';
2+
export * from './filter-value-types';
3+
export * from './filter-value-types';
14
export * from './html';
5+
export * from './icons';
6+
export * from './stacked-simple-event';
27
export * from './variable-name-formatter';

editor/src/editor-extension.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ValueEditorFactory } from './value-editors';
2+
3+
export interface EditorExtension {
4+
valueEditors?: ValueEditorExtension[];
5+
}
6+
7+
export interface ValueEditorExtension {
8+
editorId: string;
9+
factory: ValueEditorFactory;
10+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { UidGenerator } from 'sequential-workflow-editor-model';
22
import { DefinitionWalker } from 'sequential-workflow-model';
3+
import { EditorExtension } from './editor-extension';
34

45
export interface EditorProviderConfiguration {
56
uidGenerator: UidGenerator;
67
definitionWalker?: DefinitionWalker;
78
isHeaderHidden?: boolean;
9+
extensions?: EditorExtension[];
810
}

editor/src/editor-provider.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
Path,
99
StepValidatorContext
1010
} from 'sequential-workflow-editor-model';
11-
import { EditorServices, ValueEditorEditorFactoryResolver } from './value-editors';
11+
import { EditorServices, ValueEditorFactoryResolver } from './value-editors';
1212
import {
1313
GlobalEditorContext,
1414
RootEditorProvider,
@@ -30,19 +30,21 @@ export class EditorProvider<TDefinition extends Definition> {
3030
const definitionWalker = configuration.definitionWalker ?? new DefinitionWalker();
3131
const activator = ModelActivator.create(definitionModel, configuration.uidGenerator);
3232
const validator = DefinitionValidator.create(definitionModel, definitionWalker);
33-
return new EditorProvider(activator, validator, definitionModel, definitionWalker, configuration);
33+
const valueEditorFactoryResolver = ValueEditorFactoryResolver.create(configuration.extensions);
34+
return new EditorProvider(activator, validator, definitionModel, definitionWalker, valueEditorFactoryResolver, configuration);
3435
}
3536

3637
private readonly services: EditorServices = {
3738
activator: this.activator,
38-
valueEditorFactoryResolver: ValueEditorEditorFactoryResolver.resolve
39+
valueEditorFactoryResolver: this.valueEditorFactoryResolver
3940
};
4041

4142
private constructor(
4243
private readonly activator: ModelActivator<TDefinition>,
4344
private readonly validator: DefinitionValidator,
4445
private readonly definitionModel: DefinitionModel,
4546
private readonly definitionWalker: DefinitionWalker,
47+
private readonly valueEditorFactoryResolver: ValueEditorFactoryResolver,
4648
private readonly configuration: EditorProviderConfiguration
4749
) {}
4850

@@ -82,11 +84,17 @@ export class EditorProvider<TDefinition extends Definition> {
8284
const editor = Editor.create(headerData, validator, propertyModels, definitionContext, this.services, typeClassName);
8385

8486
editor.onValuesChanged.subscribe((paths: Path[]) => {
85-
if (paths.some(path => path.equals(stepModel.name.value.path))) {
87+
const isNameChanged = paths.some(path => path.equals(stepModel.name.value.path));
88+
if (isNameChanged) {
8689
context.notifyNameChanged();
87-
} else {
88-
context.notifyPropertiesChanged();
90+
return;
8991
}
92+
const areBranchesChanged = paths.some(path => path.equals('branches'));
93+
if (areBranchesChanged) {
94+
context.notifyChildrenChanged();
95+
return;
96+
}
97+
context.notifyPropertiesChanged();
9098
});
9199
return editor.root;
92100
};

editor/src/editor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DefinitionContext, Path, PropertyModel, PropertyModels } from 'sequential-workflow-editor-model';
22
import { PropertyEditor } from './property-editor/property-editor';
3-
import { EditorServices, ValueEditorEditorFactoryResolver } from './value-editors';
3+
import { EditorServices } from './value-editors';
44
import { EditorHeader, EditorHeaderData } from './editor-header';
55
import { StackedSimpleEvent } from './core/stacked-simple-event';
66
import { ValidationErrorComponent, validationErrorComponent } from './components/validation-error-component';
@@ -32,7 +32,7 @@ export class Editor {
3232

3333
const editors = new Map<PropertyModel, PropertyEditor>();
3434
for (const propertyModel of propertyModels) {
35-
if (ValueEditorEditorFactoryResolver.isHidden(propertyModel.value.id)) {
35+
if (editorServices.valueEditorFactoryResolver.isHidden(propertyModel.value.id, propertyModel.value.editorId)) {
3636
continue;
3737
}
3838

editor/src/external-types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Definition, Step } from 'sequential-workflow-model';
33
export interface StepEditorContext {
44
notifyNameChanged(): void;
55
notifyPropertiesChanged(): void;
6+
notifyChildrenChanged(): void;
67
}
78

89
export interface GlobalEditorContext {

editor/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
export * from './components';
12
export * from './core';
23
export * from './value-editors';
4+
export * from './editor-extension';
35
export * from './editor-provider-configuration';
46
export * from './editor-provider';

editor/src/property-editor/property-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class PropertyEditor implements Component {
2020
editorServices: EditorServices
2121
): PropertyEditor {
2222
const valueContext = ValueContext.create(propertyModel.value, propertyModel, definitionContext);
23-
const valueEditorFactory = editorServices.valueEditorFactoryResolver(propertyModel.value.id);
23+
const valueEditorFactory = editorServices.valueEditorFactoryResolver.resolve(propertyModel.value.id, propertyModel.value.editorId);
2424
const valueEditor = valueEditorFactory(valueContext, editorServices);
2525
let hint: PropertyHintComponent | null = null;
2626

editor/src/value-editors/dynamic/dynamic-value-editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function dynamicValueEditor(context: ValueContext<DynamicValueModel>, ser
3030
}
3131

3232
const childContext = context.createChildContext(model);
33-
editor = services.valueEditorFactoryResolver(model.id)(childContext, services);
33+
editor = services.valueEditorFactoryResolver.resolve(model.id, model.editorId)(childContext, services);
3434
placeholder.appendChild(editor.view);
3535
}
3636

editor/src/value-editors/value-editor-factory-resolver.ts

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,55 @@ import { nullableAnyVariableValueEditor, nullableAnyVariableValueEditorId } from
1515
import { booleanValueEditor, booleanValueEditorId } from './boolean/boolean-value-editor';
1616
import { generatedStringValueEditor, generatedStringValueEditorId } from './generated-string/generated-string-value-editor';
1717
import { stringDictionaryValueEditor } from './string-dictionary/string-dictionary-value-editor';
18+
import { EditorExtension } from '../editor-extension';
1819

19-
const editors: { id: string; factory: ValueEditorFactory | null }[] = [
20-
{ id: anyVariablesValueEditorId, factory: anyVariablesValueEditor as ValueEditorFactory },
21-
{ id: booleanValueEditorId, factory: booleanValueEditor as ValueEditorFactory },
22-
{ id: choiceValueEditorId, factory: choiceValueEditor as ValueEditorFactory },
23-
{ id: nullableAnyVariableValueEditorId, factory: nullableAnyVariableValueEditor as ValueEditorFactory },
24-
{ id: dynamicValueEditorId, factory: dynamicValueEditor as ValueEditorFactory },
25-
{ id: generatedStringValueEditorId, factory: generatedStringValueEditor as ValueEditorFactory },
26-
{ id: nullableVariableValueEditorId, factory: nullableVariableValueEditor as ValueEditorFactory },
27-
{ id: nullableVariableDefinitionValueEditorId, factory: nullableVariableDefinitionValueEditor as ValueEditorFactory },
28-
{ id: stringValueEditorId, factory: stringValueEditor as ValueEditorFactory },
29-
{ id: stringDictionaryValueModelId, factory: stringDictionaryValueEditor as ValueEditorFactory },
30-
{ id: numberValueEditorId, factory: numberValueEditor as ValueEditorFactory },
31-
{ id: variableDefinitionsValueEditorId, factory: variableDefinitionsValueEditor as ValueEditorFactory },
32-
{ id: sequenceValueModelId, factory: null },
33-
{ id: branchesValueModelId, factory: null }
34-
];
20+
const defaultMap: ValueEditorMap = {
21+
[anyVariablesValueEditorId]: anyVariablesValueEditor as ValueEditorFactory,
22+
[booleanValueEditorId]: booleanValueEditor as ValueEditorFactory,
23+
[choiceValueEditorId]: choiceValueEditor as ValueEditorFactory,
24+
[nullableAnyVariableValueEditorId]: nullableAnyVariableValueEditor as ValueEditorFactory,
25+
[dynamicValueEditorId]: dynamicValueEditor as ValueEditorFactory,
26+
[generatedStringValueEditorId]: generatedStringValueEditor as ValueEditorFactory,
27+
[nullableVariableValueEditorId]: nullableVariableValueEditor as ValueEditorFactory,
28+
[nullableVariableDefinitionValueEditorId]: nullableVariableDefinitionValueEditor as ValueEditorFactory,
29+
[stringValueEditorId]: stringValueEditor as ValueEditorFactory,
30+
[stringDictionaryValueModelId]: stringDictionaryValueEditor as ValueEditorFactory,
31+
[numberValueEditorId]: numberValueEditor as ValueEditorFactory,
32+
[variableDefinitionsValueEditorId]: variableDefinitionsValueEditor as ValueEditorFactory,
33+
[sequenceValueModelId]: null,
34+
[branchesValueModelId]: null
35+
};
3536

36-
export class ValueEditorEditorFactoryResolver {
37-
public static resolve(valueModelId: string): ValueEditorFactory {
38-
const editor = editors.find(editor => editor.id === valueModelId);
39-
if (!editor || !editor.factory) {
40-
throw new Error(`Value model id: ${valueModelId} is not supported`);
37+
type ValueEditorMap = Record<string, ValueEditorFactory | null>;
38+
39+
export class ValueEditorFactoryResolver {
40+
public static create(extensions?: EditorExtension[]): ValueEditorFactoryResolver {
41+
let map: ValueEditorMap;
42+
if (extensions) {
43+
map = { ...defaultMap };
44+
extensions.forEach(extension => {
45+
if (extension.valueEditors) {
46+
extension.valueEditors.forEach(e => (map[e.editorId] = e.factory));
47+
}
48+
});
49+
} else {
50+
map = defaultMap;
51+
}
52+
return new ValueEditorFactoryResolver(map);
53+
}
54+
55+
private constructor(private readonly map: ValueEditorMap) {}
56+
57+
public resolve(valueModelId: string, editorId: string | undefined): ValueEditorFactory {
58+
const id = editorId ?? valueModelId;
59+
const editor = this.map[id];
60+
if (!editor) {
61+
throw new Error(`Editor id ${id} is not supported`);
4162
}
42-
return editor.factory;
63+
return editor;
4364
}
4465

45-
public static isHidden(valueModelId: string): boolean {
46-
const editor = editors.find(editor => editor.id === valueModelId);
47-
return editor ? editor.factory === null : false;
66+
public isHidden(valueModelId: string, editorId: string | undefined): boolean {
67+
return !this.map[editorId ?? valueModelId];
4868
}
4969
}

editor/src/value-editors/value-editor.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ModelActivator, ValueModel, ValueContext } from 'sequential-workflow-editor-model';
2+
import { ValueEditorFactoryResolver } from './value-editor-factory-resolver';
23
import { Component } from '../components/component';
34

45
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -12,8 +13,6 @@ export type ValueEditorFactory<TValueModel extends ValueModel = ValueModel> = (
1213
services: EditorServices
1314
) => ValueEditor<TValueModel>;
1415

15-
export type ValueEditorFactoryResolver = (valueModelId: string) => ValueEditorFactory;
16-
1716
export interface EditorServices {
1817
valueEditorFactoryResolver: ValueEditorFactoryResolver;
1918
activator: ModelActivator;

model/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sequential-workflow-editor-model",
3-
"version": "0.8.0",
3+
"version": "0.9.0",
44
"homepage": "https://nocode-js.com/",
55
"author": {
66
"name": "NoCode JS",

model/src/context/value-context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ export class ValueContext<TValueModel extends ValueModel = ValueModel, TProperti
3131
this.onValueChanged.forward(this.model.path);
3232
}
3333

34-
public validate(): ValidationResult {
34+
public readonly validate = (): ValidationResult => {
3535
return this.model.validate(this);
36-
}
36+
};
3737

3838
public readonly getPropertyValue = <Key extends keyof TProperties>(name: Key): TProperties[Key] => {
3939
return readPropertyValue(name, this.propertyModel, this.definitionContext.object);

model/src/context/variables-provider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class ParentsProvider {
3737

3838
if (this.step) {
3939
const parents = this.definitionWalker.getParents(this.definition, this.step);
40-
const count = parents.length - 1; // skips variable definitions from itself
40+
const count = parents.length;
4141
for (let index = 0; index < count; index++) {
4242
const parent = parents[index];
4343
if (typeof parent === 'string') {
@@ -81,10 +81,10 @@ export class ParentsProvider {
8181
}
8282
}
8383

84-
public readonly getStepTypes = (): string[] => {
84+
public readonly getParentStepTypes = (): string[] => {
8585
if (this.step) {
8686
const parents = this.definitionWalker.getParents(this.definition, this.step);
87-
return (parents.filter(p => typeof p === 'object') as Step[]).map(p => p.type);
87+
return (parents.slice(0, parents.length - 1).filter(p => typeof p === 'object') as Step[]).map(p => p.type);
8888
}
8989
return [];
9090
};

model/src/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface ValueModel<
6464
TProperties extends Properties = Properties
6565
> {
6666
id: ValueModelId;
67+
editorId?: string;
6768
path: Path;
6869
label: string;
6970
configuration: TConfiguration;

model/src/test-tools/value-context-stub.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { ValueContext } from '../context';
22
import { ValueModel } from '../model';
33

4-
export function createValueContextStub<TValueModel extends ValueModel>(value: unknown, configuration: object): ValueContext<TValueModel> {
4+
export function createValueContextStub<TValueModel extends ValueModel>(
5+
value: unknown,
6+
configuration: TValueModel['configuration']
7+
): ValueContext<TValueModel> {
58
return {
69
getValue: () => value,
710
model: {

model/src/validator/step-validator-context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ export class StepValidatorContext {
1212
* @returns The parent step types.
1313
* @example `['loop', 'if']`
1414
*/
15-
public readonly getParentStepTypes = this.parentsProvider.getStepTypes;
15+
public readonly getParentStepTypes = this.parentsProvider.getParentStepTypes;
1616
}

0 commit comments

Comments
 (0)