Skip to content

Commit

Permalink
feat: bootstrap document preview element
Browse files Browse the repository at this point in the history
  • Loading branch information
vsgoulart committed Dec 9, 2024
1 parent 10334cb commit f8ef236
Show file tree
Hide file tree
Showing 36 changed files with 563 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { get } from 'min-dash';

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

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

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

const entries = [];

entries.push({
id: 'dataSource',
component: DocumentsDataSource,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'documentPreview',
});

return entries;
}

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

const debounce = useService('debounce');

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

const path = ['dataSource'];

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

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

const schema = `[
{
"documentId": "u123",
"metadata": {
"filename": "Document.pdf",
"mimeType": "application/pdf"
}
}
]`;

const tooltip = (
<div>
<p>A source is a JSON object containing metadata for a document or an array of documents.</p>
<p>Each entry must include a document ID, name, and MIME type.</p>
<p>Additional details are optional. The expected format is as follows:</p>
<pre>
<code>{schema}</code>
</pre>
</div>
);

return FeelTemplatingEntry({
debounce,
element: field,
getValue,
id,
label: 'Documents metadata source',
feel: 'required',
singleLine: true,
setValue,
variables,
tooltip,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { get } from 'min-dash';

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

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

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

const entries = [];

entries.push({
id: 'endpointKey',
component: EndpointKey,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'documentPreview',
});

return entries;
}

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

const debounce = useService('debounce');

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

const path = ['endpointKey'];

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

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

const tooltip = (
<div>
<p>A context key that will be evaluated to a string containing the API endpoint for downloading a document.</p>
<p>
This string must contain <br />
the <code>{'{ documentId }'}</code> placeholder which will be replaced with the document ID from the documents
metadata.
</p>
<p>
If you're using the Camunda Tasklist UI this variable will be automatically injected in the context for you.
</p>
<p>
Find more details in the{' '}
<a href="https://docs.camunda.io" rel="noopener noreferrer" target="_blank">
Camunda documentation
</a>
.
</p>
</div>
);

return FeelTemplatingEntry({
debounce,
element: field,
getValue,
id,
label: 'Document API endpoint key',
feel: 'required',
singleLine: true,
setValue,
variables,
description,
tooltip,
});
}

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

const description = <>An API endpoint for downloading a document</>;
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function LabelEntry(props) {
},
});

const isSimplyLabled = (field) => {
const isSimplyLabeled = (field) => {
return [...INPUTS.filter((input) => input !== 'datetime'), ...LABELED_NON_INPUTS].includes(field.type);
};

Expand All @@ -47,7 +47,7 @@ export function LabelEntry(props) {
editField,
field,
isEdited: isFeelEntryEdited,
isDefaultVisible: isSimplyLabled,
isDefaultVisible: isSimplyLabeled,
});

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

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

import { NumberFieldEntry, isNumberFieldEntryEdited } from '@bpmn-io/properties-panel';

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

const entries = [];

entries.push({
id: 'maxHeight',
component: MaxHeight,
editField: editField,
field: field,
isEdited: isNumberFieldEntryEdited,
isDefaultVisible: (field) => field.type === 'documentPreview',
});

return entries;
}

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

const debounce = useService('debounce');

const path = ['maxHeight'];

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

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

return NumberFieldEntry({
debounce,
label: 'Max height',
element: field,
id,
getValue,
setValue,
validate,
});
}

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

/**
* @param {string|number|undefined} value
* @returns {string|null}
*/
const validate = (value) => {
if (value === undefined || value === '') {
return null;
}

if (typeof value === 'string') {
return 'Value must be a number.';
}

if (!Number.isInteger(value)) {
return 'Should be an integer.';
}

if (value < 1) {
return 'Should be greater than zero.';
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { get } from 'min-dash';

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

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

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

const entries = [];

entries.push({
id: 'title',
component: Title,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'documentPreview',
});

return entries;
}

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

const debounce = useService('debounce');

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

const path = ['title'];

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

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

return FeelTemplatingEntry({
debounce,
element: field,
getValue,
id,
label: 'Title',
singleLine: true,
setValue,
variables,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ export { StaticColumnsSourceEntry } from './StaticColumnsSourceEntry';
export { VersionTagEntry } from './VersionTagEntry';
export { AcceptEntry } from './AcceptEntry';
export { MultipleEntry } from './MultipleEntry';
export { TitleEntry } from './TitleEntry';
export { DocumentsDataSourceEntry } from './DocumentsDataSource';
export { EndpointKeyEntry } from './EndpointKey';
export { MaxHeightEntry } from './MaxHeightEntry';
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { AdornerEntry, GroupAppearanceEntry, LayouterAppearanceEntry } from '../entries';
import { AdornerEntry, GroupAppearanceEntry, LayouterAppearanceEntry, MaxHeightEntry } from '../entries';

export function AppearanceGroup(field, editField, getService) {
const entries = [
...AdornerEntry({ field, editField }),
...GroupAppearanceEntry({ field, editField }),
...LayouterAppearanceEntry({ field, editField }),
...MaxHeightEntry({ field, editField }),
];

if (!entries.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ import {
VersionTagEntry,
AcceptEntry,
MultipleEntry,
TitleEntry,
DocumentsDataSourceEntry,
EndpointKeyEntry,
} from '../entries';

export function GeneralGroup(field, editField, getService) {
const entries = [
...IdEntry({ field, editField }),
...VersionTagEntry({ field, editField }),
...LabelEntry({ field, editField }),
...TitleEntry({ field, editField }),
...DescriptionEntry({ field, editField }),
...KeyEntry({ field, editField, getService }),
...PathEntry({ field, editField, getService }),
Expand All @@ -57,6 +61,8 @@ export function GeneralGroup(field, editField, getService) {
...TableDataSourceEntry({ field, editField }),
...PaginationEntry({ field, editField }),
...RowCountEntry({ field, editField }),
...DocumentsDataSourceEntry({ field, editField }),
...EndpointKeyEntry({ field, editField }),
];

if (entries.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3436,6 +3436,26 @@ describe('properties panel', function () {
});
});
});

describe('documentPreview', function () {
it('entries', function () {
// given
const field = schema.components.find(({ id }) => id === 'myDocuments');

bootstrapPropertiesPanel({
container,
field,
});

// then
expectPanelStructure(container, {
General: ['Title', 'Documents metadata source', 'Document API endpoint key'],
Condition: [],
Appearance: ['Max height'],
'Custom properties': [],
});
});
});
});

describe('custom properties', function () {
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 @@ -246,6 +246,14 @@
"multiple": true,
"accept": ".jpg,.png"
},
{
"title": "My documents",
"type": "documentPreview",
"id": "myDocuments",
"dataSource": "=myDocuments",
"endpointKey": "=myDocumentsEndpointKey",
"maxHeight": 500
},
{
"id": "Spacer_1",
"type": "spacer",
Expand Down
2 changes: 1 addition & 1 deletion packages/form-js-viewer/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export * from './render';
export * from './util';
export * from './features';

const schemaVersion = 17;
const schemaVersion = 18;

export { Form, schemaVersion };

Expand Down
Loading

0 comments on commit f8ef236

Please sign in to comment.