Skip to content

Commit

Permalink
0.13.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
b4rtaz committed Jun 21, 2024
1 parent 320f0a4 commit ec7efee
Show file tree
Hide file tree
Showing 22 changed files with 181 additions and 59 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.13.0

This version introduces several internal changes that allowed for the creation of a new type of editor in the pro version: the hidden dependent value editor.

## 0.12.1

This version normalizes translations.
Expand Down
6 changes: 3 additions & 3 deletions demos/vanilla-js-app/vanilla-js.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
}
</style>

<link href="https://cdn.jsdelivr.net/npm/[email protected].1/css/designer.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/[email protected].1/css/designer-light.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected].1/dist/index.umd.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected].2/css/designer.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/[email protected].2/css/designer-light.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected].2/dist/index.umd.js"></script>

<script src="./assets/lib.js"></script>
<script src="./assets/vanilla-js.js"></script>
Expand Down
4 changes: 2 additions & 2 deletions demos/webpack-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"dependencies": {
"xstate": "^4.38.2",
"sequential-workflow-model": "^0.2.0",
"sequential-workflow-designer": "^0.21.1",
"sequential-workflow-designer": "^0.21.2",
"sequential-workflow-machine": "^0.4.0",
"sequential-workflow-editor-model": "^0.12.1",
"sequential-workflow-editor": "^0.12.1"
Expand All @@ -33,4 +33,4 @@
"@typescript-eslint/parser": "^5.47.0",
"eslint": "^8.30.0"
}
}
}
3 changes: 2 additions & 1 deletion demos/webpack-app/src/editors/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export class App {
rootEditorProvider: () => {
const editor = document.createElement('div');
editor.innerHTML =
'This demo showcases all the supported editors by the Sequential Workflow Editor. <a href="https://github.com/nocode-js/sequential-workflow-editor">GitHub</a>';
'This demo showcases all the supported editors by the <a href="https://github.com/nocode-js/sequential-workflow-editor">Sequential Workflow Editor</a>.<br /><br />' +
'Start exploring by clicking on each step.';
return editor;
},
stepEditorProvider: editorProvider.createStepEditorProvider()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface AnyVariablesStepModel extends Step {
}

export const anyVariablesStepModel = createStepModel<AnyVariablesStepModel>('anyVariables', 'task', step => {
step.description('In this step, you can select a collection of variables of any type.');

step.property('zeroConfig').value(createAnyVariablesValueModel({}));
step.property('onlyBoolean').value(
createAnyVariablesValueModel({
Expand Down
2 changes: 2 additions & 0 deletions demos/webpack-app/src/editors/model/boolean-step-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export interface BooleanStepModel extends Step {
}

export const booleanStepModel = createStepModel<BooleanStepModel>('boolean', 'task', step => {
step.description('This step demonstrates properties with boolean values.');

step.property('zeroConfig').value(createBooleanValueModel({}));
step.property('defaultValueTrue').value(
createBooleanValueModel({
Expand Down
2 changes: 2 additions & 0 deletions demos/webpack-app/src/editors/model/choice-step-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface ChoiceStepModel extends Step {
}

export const choiceStepModel = createStepModel<ChoiceStepModel>('choice', 'task', step => {
step.description('In this step, you can see properties that allow you to select a value from a predefined list.');

step.property('minimalConfig').value(createChoiceValueModel({ choices: ['red', 'blue', 'green'] }));

step.property('defaultValueAllow').value(
Expand Down
4 changes: 4 additions & 0 deletions demos/webpack-app/src/editors/model/dynamic-step-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface DynamicStepModel extends Step {
}

export const dynamicStepModel = createStepModel<DynamicStepModel>('dynamic', 'task', step => {
step.description(
'This step has properties with dynamic values. For each property, you can change the value type by selecting the desired type.'
);

step.property('example').value(
createDynamicValueModel({
models: [createStringValueModel({}), createBooleanValueModel({})]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export interface GeneratedStringStepModel extends Step {
}

export const generatedStringStepModel = createStepModel<GeneratedStringStepModel>('generatedString', 'task', step => {
step.description(
'This step has a property whose value is generated using data from another property. To see how it works, please change the value of the "X" property to 0, 1, 2, etc.'
);

step.property('x').value(createNumberValueModel({}));

step.property('example')
Expand Down
3 changes: 3 additions & 0 deletions editor/css/editor.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
.swe-editor > .swe-validation-error {
margin: 0 10px;
}
.swe-hidden {
display: none;
}

/* properties */

Expand Down
4 changes: 3 additions & 1 deletion editor/src/components/property-validation-error-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { validationErrorComponent } from './validation-error-component';

export interface PropertyValidationErrorComponent extends Component {
validate(): void;
isHidden(): boolean;
}

export function propertyValidationErrorComponent(
Expand All @@ -21,6 +22,7 @@ export function propertyValidationErrorComponent(

return {
view: validation.view,
validate
validate,
isHidden: validation.isHidden
};
}
38 changes: 38 additions & 0 deletions editor/src/components/validation-error-component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { validationErrorComponent } from './validation-error-component';

describe('ValidationErrorComponent', () => {
it('returns correct value for isHidden() and emits changes', () => {
let emitted: boolean | null = null;
const component = validationErrorComponent();
component.onIsHiddenChanged.subscribe(v => (emitted = v));

// test 1
expect(component.isHidden()).toBe(true);
expect(component.view.children.length).toBe(0);
expect(emitted).toBeNull();

// test 2
emitted = null;
component.setDefaultError({ $: 'Expected 2 characters' });

expect(component.isHidden()).toBe(false);
expect(component.view.children.length).toBeGreaterThan(0);
expect(emitted).toBe(false);

// test 3
emitted = null;
component.setDefaultError({ $: 'Expected 3 characters' });

expect(component.isHidden()).toBe(false);
expect(component.view.children.length).toBeGreaterThan(0);
expect(emitted).toBeNull(); // Visibility did not change

// test 4
emitted = null;
component.setDefaultError(null);

expect(component.isHidden()).toBe(true);
expect(component.view.children.length).toBe(0);
expect(emitted).toBe(true);
});
});
18 changes: 17 additions & 1 deletion editor/src/components/validation-error-component.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ValidationResult } from 'sequential-workflow-editor-model';
import { SimpleEvent, ValidationResult } from 'sequential-workflow-editor-model';
import { Component } from './component';
import { Html } from '../core/html';

export interface ValidationErrorComponent extends Component {
onIsHiddenChanged: SimpleEvent<boolean>;
isHidden(): boolean;
setError(error: string | null): void;
setDefaultError(result: ValidationResult): void;
}
Expand All @@ -11,9 +13,16 @@ export function validationErrorComponent(): ValidationErrorComponent {
const view = Html.element('div', {
class: 'swe-validation-error'
});
const onIsHiddenChanged = new SimpleEvent<boolean>();
let child: HTMLElement | null = null;

function isHidden() {
return child === null;
}

function setError(error: string | null) {
const oldState = isHidden();

if (child) {
view.removeChild(child);
child = null;
Expand All @@ -25,14 +34,21 @@ export function validationErrorComponent(): ValidationErrorComponent {
child.textContent = error;
view.appendChild(child);
}

const newState = isHidden();
if (oldState !== newState) {
onIsHiddenChanged.forward(newState);
}
}

function setDefaultError(result: ValidationResult) {
setError(result && result['$']);
}

return {
onIsHiddenChanged,
view,
isHidden,
setError,
setDefaultError
};
Expand Down
12 changes: 12 additions & 0 deletions editor/src/core/html.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,16 @@ describe('Html', () => {

expect(element.getAttribute('data-test')).toBe('555');
});

it('toggles class', () => {
const element = document.createElement('div');

Html.toggleClass(element, true, 'foo');

expect(element.classList.contains('foo')).toBe(true);

Html.toggleClass(element, false, 'foo');

expect(element.classList.contains('foo')).toBe(false);
});
});
8 changes: 8 additions & 0 deletions editor/src/core/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,12 @@ export class Html {
}
return element;
}

public static toggleClass(element: Element, isEnabled: boolean, className: string) {
if (isEnabled) {
element.classList.add(className);
} else {
element.classList.remove(className);
}
}
}
4 changes: 0 additions & 4 deletions editor/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ export class Editor {

const editors = new Map<PropertyModel, PropertyEditor>();
for (const propertyModel of propertyModels) {
if (editorServices.valueEditorFactoryResolver.isHidden(propertyModel.value.id, propertyModel.value.editorId)) {
continue;
}

const propertyEditor = PropertyEditor.create(propertyModel, stepType, definitionContext, editorServices);
root.appendChild(propertyEditor.view);
editors.set(propertyModel, propertyEditor);
Expand Down
61 changes: 47 additions & 14 deletions editor/src/property-editor/property-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Component } from '../components/component';
import { PropertyValidationErrorComponent, propertyValidationErrorComponent } from '../components/property-validation-error-component';
import { Icons } from '../core/icons';
import { PropertyHintComponent, propertyHint } from './property-hint';
import { StackedSimpleEvent } from '../core';

export class PropertyEditor implements Component {
public static create(
Expand All @@ -31,17 +32,21 @@ export class PropertyEditor implements Component {
let hint: PropertyHintComponent | null = null;

const nameClassName = propertyModel.path.last();
const pathStr = propertyModel.path.toString();

const view = Html.element('div', {
class: `swe-property swe-name-${nameClassName}`
});
view.setAttribute('data-path', pathStr);

const header = Html.element('div', {
class: 'swe-property-header'
});
const label = Html.element('h4', {
class: 'swe-property-header-label'
});
const i18nPrefix = stepType ? `step.${stepType}.property:` : 'root.property:';
label.innerText = editorServices.i18n(i18nPrefix + propertyModel.path.toString(), propertyModel.label);
label.innerText = editorServices.i18n(i18nPrefix + pathStr, propertyModel.label);

header.appendChild(label);
view.appendChild(header);
Expand All @@ -61,15 +66,16 @@ export class PropertyEditor implements Component {

view.appendChild(valueEditor.view);

let control: HTMLElement | null = null;
if (valueEditor.controlView) {
const control = Html.element('div', {
control = Html.element('div', {
class: 'swe-property-header-control'
});
control.appendChild(valueEditor.controlView);
header.appendChild(control);
}

let validationError: PropertyValidationErrorComponent | null = null;
let propertyValidationError: PropertyValidationErrorComponent | null = null;
if (propertyModel.validator) {
const valueContext = ValueContext.createFromDefinitionContext(
propertyModel.value,
Expand All @@ -78,38 +84,65 @@ export class PropertyEditor implements Component {
editorServices.i18n
);
const validatorContext = PropertyValidatorContext.create(valueContext);
validationError = propertyValidationErrorComponent(propertyModel.validator, validatorContext);
view.appendChild(validationError.view);
propertyValidationError = propertyValidationErrorComponent(propertyModel.validator, validatorContext);
view.appendChild(propertyValidationError.view);
}

const editor = new PropertyEditor(view, valueContext.onValueChanged, valueEditor, validationError);
if (propertyModel.validator) {
const editor = new PropertyEditor(view, valueContext.onValueChanged, valueEditor, control, propertyValidationError);
if (propertyValidationError) {
valueContext.onValueChanged.subscribe(editor.onValueChangedHandler);
}
if (valueEditor.onIsHiddenChanged) {
valueEditor.onIsHiddenChanged.subscribe(editor.onEditorIsHiddenChanged);
}
editor.reloadVisibility();
return editor;
}

private readonly onReloadVisibilityRequested = new StackedSimpleEvent<void>();

public constructor(
public readonly view: HTMLElement,
public readonly onValueChanged: SimpleEvent<Path>,
private readonly valueEditor: ValueEditor,
private readonly validationError: PropertyValidationErrorComponent | null
) {}
private readonly control: HTMLElement | null,
private readonly propertyValidationError: PropertyValidationErrorComponent | null
) {
this.onReloadVisibilityRequested.subscribe(this.reloadVisibility);
}

public reloadDependencies() {
if (this.valueEditor.reloadDependencies) {
this.valueEditor.reloadDependencies();
}
this.revalidate();
this.validateProperty();
this.onReloadVisibilityRequested.push();
}

private revalidate() {
if (this.validationError) {
this.validationError.validate();
private validateProperty() {
if (this.propertyValidationError) {
this.propertyValidationError.validate();
}
}

private readonly reloadVisibility = () => {
const isValueEditorHidden = this.valueEditor.isHidden ? this.valueEditor.isHidden() : false;
const isValidationErrorHidden = this.propertyValidationError ? this.propertyValidationError.isHidden() : true;

const isPropertyEditorHidden = isValueEditorHidden && isValidationErrorHidden;

Html.toggleClass(this.view, isPropertyEditorHidden, 'swe-hidden');
Html.toggleClass(this.valueEditor.view, isValueEditorHidden, 'swe-hidden');
if (this.control) {
Html.toggleClass(this.control, isValueEditorHidden, 'swe-hidden');
}
};

private readonly onValueChangedHandler = () => {
this.revalidate();
this.validateProperty();
};

private readonly onEditorIsHiddenChanged = () => {
this.onReloadVisibilityRequested.push();
};
}
11 changes: 11 additions & 0 deletions editor/src/value-editors/hidden/hidden-value-editor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { hiddenValueEditor } from './hidden-value-editor';

describe('hiddenValueEditor', () => {
it('is hidden', () => {
const editor = hiddenValueEditor();

expect(editor.view).toBeDefined();
expect(editor.isHidden).toBeDefined();
expect((editor.isHidden as () => boolean)()).toBe(true);
});
});
Loading

0 comments on commit ec7efee

Please sign in to comment.