diff --git a/src/formio/components/cosign.ts b/src/formio/components/cosign.ts new file mode 100644 index 0000000..850683e --- /dev/null +++ b/src/formio/components/cosign.ts @@ -0,0 +1,66 @@ +import {OFExtensions, StrictComponentSchema} from '..'; +import {EmailInputSchema} from './email'; + +type TranslatableKeys = 'label' | 'description'; + +/** + * We don't currently support these properties - they get added in by base types, so we + * need to strip them out again. + */ +type KeysToOmit = + | 'hideLabel' + | 'placeholder' + | 'multiple' + | 'clearOnHide' + | 'conditional' + | 'errors' + | 'disabled' + | 'validateOn' + | 'tooltip'; + +export type CosignV1InputSchema = StrictComponentSchema & + Pick, 'openForms'>; + +/** + * The legacy Cosign component type, otherwise known as 'CosignOld'. + * + * The component does not actually provide any input data, it mostly functions as a + * marker in the form that cosigning is expected, hence the `never` value type. In the + * UI, it displays a button to start an (additional) login session to authenticate the + * cosigner and requires them to be physically in the same space. + * + * @group Form.io components + * @category Concrete types + * + * @deprecated + * + * The in-band cosign flow is problematic with existing DigiD/eHerkenning sessions. It + * is currently not scheduled for removal, but we recommend using the V2 variant for + * better UX. + */ +export interface CosignV1ComponentSchema extends Omit { + type: 'coSign'; + authPlugin: string; // plugin identifiers in the backend are dynamic +} + +type V2KeysToOmit = 'hideLabel' | 'disabled' | 'placeholder' | 'registration'; + +/** + * The cosign component type, otherwise known as 'Cosign'. + * + * This is a custom component sharing most of the functionality with the email input + * component type - it collects the e-mail address of any/a cosigner so that they + * receive a notification they're expected to cosign. The actual cosigning happens + * out-of-band. This component *does* take form data input, as opposed to the V1 + * component implementation. + * + * @group Form.io components + * @category Concrete types + */ +export interface CosignV2ComponentSchema extends Omit { + type: 'cosign'; + validateOn: 'blur'; + authPlugin: string; // plugin identifiers in the backend are dynamic + defaultValue?: string; // no multiple support, so must always be a single string + autocomplete?: string; +} diff --git a/src/formio/components/index.ts b/src/formio/components/index.ts index e8c0802..2948dbb 100644 --- a/src/formio/components/index.ts +++ b/src/formio/components/index.ts @@ -22,6 +22,7 @@ export * from './addressNL'; export * from './map'; export * from './editgrid'; export * from './signature'; +export * from './cosign'; // Layout components export * from './content'; diff --git a/src/formio/index.ts b/src/formio/index.ts index b77d613..2f9bea9 100644 --- a/src/formio/index.ts +++ b/src/formio/index.ts @@ -4,6 +4,8 @@ import { CheckboxComponentSchema, ColumnsComponentSchema, ContentComponentSchema, + CosignV1ComponentSchema, + CosignV2ComponentSchema, CurrencyComponentSchema, DateComponentSchema, DateTimeComponentSchema, @@ -74,12 +76,15 @@ export type AnyComponentSchema = | AddressNLComponentSchema | NpFamilyMembersComponentSchema | SignatureComponentSchema + | CosignV2ComponentSchema | MapComponentSchema | EditGridComponentSchema // layout | ContentComponentSchema | ColumnsComponentSchema - | FieldsetComponentSchema; + | FieldsetComponentSchema + // deprecated + | CosignV1ComponentSchema; /** * Convenience type alias for all supported concrete component schema types. diff --git a/test-d/formio/components/cosign-v1.test-d.ts b/test-d/formio/components/cosign-v1.test-d.ts new file mode 100644 index 0000000..e856ce0 --- /dev/null +++ b/test-d/formio/components/cosign-v1.test-d.ts @@ -0,0 +1,58 @@ +import {expectAssignable, expectNotAssignable} from 'tsd'; + +import {CosignV1ComponentSchema} from '../../../lib/'; + +// minimal CoSign component schema +expectAssignable({ + id: 'yejak', + type: 'coSign', + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', +}); + +// full, correct schema +expectAssignable({ + id: 'yejak', + type: 'coSign', + key: 'someCoSign', + // basic tab in builder form + label: 'Some cosign', + description: 'A description', + authPlugin: 'oidc-digid', + hidden: false, + // translations tab in builder form + openForms: { + translations: { + nl: { + label: 'foo', + description: 'bar', + }, + }, + }, +}); + +// different component type +expectNotAssignable({ + type: 'fieldset' as const, +}); + +// using unsupported properties +expectNotAssignable({ + id: 'yejak', + type: 'CoSign' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + hideLabel: true, +}); + +// multiple is not supported +expectNotAssignable({ + id: 'yejak', + type: 'CoSign' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + multiple: true as boolean, +}); diff --git a/test-d/formio/components/cosign-v2.test-d.ts b/test-d/formio/components/cosign-v2.test-d.ts new file mode 100644 index 0000000..acc2e68 --- /dev/null +++ b/test-d/formio/components/cosign-v2.test-d.ts @@ -0,0 +1,125 @@ +import {expectAssignable, expectNotAssignable} from 'tsd'; + +import {CosignV2ComponentSchema} from '../../../lib/'; + +// minimal cosign component schema +expectAssignable({ + id: 'yejak', + type: 'cosign', + validateOn: 'blur', + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', +}); + +// full, correct schema +expectAssignable({ + id: 'yejak', + type: 'cosign', + validateOn: 'blur', + // basic tab in builder form + label: 'Some cosign', + key: 'someCoSign', + description: 'A description', + tooltip: 'A tooltip', + authPlugin: 'oidc-digid', + showInSummary: true, + showInEmail: false, + showInPDF: true, + hidden: false, + clearOnHide: true, + isSensitiveData: true, + defaultValue: '', + autocomplete: 'email', + // advanced tab in builder form + conditional: { + show: undefined, + when: undefined, + eq: undefined, + }, + // validation tab in builder form + validate: { + required: false, + plugins: undefined, + }, + translatedErrors: { + nl: { + required: 'Je moet een waarde opgeven!!!', + }, + }, + errors: { + // translatedErrors is converted into errors by the backend + required: 'Je moet een waarde opgeven!!!', + }, + // translations tab in builder form + openForms: { + translations: { + nl: { + label: 'foo', + description: 'bar', + tooltip: 'baz', + }, + }, + }, +}); + +// different component type +expectNotAssignable({ + type: 'fieldset' as const, +}); + +// using unsupported properties +expectNotAssignable({ + id: 'yejak', + type: 'cosign' as const, + validateOn: 'blur' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + hideLabel: true, +}); + +// multiple is not supported +expectNotAssignable({ + id: 'yejak', + type: 'cosign' as const, + validateOn: 'blur' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + multiple: true as boolean, +}); +expectNotAssignable({ + id: 'yejak', + type: 'cosign' as const, + validateOn: 'blur' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + defaultValue: [], +}); + +// while it shares functionality with email, we should not be able to use all +// email extensions +expectNotAssignable({ + id: 'yejak', + type: 'cosign' as const, + validateOn: 'blur' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + confirmationRecipient: true, +}); + +// registration attributes are not supported +expectNotAssignable({ + id: 'yejak', + type: 'cosign' as const, + validateOn: 'blur' as const, + key: 'someCoSign', + label: 'Some cosign', + authPlugin: 'digid', + registration: { + attribute: 'foo', + }, +});