Skip to content

Commit

Permalink
feat: implement file picker component
Browse files Browse the repository at this point in the history
  • Loading branch information
vsgoulart committed Oct 23, 2024
1 parent 5c26ffe commit 08e37e9
Show file tree
Hide file tree
Showing 26 changed files with 675 additions and 17 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const INPUTS = [
'taglist',
'textfield',
'textarea',
'filepicker',
];

export const OPTIONS_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { get } from 'min-dash';

import { useService, useVariables } from '../hooks';

import { FeelTemplatingEntry, isFeelEntryEdited } from '@bpmn-io/properties-panel';

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

const entries = [];

entries.push({
id: 'accept',
component: Accept,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'filepicker',
});

return entries;
}

function Accept(props) {
const { editField, field, id } = props;

const debounce = useService('debounce');

const variables = useVariables().map((name) => ({ name }));

const path = ['accept'];

const getValue = () => {
return get(field, path, '');
};

const setValue = (value) => {
return editField(field, path, value);
};

return FeelTemplatingEntry({
debounce,
element: field,
getValue,
id,
label: 'Supported file formats',
singleLine: true,
setValue,
variables,
description,
});
}

// helpers //////////

const description = (
<>
A comma-separated list of{' '}
<a
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers"
target="_blank">
file type specifiers
</a>
</>
);
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,29 @@ export function DefaultValueEntry(props) {
};
}

const defaulValueBase = {
const defaultValueBase = {
editField,
field,
id: 'defaultValue',
label: 'Default value',
};

entries.push({
...defaulValueBase,
...defaultValueBase,
component: DefaultValueCheckbox,
isEdited: isSelectEntryEdited,
isDefaultVisible: isDefaultVisible((field) => field.type === 'checkbox'),
});

entries.push({
...defaulValueBase,
...defaultValueBase,
component: DefaultValueNumber,
isEdited: isTextFieldEntryEdited,
isDefaultVisible: isDefaultVisible((field) => field.type === 'number'),
});

entries.push({
...defaulValueBase,
...defaultValueBase,
component: DefaultValueSingleSelect,
isEdited: isSelectEntryEdited,
isDefaultVisible: isDefaultVisible((field) => field.type === 'radio' || field.type === 'select'),
Expand All @@ -67,14 +67,14 @@ export function DefaultValueEntry(props) {
// todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)

entries.push({
...defaulValueBase,
...defaultValueBase,
component: DefaultValueTextfield,
isEdited: isTextFieldEntryEdited,
isDefaultVisible: isDefaultVisible((field) => field.type === 'textfield'),
});

entries.push({
...defaulValueBase,
...defaultValueBase,
component: DefaultValueTextarea,
isEdited: isTextAreaEntryEdited,
isDefaultVisible: isDefaultVisible((field) => field.type === 'textarea'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function DescriptionEntry(props) {
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => INPUTS.includes(field.type),
isDefaultVisible: (field) => field.type !== 'filepicker' && INPUTS.includes(field.type),
});

return entries;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { get } from 'min-dash';

import { useService, useVariables } from '../hooks';

import { FeelToggleSwitchEntry, isFeelEntryEdited } from '@bpmn-io/properties-panel';

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

const entries = [];

entries.push({
id: 'multiple',
component: Multiple,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'filepicker',
});

return entries;
}

function Multiple(props) {
const { editField, field, id } = props;

const debounce = useService('debounce');

const variables = useVariables().map((name) => ({ name }));

const path = ['multiple'];

const getValue = () => {
return get(field, path, '');
};

const setValue = (value) => {
return editField(field, path, value);
};

return FeelToggleSwitchEntry({
debounce,
element: field,
feel: 'optional',
getValue,
id,
label: 'Upload multiple files',
inline: true,
setValue,
variables,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ export { HeadersSourceSelectEntry } from './HeadersSourceSelectEntry';
export { ColumnsExpressionEntry } from './ColumnsExpressionEntry';
export { StaticColumnsSourceEntry } from './StaticColumnsSourceEntry';
export { VersionTagEntry } from './VersionTagEntry';
export { AcceptEntry } from './AcceptEntry';
export { MultipleEntry } from './MultipleEntry';
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
PaginationEntry,
RowCountEntry,
VersionTagEntry,
AcceptEntry,
MultipleEntry,
} from '../entries';

export function GeneralGroup(field, editField, getService) {
Expand All @@ -48,6 +50,8 @@ export function GeneralGroup(field, editField, getService) {
...ImageSourceEntry({ field, editField }),
...AltTextEntry({ field, editField }),
...SelectEntries({ field, editField }),
...AcceptEntry({ field, editField }),
...MultipleEntry({ field, editField }),
...DisabledEntry({ field, editField }),
...ReadonlyEntry({ field, editField }),
...TableDataSourceEntry({ field, editField }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3416,6 +3416,26 @@ describe('properties panel', function () {
});
});
});

describe('filepicker', function () {
it('entries', function () {
// given
const field = schema.components.find(({ key }) => key === 'files');

bootstrapPropertiesPanel({
container,
field,
});

// then
expectPanelStructure(container, {
General: ['Field label', 'Key', 'Supported file formats', 'Upload multiple files', 'Disabled', 'Read only'],
Condition: [],
Validation: ['Required'],
'Custom properties': [],
});
});
});
});

describe('custom properties', function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ describe('GeneralGroup', function () {

it('should render for INPUTS', function () {
// given
for (const type of INPUTS) {
for (const type of INPUTS.filter((type) => type !== 'filepicker')) {
const field = { type };

// when
Expand Down Expand Up @@ -580,11 +580,14 @@ describe('GeneralGroup', function () {
});

describe('for all other INPUTS', () => {
const otherInputTypes = INPUTS.filter((i) => !OPTIONS_INPUTS.includes(i));
const nonDefaultValueInputs = new Set(['datetime', 'filepicker']);
const defaultValueInputs = INPUTS.filter(
(input) => !OPTIONS_INPUTS.includes(input) && !nonDefaultValueInputs.has(input),
);

it('should render', function () {
// given
for (const type of otherInputTypes) {
for (const type of defaultValueInputs) {
const field = { type };

// when
Expand All @@ -593,8 +596,22 @@ describe('GeneralGroup', function () {
// then
const defaultValueEntry = findEntry('defaultValue', container);

if (type === 'datetime') expect(defaultValueEntry).to.not.exist;
else expect(defaultValueEntry).to.exist;
expect(defaultValueEntry).to.exist;
}
});

it('should not render', function () {
// given
for (const type of nonDefaultValueInputs) {
const field = { type };

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

// then
const defaultValueEntry = findEntry('defaultValue', container);

expect(defaultValueEntry).to.not.exist;
}
});
});
Expand Down
8 changes: 8 additions & 0 deletions packages/form-js-editor/test/spec/form.json
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@
"alt": "The bpmn.io logo",
"type": "image"
},
{
"label": "Image files",
"type": "filepicker",
"id": "files",
"key": "files",
"multiple": true,
"accept": ".jpg,.png"
},
{
"id": "Spacer_1",
"type": "spacer",
Expand Down
25 changes: 22 additions & 3 deletions packages/form-js-viewer/assets/form-js-base.css
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@
.fjs-container .fjs-input[type='tel'],
.fjs-container .fjs-input[type='number'],
.fjs-container .fjs-button[type='submit'],
.fjs-container .fjs-button[type='button'],
.fjs-container .fjs-button[type='reset'],
.fjs-container .fjs-textarea,
.fjs-container .fjs-select {
Expand Down Expand Up @@ -636,7 +637,8 @@
margin: 6px 10px 6px 4px;
}

.fjs-container .fjs-button[type='submit'] {
.fjs-container .fjs-button[type='submit'],
.fjs-container .fjs-button[type='button'] {
color: var(--cds-text-inverse, var(--color-white));
background-color: var(--color-accent);
border-color: var(--color-accent);
Expand All @@ -649,12 +651,14 @@
}

.fjs-container .fjs-button[type='submit'],
.fjs-container .fjs-button[type='button'],
.fjs-container .fjs-button[type='reset'] {
min-width: 100px;
width: auto;
}

.fjs-container .fjs-button[type='submit'] {
.fjs-container .fjs-button[type='submit'],
.fjs-container .fjs-button[type='button'] {
font-weight: 600;
}

Expand All @@ -665,6 +669,7 @@
.fjs-container .fjs-input[type='tel']:focus,
.fjs-container .fjs-input[type='number']:focus,
.fjs-container .fjs-button[type='submit']:focus,
.fjs-container .fjs-button[type='button']:focus,
.fjs-container .fjs-button[type='reset']:focus,
.fjs-container .fjs-textarea:focus,
.fjs-container .fjs-select:focus {
Expand All @@ -681,7 +686,8 @@
outline: none;
}

.fjs-container .fjs-button[type='submit']:focus {
.fjs-container .fjs-button[type='submit']:focus,
.fjs-container .fjs-button[type='button']:focus {
border-color: var(--color-accent);
}

Expand Down Expand Up @@ -724,13 +730,15 @@
}

.fjs-container .fjs-button[type='submit']:disabled,
.fjs-container .fjs-button[type='button']:disabled,
.fjs-container .fjs-button[type='reset']:disabled {
color: var(--cds-text-on-color-disabled, var(--color-text-light));
background-color: var(--color-background-disabled);
border-color: var(--color-borders-disabled);
}

.fjs-container .fjs-button[type='submit']:read-only,
.fjs-container .fjs-button[type='button']:read-only,
.fjs-container .fjs-button[type='reset']:read-only {
color: var(--text-light);
background-color: var(--color-background-readonly);
Expand Down Expand Up @@ -1278,3 +1286,14 @@
.fjs-container .flatpickr-calendar {
width: 326px;
}

.fjs-hidden {
display: none;
}

.fjs-container .fjs-filepicker-container {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
}
Loading

0 comments on commit 08e37e9

Please sign in to comment.