Skip to content

Commit

Permalink
feat: simple field adorners
Browse files Browse the repository at this point in the history
Closes #420

Co-Authored-By: Niklas Kiefer <niklas.kiefer@camunda.com>
  • Loading branch information
Skaiir and Niklas Kiefer committed Dec 12, 2022
1 parent 79888b5 commit 7efdcb9
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { PropertiesPanelPlaceholderProvider } from './PropertiesPanelPlaceholder

import {
ConditionGroup,
AppearanceGroup,
CustomValuesGroup,
GeneralGroup,
SerializationGroup,
Expand All @@ -30,6 +31,7 @@ function getGroups(field, editField) {
const groups = [
GeneralGroup(field, editField),
ConditionGroup(field, editField),
AppearanceGroup(field, editField),
SerializationGroup(field, editField),
...ValuesGroups(field, editField),
ConstraintsGroup(field, editField),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { TextFieldEntry, isTextFieldEntryEdited } from '@bpmn-io/properties-panel';

import { get, set } from 'min-dash';
import { useService } from '../hooks';

export default function AdornerEntry(props) {
const {
editField,
field
} = props;

const {
type
} = field;

const entries = [];

const onChange = (key) => {
return (value) => {
const appearance = get(field, [ 'appearance' ], {});

editField(field, [ 'appearance' ], set(appearance, [ key ], value));
};
};

const getValue = (key) => {
return () => {
return get(field, [ 'appearance', key ]);
};
};

if ([ 'number', 'textfield' ].includes(type)) {
entries.push({
id: 'prefix-adorner',
component: PrefixAdorner,
isEdited: isTextFieldEntryEdited,
editField,
field,
onChange,
getValue
});

entries.push({
id: 'suffix-adorner',
component: SuffixAdorner,
isEdited: isTextFieldEntryEdited,
editField,
field,
onChange,
getValue
});
}

return entries;
}

function PrefixAdorner(props) {
const {
field,
id,
onChange,
getValue
} = props;

const debounce = useService('debounce');

return TextFieldEntry({
debounce,
element: field,
getValue: getValue('prefixAdorner'),
id,
label: 'Prefix',
setValue: onChange('prefixAdorner')
});
}

function SuffixAdorner(props) {
const {
field,
id,
onChange,
getValue
} = props;

const debounce = useService('debounce');

return TextFieldEntry({
debounce,
element: field,
getValue: getValue('suffixAdorner'),
id,
label: 'Suffix',
setValue: onChange('suffixAdorner')
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export { default as CustomValueEntry } from './CustomValueEntry';
export { default as ValuesSourceSelectEntry } from './ValuesSourceSelectEntry';
export { default as InputKeyValuesSourceEntry } from './InputKeyValuesSourceEntry';
export { default as StaticValuesSourceEntry } from './StaticValuesSourceEntry';
export { default as AdornerEntry } from './AdornerEntry';
export { ConditionEntry } from './ConditionEntry';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
AdornerEntry
} from '../entries';


export default function AppearanceGroup(field, editField) {

const entries = [
...AdornerEntry({ field, editField })
];

if (!entries.length) {
return null;
}

return {
id: 'appearance',
label: 'Appearance',
entries
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export { default as ConstraintsGroup } from './ConstraintsGroup';
export { default as ValidationGroup } from './ValidationGroup';
export { default as ValuesGroups } from './ValuesGroups';
export { default as CustomValuesGroup } from './CustomValuesGroup';
export { default as AppearanceGroup } from './AppearanceGroup';
export { ConditionGroup } from './ConditionGroup';
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import {
cleanup,
fireEvent,
render
} from '@testing-library/preact/pure';

import { AppearanceGroup } from '../../../../../src/features/properties-panel/groups';

import { WithPropertiesPanelContext, WithPropertiesPanel } from '../helper';


describe('AppearanceGroup', function() {

afterEach(() => cleanup());


it('should NOT render for checkbox', function() {

// given
const field = { type: 'checkbox' };

const group = AppearanceGroup(field);

// then
expect(group).to.not.exist;
});


describe('suffixAdorner', function() {

it('should render for textfield', function() {

// given
const field = { type: 'textfield' };

// when
const { container } = renderAppearanceGroup({ field });

// then
const input = findInput('suffix-adorner', container);

expect(input).to.exist;
});


it('should read', function() {

// given
const field = {
type: 'textfield',
appearance: {
suffixAdorner: 'foo'
}
};

// when
const { container } = renderAppearanceGroup({ field });

// then
const input = findInput('suffix-adorner', container);

// then
expect(input).to.exist;
expect(input.value).to.eql('foo');
});


it('should write', function() {

// given
const field = {
type: 'textfield',
appearance: {
suffixAdorner: 'foo'
}
};

const editFieldSpy = sinon.spy();

const { container } = renderAppearanceGroup({ field, editField: editFieldSpy });

const input = findInput('suffix-adorner', container);

// when
fireEvent.input(input, { target: { value: 'bar' } });

// then
expect(editFieldSpy).to.have.been.calledOnce;
expect(field.appearance.suffixAdorner).to.eql('bar');
});

});


describe('prefixAdorner', function() {

it('should render for textfield', function() {

// given
const field = { type: 'textfield' };

// when
const { container } = renderAppearanceGroup({ field });

// then
const input = findInput('prefix-adorner', container);

expect(input).to.exist;
});


it('should read', function() {

// given
const field = {
type: 'textfield',
appearance: {
prefixAdorner: 'foo'
}
};

// when
const { container } = renderAppearanceGroup({ field });

// then
const input = findInput('prefix-adorner', container);

// then
expect(input).to.exist;
expect(input.value).to.eql('foo');
});


it('should write', function() {

// given
const field = {
type: 'textfield',
appearance: {
prefixAdorner: 'foo'
}
};

const editFieldSpy = sinon.spy();

const { container } = renderAppearanceGroup({ field, editField: editFieldSpy });

const input = findInput('prefix-adorner', container);

// when
fireEvent.input(input, { target: { value: 'bar' } });

// then
expect(editFieldSpy).to.have.been.calledOnce;
expect(field.appearance.prefixAdorner).to.eql('bar');
});

});

});


// helper ///////////////

function renderAppearanceGroup(options) {
const {
editField,
field
} = options;

const groups = [ AppearanceGroup(field, editField) ];

return render(WithPropertiesPanelContext(WithPropertiesPanel({
field,
groups
})));
}

function findInput(id, container) {
return container.querySelector(`input[name="${id}"]`);
}
Loading

0 comments on commit 7efdcb9

Please sign in to comment.