From 30e117d4cc4206c056996be3d1eeac740c7c98fb Mon Sep 17 00:00:00 2001 From: Vinicius Goulart Date: Sun, 8 Dec 2024 23:12:36 +0100 Subject: [PATCH] feat: bootstrap document preview element --- .../entries/DocumentsDataSource.js | 74 +++++++++++++++++ .../properties-panel/entries/EndpointKey.js | 79 +++++++++++++++++++ .../properties-panel/entries/LabelEntry.js | 4 +- .../entries/MaxHeightEntry.js | 72 +++++++++++++++++ .../properties-panel/entries/TitleEntry.js | 51 ++++++++++++ .../properties-panel/entries/index.js | 4 + .../groups/AppearanceGroup.js | 3 +- .../properties-panel/groups/GeneralGroup.js | 6 ++ .../properties-panel/PropertiesPanel.spec.js | 20 +++++ packages/form-js-editor/test/spec/form.json | 8 ++ packages/form-js-viewer/src/index.js | 2 +- .../components/form-fields/DocumentPreview.js | 17 ++++ .../components/icons/DocumentPreview.svg | 1 + .../src/render/components/icons/index.js | 2 + .../src/render/components/index.js | 3 + .../src/util/getSchemaVariables.js | 3 + .../test/spec/documentPreview.json | 15 ++++ .../test/spec/util/GetSchemaVariables.spec.js | 7 ++ packages/form-js/test/spec/Form.spec.js | 2 +- .../form-json-schema/src/defs/component.json | 17 +++- .../field-types/presentation-components.json | 2 +- .../defs/rules/rules-allowed-properties.json | 48 ++++++++++- .../defs/rules/rules-required-properties.json | 15 +++- packages/form-json-schema/src/defs/type.json | 3 +- packages/form-json-schema/src/index.json | 2 +- .../test/fixtures/accept-not-allowed.js | 4 +- .../test/fixtures/content-not-allowed.js | 4 +- .../test/fixtures/dataSource-not-allowed.js | 4 +- .../test/fixtures/documentPreview.js | 14 ++++ .../test/fixtures/endpointKey-not-allowed.js | 27 +++++++ .../expression-field-expression-required.js | 6 +- .../test/fixtures/maxHeight-not-allowed.js | 27 +++++++ .../test/fixtures/multiple-not-allowed.js | 4 +- .../fixtures/schemaVersion-not-supported.js | 6 +- .../test/fixtures/title-not-allowed.js | 27 +++++++ .../test/spec/validation.spec.js | 8 ++ 36 files changed, 563 insertions(+), 28 deletions(-) create mode 100644 packages/form-js-editor/src/features/properties-panel/entries/DocumentsDataSource.js create mode 100644 packages/form-js-editor/src/features/properties-panel/entries/EndpointKey.js create mode 100644 packages/form-js-editor/src/features/properties-panel/entries/MaxHeightEntry.js create mode 100644 packages/form-js-editor/src/features/properties-panel/entries/TitleEntry.js create mode 100644 packages/form-js-viewer/src/render/components/form-fields/DocumentPreview.js create mode 100644 packages/form-js-viewer/src/render/components/icons/DocumentPreview.svg create mode 100644 packages/form-js-viewer/test/spec/documentPreview.json create mode 100644 packages/form-json-schema/test/fixtures/documentPreview.js create mode 100644 packages/form-json-schema/test/fixtures/endpointKey-not-allowed.js create mode 100644 packages/form-json-schema/test/fixtures/maxHeight-not-allowed.js create mode 100644 packages/form-json-schema/test/fixtures/title-not-allowed.js diff --git a/packages/form-js-editor/src/features/properties-panel/entries/DocumentsDataSource.js b/packages/form-js-editor/src/features/properties-panel/entries/DocumentsDataSource.js new file mode 100644 index 000000000..0a190f585 --- /dev/null +++ b/packages/form-js-editor/src/features/properties-panel/entries/DocumentsDataSource.js @@ -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 = ( +
+

A source is a JSON object containing metadata for a document or an array of documents.

+

Each entry must include a document ID, name, and MIME type.

+

Additional details are optional. The expected format is as follows:

+
+        {schema}
+      
+
+ ); + + return FeelTemplatingEntry({ + debounce, + element: field, + getValue, + id, + label: 'Documents metadata source', + feel: 'required', + singleLine: true, + setValue, + variables, + tooltip, + }); +} diff --git a/packages/form-js-editor/src/features/properties-panel/entries/EndpointKey.js b/packages/form-js-editor/src/features/properties-panel/entries/EndpointKey.js new file mode 100644 index 000000000..36ae13e9b --- /dev/null +++ b/packages/form-js-editor/src/features/properties-panel/entries/EndpointKey.js @@ -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 = ( +
+

A context key that will be evaluated to a string containing the API endpoint for downloading a document.

+

+ This string must contain
+ the {'{ documentId }'} placeholder which will be replaced with the document ID from the documents + metadata. +

+

+ If you're using the Camunda Tasklist UI this variable will be automatically injected in the context for you. +

+

+ Find more details in the{' '} + + Camunda documentation + + . +

+
+ ); + + 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; diff --git a/packages/form-js-editor/src/features/properties-panel/entries/LabelEntry.js b/packages/form-js-editor/src/features/properties-panel/entries/LabelEntry.js index 884ac308a..e6ad46fde 100644 --- a/packages/form-js-editor/src/features/properties-panel/entries/LabelEntry.js +++ b/packages/form-js-editor/src/features/properties-panel/entries/LabelEntry.js @@ -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); }; @@ -47,7 +47,7 @@ export function LabelEntry(props) { editField, field, isEdited: isFeelEntryEdited, - isDefaultVisible: isSimplyLabled, + isDefaultVisible: isSimplyLabeled, }); return entries; diff --git a/packages/form-js-editor/src/features/properties-panel/entries/MaxHeightEntry.js b/packages/form-js-editor/src/features/properties-panel/entries/MaxHeightEntry.js new file mode 100644 index 000000000..28b5e4553 --- /dev/null +++ b/packages/form-js-editor/src/features/properties-panel/entries/MaxHeightEntry.js @@ -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.'; + } +}; diff --git a/packages/form-js-editor/src/features/properties-panel/entries/TitleEntry.js b/packages/form-js-editor/src/features/properties-panel/entries/TitleEntry.js new file mode 100644 index 000000000..304d00e9b --- /dev/null +++ b/packages/form-js-editor/src/features/properties-panel/entries/TitleEntry.js @@ -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, + }); +} diff --git a/packages/form-js-editor/src/features/properties-panel/entries/index.js b/packages/form-js-editor/src/features/properties-panel/entries/index.js index 3636c9970..a1d9f75d3 100644 --- a/packages/form-js-editor/src/features/properties-panel/entries/index.js +++ b/packages/form-js-editor/src/features/properties-panel/entries/index.js @@ -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'; diff --git a/packages/form-js-editor/src/features/properties-panel/groups/AppearanceGroup.js b/packages/form-js-editor/src/features/properties-panel/groups/AppearanceGroup.js index 24d6fb293..645bb09ef 100644 --- a/packages/form-js-editor/src/features/properties-panel/groups/AppearanceGroup.js +++ b/packages/form-js-editor/src/features/properties-panel/groups/AppearanceGroup.js @@ -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) { diff --git a/packages/form-js-editor/src/features/properties-panel/groups/GeneralGroup.js b/packages/form-js-editor/src/features/properties-panel/groups/GeneralGroup.js index a8cd25ccd..ec4bcfe24 100644 --- a/packages/form-js-editor/src/features/properties-panel/groups/GeneralGroup.js +++ b/packages/form-js-editor/src/features/properties-panel/groups/GeneralGroup.js @@ -26,6 +26,9 @@ import { VersionTagEntry, AcceptEntry, MultipleEntry, + TitleEntry, + DocumentsDataSourceEntry, + EndpointKeyEntry, } from '../entries'; export function GeneralGroup(field, editField, getService) { @@ -33,6 +36,7 @@ export function GeneralGroup(field, editField, getService) { ...IdEntry({ field, editField }), ...VersionTagEntry({ field, editField }), ...LabelEntry({ field, editField }), + ...TitleEntry({ field, editField }), ...DescriptionEntry({ field, editField }), ...KeyEntry({ field, editField, getService }), ...PathEntry({ field, editField, getService }), @@ -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) { diff --git a/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js b/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js index 98e19aeeb..30c6e7c59 100644 --- a/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js +++ b/packages/form-js-editor/test/spec/features/properties-panel/PropertiesPanel.spec.js @@ -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 () { diff --git a/packages/form-js-editor/test/spec/form.json b/packages/form-js-editor/test/spec/form.json index f8ac1c932..8b70e0f2c 100644 --- a/packages/form-js-editor/test/spec/form.json +++ b/packages/form-js-editor/test/spec/form.json @@ -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", diff --git a/packages/form-js-viewer/src/index.js b/packages/form-js-viewer/src/index.js index 1c7307496..8df90ffcc 100644 --- a/packages/form-js-viewer/src/index.js +++ b/packages/form-js-viewer/src/index.js @@ -5,7 +5,7 @@ export * from './render'; export * from './util'; export * from './features'; -const schemaVersion = 17; +const schemaVersion = 18; export { Form, schemaVersion }; diff --git a/packages/form-js-viewer/src/render/components/form-fields/DocumentPreview.js b/packages/form-js-viewer/src/render/components/form-fields/DocumentPreview.js new file mode 100644 index 000000000..588bebac4 --- /dev/null +++ b/packages/form-js-viewer/src/render/components/form-fields/DocumentPreview.js @@ -0,0 +1,17 @@ +/** + * @returns {import("preact").JSX.Element} + */ +export function DocumentPreview() { + return null; +} + +DocumentPreview.config = { + type: 'documentPreview', + keyed: false, + group: 'presentation', + name: 'Document preview', + create: (options = {}) => ({ + title: 'Document preview', + ...options, + }), +}; diff --git a/packages/form-js-viewer/src/render/components/icons/DocumentPreview.svg b/packages/form-js-viewer/src/render/components/icons/DocumentPreview.svg new file mode 100644 index 000000000..db46124a5 --- /dev/null +++ b/packages/form-js-viewer/src/render/components/icons/DocumentPreview.svg @@ -0,0 +1 @@ + diff --git a/packages/form-js-viewer/src/render/components/icons/index.js b/packages/form-js-viewer/src/render/components/icons/index.js index 7896d8201..d50926215 100644 --- a/packages/form-js-viewer/src/render/components/icons/index.js +++ b/packages/form-js-viewer/src/render/components/icons/index.js @@ -21,6 +21,7 @@ import ImageIcon from './Image.svg'; import GroupIcon from './Group.svg'; import TableIcon from './Table.svg'; import FilePickerIcon from './FilePicker.svg'; +import DocumentPreviewIcon from './DocumentPreview.svg'; export const iconsByType = (type) => { return { @@ -46,6 +47,7 @@ export const iconsByType = (type) => { textarea: TextareaIcon, table: TableIcon, filepicker: FilePickerIcon, + documentPreview: DocumentPreviewIcon, default: FormIcon, }[type]; }; diff --git a/packages/form-js-viewer/src/render/components/index.js b/packages/form-js-viewer/src/render/components/index.js index 6446b5abe..0c2cc9570 100644 --- a/packages/form-js-viewer/src/render/components/index.js +++ b/packages/form-js-viewer/src/render/components/index.js @@ -20,6 +20,7 @@ import { Textfield } from './form-fields/Textfield'; import { Textarea } from './form-fields/Textarea'; import { Table } from './form-fields/Table'; import { FilePicker } from './form-fields/FilePicker'; +import { DocumentPreview } from './form-fields/DocumentPreview'; import { Label } from './Label'; import { Description } from './Description'; @@ -54,6 +55,7 @@ export { Textarea, Table, FilePicker, + DocumentPreview, }; export const formFields = [ @@ -79,6 +81,7 @@ export const formFields = [ Html, Spacer, Separator, + DocumentPreview, /* Containers */ Group, diff --git a/packages/form-js-viewer/src/util/getSchemaVariables.js b/packages/form-js-viewer/src/util/getSchemaVariables.js index 70c838bf8..27b3ffcb7 100644 --- a/packages/form-js-viewer/src/util/getSchemaVariables.js +++ b/packages/form-js-viewer/src/util/getSchemaVariables.js @@ -25,6 +25,8 @@ const EXPRESSION_PROPERTIES = [ 'expression', 'multiple', 'accept', + 'endpointKey', + 'title', ]; const TEMPLATE_PROPERTIES = [ @@ -37,6 +39,7 @@ const TEMPLATE_PROPERTIES = [ 'text', 'content', 'url', + 'title', ]; /** diff --git a/packages/form-js-viewer/test/spec/documentPreview.json b/packages/form-js-viewer/test/spec/documentPreview.json new file mode 100644 index 000000000..b42f9d7f7 --- /dev/null +++ b/packages/form-js-viewer/test/spec/documentPreview.json @@ -0,0 +1,15 @@ +{ + "components": [ + { + "title": "Case {{case_id}} documents", + "type": "documentPreview", + "id": "Field_0wy8tws", + "dataSource": "=my_documents", + "endpointKey": "=my_documents_endpoint" + } + ], + "$schema": "../../../form-json-schema/resources/schema.json", + "type": "default", + "id": "Form_1bd2k8m", + "schemaVersion": 18 +} diff --git a/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js b/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js index 2efbe6a2f..5dfe019b5 100644 --- a/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js +++ b/packages/form-js-viewer/test/spec/util/GetSchemaVariables.spec.js @@ -20,6 +20,7 @@ import iframesSchema from '../iframes.json'; import htmlSchema from '../html.json'; import expressionFieldSchema from '../expressionField.json'; import filepickerSchema from '../filepicker.json'; +import documentPreviewSchema from '../documentPreview.json'; describe('util/getSchemaVariables', () => { it('should include form field keys', () => { @@ -228,4 +229,10 @@ describe('util/getSchemaVariables', () => { 'dynamiclist_path', ]); }); + + it('should include variables in document preview', () => { + const variables = getSchemaVariables(documentPreviewSchema); + + expect(variables).to.eql(['my_documents', 'my_documents_endpoint', 'case_id']); + }); }); diff --git a/packages/form-js/test/spec/Form.spec.js b/packages/form-js/test/spec/Form.spec.js index e60129fc0..39bf5aae5 100644 --- a/packages/form-js/test/spec/Form.spec.js +++ b/packages/form-js/test/spec/Form.spec.js @@ -111,7 +111,7 @@ describe('viewer exports', function () { it('should expose schemaVersion', function () { expect(typeof schemaVersion).to.eql('number'); - expect(schemaVersion).to.eql(17); + expect(schemaVersion).to.eql(18); }); it('should generate unique ID for every instance', async function () { diff --git a/packages/form-json-schema/src/defs/component.json b/packages/form-json-schema/src/defs/component.json index 31e157b2f..9230d4482 100644 --- a/packages/form-json-schema/src/defs/component.json +++ b/packages/form-json-schema/src/defs/component.json @@ -251,7 +251,7 @@ }, "dataSource": { "$id": "#/component/dataSource", - "description": "Specifies the data source which will populate the table component.", + "description": "Specifies the data source which will populate the table or the document preview components.", "type": "string" }, "security": { @@ -272,6 +272,21 @@ "$id": "#/component/multiple", "description": "Allow multiple files to be selected.", "type": ["boolean", "string"] + }, + "title": { + "$id": "#/component/title", + "description": "The title displayed on top of the document preview component.", + "type": "string" + }, + "maxHeight": { + "$id": "#/component/maxHeight", + "description": "The maximum height of a document item in the document preview component.", + "type": "number" + }, + "endpointKey": { + "$id": "#/component/endpointKey", + "description": "The endpoint key used to fetch the document data.", + "type": "string" } }, "required": ["type"] diff --git a/packages/form-json-schema/src/defs/field-types/presentation-components.json b/packages/form-json-schema/src/defs/field-types/presentation-components.json index 71249e62d..a882bf241 100644 --- a/packages/form-json-schema/src/defs/field-types/presentation-components.json +++ b/packages/form-json-schema/src/defs/field-types/presentation-components.json @@ -1,7 +1,7 @@ { "properties": { "type": { - "enum": ["table"] + "enum": ["table", "documentPreview"] } }, "required": ["type"] diff --git a/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json b/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json index 576276d57..bf351a1f5 100644 --- a/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json +++ b/packages/form-json-schema/src/defs/rules/rules-allowed-properties.json @@ -342,21 +342,30 @@ { "if": { "not": { - "$ref": "../field-types/presentation-components.json" + "properties": { + "type": { + "const": "table" + } + }, + "required": ["type"] } }, "then": { "properties": { "columns": false, "columnsExpression": false, - "rowCount": false, - "dataSource": false + "rowCount": false } } }, { "if": { - "$ref": "../field-types/presentation-components.json" + "properties": { + "type": { + "const": "table" + } + }, + "required": ["type"] }, "then": { "oneOf": [ @@ -381,6 +390,18 @@ ] } }, + { + "if": { + "not": { + "$ref": "../field-types/presentation-components.json" + } + }, + "then": { + "properties": { + "dataSource": false + } + } + }, { "if": { "not": { @@ -430,6 +451,25 @@ "description": false } } + }, + { + "if": { + "not": { + "properties": { + "type": { + "const": "documentPreview" + } + }, + "required": ["type"] + } + }, + "then": { + "properties": { + "title": false, + "endpointKey": false, + "maxHeight": false + } + } } ] } diff --git a/packages/form-json-schema/src/defs/rules/rules-required-properties.json b/packages/form-json-schema/src/defs/rules/rules-required-properties.json index 9666329ae..6613b81b5 100644 --- a/packages/form-json-schema/src/defs/rules/rules-required-properties.json +++ b/packages/form-json-schema/src/defs/rules/rules-required-properties.json @@ -11,7 +11,12 @@ }, { "if": { - "$ref": "../field-types/presentation-components.json" + "properties": { + "type": { + "const": "table" + } + }, + "required": ["type"] }, "then": { "oneOf": [ @@ -24,6 +29,14 @@ ] } }, + { + "if": { + "$ref": "../field-types/presentation-components.json" + }, + "then": { + "required": ["dataSource"] + } + }, { "if": { "properties": { diff --git a/packages/form-json-schema/src/defs/type.json b/packages/form-json-schema/src/defs/type.json index e7587befc..9f5dec4b2 100644 --- a/packages/form-json-schema/src/defs/type.json +++ b/packages/form-json-schema/src/defs/type.json @@ -23,6 +23,7 @@ "table", "iframe", "expression", - "filepicker" + "filepicker", + "documentPreview" ] } diff --git a/packages/form-json-schema/src/index.json b/packages/form-json-schema/src/index.json index a403e0e11..bfdd7ef24 100644 --- a/packages/form-json-schema/src/index.json +++ b/packages/form-json-schema/src/index.json @@ -25,7 +25,7 @@ "description": "The schema version of a form", "type": "integer", "minimum": 1, - "maximum": 17 + "maximum": 18 }, "executionPlatform": { "$id": "#/executionPlatform", diff --git a/packages/form-json-schema/test/fixtures/accept-not-allowed.js b/packages/form-json-schema/test/fixtures/accept-not-allowed.js index f9e6423be..24a8dcbf0 100644 --- a/packages/form-json-schema/test/fixtures/accept-not-allowed.js +++ b/packages/form-json-schema/test/fixtures/accept-not-allowed.js @@ -15,11 +15,11 @@ export const errors = [ keyword: 'false schema', message: 'boolean schema is false', params: {}, - schemaPath: '#/properties/components/items/allOf/1/allOf/20/then/properties/accept/false schema', + schemaPath: '#/properties/components/items/allOf/1/allOf/21/then/properties/accept/false schema', }, { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/1/allOf/20/if', + schemaPath: '#/properties/components/items/allOf/1/allOf/21/if', keyword: 'if', params: { failingKeyword: 'then' }, message: 'must match "then" schema', diff --git a/packages/form-json-schema/test/fixtures/content-not-allowed.js b/packages/form-json-schema/test/fixtures/content-not-allowed.js index ad72669f7..2e3666add 100644 --- a/packages/form-json-schema/test/fixtures/content-not-allowed.js +++ b/packages/form-json-schema/test/fixtures/content-not-allowed.js @@ -12,14 +12,14 @@ export const form = { export const errors = [ { instancePath: '/components/0/content', - schemaPath: '#/properties/components/items/allOf/1/allOf/19/then/properties/content/false schema', + schemaPath: '#/properties/components/items/allOf/1/allOf/20/then/properties/content/false schema', keyword: 'false schema', params: {}, message: 'boolean schema is false', }, { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/1/allOf/19/if', + schemaPath: '#/properties/components/items/allOf/1/allOf/20/if', keyword: 'if', params: { failingKeyword: 'then' }, message: 'must match "then" schema', diff --git a/packages/form-json-schema/test/fixtures/dataSource-not-allowed.js b/packages/form-json-schema/test/fixtures/dataSource-not-allowed.js index 0d916d272..3de1e57d4 100644 --- a/packages/form-json-schema/test/fixtures/dataSource-not-allowed.js +++ b/packages/form-json-schema/test/fixtures/dataSource-not-allowed.js @@ -12,14 +12,14 @@ export const form = { export const errors = [ { instancePath: '/components/0/dataSource', - schemaPath: '#/properties/components/items/allOf/1/allOf/17/then/properties/dataSource/false schema', + schemaPath: '#/properties/components/items/allOf/1/allOf/19/then/properties/dataSource/false schema', keyword: 'false schema', params: {}, message: 'boolean schema is false', }, { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/1/allOf/17/if', + schemaPath: '#/properties/components/items/allOf/1/allOf/19/if', keyword: 'if', params: { failingKeyword: 'then' }, message: 'must match "then" schema', diff --git a/packages/form-json-schema/test/fixtures/documentPreview.js b/packages/form-json-schema/test/fixtures/documentPreview.js new file mode 100644 index 000000000..d733aa4e1 --- /dev/null +++ b/packages/form-json-schema/test/fixtures/documentPreview.js @@ -0,0 +1,14 @@ +export const form = { + type: 'default', + components: [ + { + type: 'documentPreview', + dataSource: '=someSource', + title: 'My documents', + endpointKey: '=someEndpointKey', + maxHeight: 100, + }, + ], +}; + +export const errors = null; diff --git a/packages/form-json-schema/test/fixtures/endpointKey-not-allowed.js b/packages/form-json-schema/test/fixtures/endpointKey-not-allowed.js new file mode 100644 index 000000000..5e820a211 --- /dev/null +++ b/packages/form-json-schema/test/fixtures/endpointKey-not-allowed.js @@ -0,0 +1,27 @@ +export const form = { + type: 'default', + components: [ + { + type: 'textfield', + key: 'textfield_g35o3e', + endpointKey: '=myKey', + }, + ], +}; + +export const errors = [ + { + instancePath: '/components/0/endpointKey', + keyword: 'false schema', + message: 'boolean schema is false', + params: {}, + schemaPath: '#/properties/components/items/allOf/1/allOf/23/then/properties/endpointKey/false schema', + }, + { + instancePath: '/components/0', + schemaPath: '#/properties/components/items/allOf/1/allOf/23/if', + keyword: 'if', + params: { failingKeyword: 'then' }, + message: 'must match "then" schema', + }, +]; diff --git a/packages/form-json-schema/test/fixtures/expression-field-expression-required.js b/packages/form-json-schema/test/fixtures/expression-field-expression-required.js index e16b2ceb4..45c4ffef9 100644 --- a/packages/form-json-schema/test/fixtures/expression-field-expression-required.js +++ b/packages/form-json-schema/test/fixtures/expression-field-expression-required.js @@ -11,7 +11,7 @@ export const form = { export const errors = [ { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/0/allOf/2/then/required', + schemaPath: '#/properties/components/items/allOf/0/allOf/3/then/required', keyword: 'required', params: { missingProperty: 'expression', @@ -20,7 +20,7 @@ export const errors = [ }, { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/0/allOf/2/then/required', + schemaPath: '#/properties/components/items/allOf/0/allOf/3/then/required', keyword: 'required', params: { missingProperty: 'computeOn', @@ -34,6 +34,6 @@ export const errors = [ params: { failingKeyword: 'then', }, - schemaPath: '#/properties/components/items/allOf/0/allOf/2/if', + schemaPath: '#/properties/components/items/allOf/0/allOf/3/if', }, ]; diff --git a/packages/form-json-schema/test/fixtures/maxHeight-not-allowed.js b/packages/form-json-schema/test/fixtures/maxHeight-not-allowed.js new file mode 100644 index 000000000..a051f000a --- /dev/null +++ b/packages/form-json-schema/test/fixtures/maxHeight-not-allowed.js @@ -0,0 +1,27 @@ +export const form = { + type: 'default', + components: [ + { + type: 'textfield', + key: 'textfield_g35o3e', + maxHeight: 100, + }, + ], +}; + +export const errors = [ + { + instancePath: '/components/0/maxHeight', + keyword: 'false schema', + message: 'boolean schema is false', + params: {}, + schemaPath: '#/properties/components/items/allOf/1/allOf/23/then/properties/maxHeight/false schema', + }, + { + instancePath: '/components/0', + schemaPath: '#/properties/components/items/allOf/1/allOf/23/if', + keyword: 'if', + params: { failingKeyword: 'then' }, + message: 'must match "then" schema', + }, +]; diff --git a/packages/form-json-schema/test/fixtures/multiple-not-allowed.js b/packages/form-json-schema/test/fixtures/multiple-not-allowed.js index 634dab41f..564b47bd3 100644 --- a/packages/form-json-schema/test/fixtures/multiple-not-allowed.js +++ b/packages/form-json-schema/test/fixtures/multiple-not-allowed.js @@ -15,11 +15,11 @@ export const errors = [ keyword: 'false schema', message: 'boolean schema is false', params: {}, - schemaPath: '#/properties/components/items/allOf/1/allOf/20/then/properties/multiple/false schema', + schemaPath: '#/properties/components/items/allOf/1/allOf/21/then/properties/multiple/false schema', }, { instancePath: '/components/0', - schemaPath: '#/properties/components/items/allOf/1/allOf/20/if', + schemaPath: '#/properties/components/items/allOf/1/allOf/21/if', keyword: 'if', params: { failingKeyword: 'then' }, message: 'must match "then" schema', diff --git a/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js b/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js index 7aa023edd..699b613a7 100644 --- a/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js +++ b/packages/form-json-schema/test/fixtures/schemaVersion-not-supported.js @@ -1,7 +1,7 @@ export const form = { type: 'default', components: [], - schemaVersion: 18, + schemaVersion: 19, }; export const errors = [ @@ -9,7 +9,7 @@ export const errors = [ instancePath: '/schemaVersion', schemaPath: '#/properties/schemaVersion/maximum', keyword: 'maximum', - params: { comparison: '<=', limit: 17 }, - message: 'must be <= 17', + params: { comparison: '<=', limit: 18 }, + message: 'must be <= 18', }, ]; diff --git a/packages/form-json-schema/test/fixtures/title-not-allowed.js b/packages/form-json-schema/test/fixtures/title-not-allowed.js new file mode 100644 index 000000000..9ceaeb89d --- /dev/null +++ b/packages/form-json-schema/test/fixtures/title-not-allowed.js @@ -0,0 +1,27 @@ +export const form = { + type: 'default', + components: [ + { + type: 'textfield', + key: 'textfield_g35o3e', + title: 'My title', + }, + ], +}; + +export const errors = [ + { + instancePath: '/components/0/title', + keyword: 'false schema', + message: 'boolean schema is false', + params: {}, + schemaPath: '#/properties/components/items/allOf/1/allOf/23/then/properties/title/false schema', + }, + { + instancePath: '/components/0', + schemaPath: '#/properties/components/items/allOf/1/allOf/23/if', + keyword: 'if', + params: { failingKeyword: 'then' }, + message: 'must match "then" schema', + }, +]; diff --git a/packages/form-json-schema/test/spec/validation.spec.js b/packages/form-json-schema/test/spec/validation.spec.js index 5b9d2766e..ab1a556f3 100644 --- a/packages/form-json-schema/test/spec/validation.spec.js +++ b/packages/form-json-schema/test/spec/validation.spec.js @@ -180,6 +180,14 @@ describe('validation', function () { testForm('accept-not-allowed'); testForm('multiple-not-allowed'); + + testForm('documentPreview'); + + testForm('title-not-allowed'); + + testForm('maxHeight-not-allowed'); + + testForm('endpointKey-not-allowed'); }); describe('rules - default', function () {