Skip to content

Commit

Permalink
Merge pull request #174 from open-formulieren/chore/remove-fallback-t…
Browse files Browse the repository at this point in the history
…ypes

Remove the low-level fallback handling
  • Loading branch information
sergei-maertens authored Aug 15, 2024
2 parents e049c28 + d76a52e commit 0b88686
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 144 deletions.
5 changes: 5 additions & 0 deletions i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,11 @@
"description": "Values table: accessible label to remove an option",
"originalDefault": "Remove"
},
"ISVTEk": {
"defaultMessage": "The component type <code>{type}</code> is unknown. We can only display the JSON definition.",
"description": "Informational message about unsupported component",
"originalDefault": "The component type <code>{type}</code> is unknown. We can only display the JSON definition."
},
"JDYF2q": {
"defaultMessage": "The data entered in this component will be removed in accordance with the privacy settings.",
"description": "Tooltip for 'IsSensitiveData' builder field",
Expand Down
5 changes: 5 additions & 0 deletions i18n/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@
"description": "Values table: accessible label to remove an option",
"originalDefault": "Remove"
},
"ISVTEk": {
"defaultMessage": "The component type <code>{type}</code> is unknown. We can only display the JSON definition.",
"description": "Informational message about unsupported component",
"originalDefault": "The component type <code>{type}</code> is unknown. We can only display the JSON definition."
},
"JDYF2q": {
"defaultMessage": "Gegevens opgevoerd in dit component worden geschoond volgens de privacy-instellingen.",
"description": "Tooltip for 'IsSensitiveData' builder field",
Expand Down
19 changes: 19 additions & 0 deletions src/components/ComponentConfiguration.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,25 @@ export const Default: Story = {
},
};

export const UnsupportedComponent: Story = {
render: Template,
name: 'invalid/unsupported component type',

args: {
component: {
// @ts-expect-error
type: 'an-invalid-type',
},
builderInfo: {
title: 'invalid',
group: 'basic',
icon: 'terminal',
schema: {placeholder: ''},
weight: 0,
},
},
};

export const TextField: Story = {
render: Template,
name: 'type: textfield',
Expand Down
95 changes: 67 additions & 28 deletions src/components/ComponentConfiguration.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import {JSONEditor} from '@open-formulieren/monaco-json-editor';
import {FallbackSchema} from '@open-formulieren/types';
import {FormattedMessage} from 'react-intl';

import {BuilderContext, BuilderContextType} from '@/context';
import {isKnownComponentType} from '@/registry';

import ComponentEditForm, {ComponentEditFormProps} from './ComponentEditForm';

export interface ComponentConfigurationProps extends BuilderContextType, ComponentEditFormProps {}
type MergedProps = BuilderContextType & ComponentEditFormProps;
export type ComponentConfigurationProps = Omit<MergedProps, 'component'> & {
component: MergedProps['component'] | FallbackSchema;
};

/**
* The main entrypoint to edit a component in the builder modal.
Expand Down Expand Up @@ -42,34 +50,65 @@ const ComponentConfiguration: React.FC<ComponentConfigurationProps> = ({
onCancel,
onRemove,
onSubmit,
}) => (
<BuilderContext.Provider
value={{
uniquifyKey,
supportedLanguageCodes,
richTextColors,
theme,
getFormComponents,
getValidatorPlugins,
getRegistrationAttributes,
getPrefillPlugins,
getPrefillAttributes,
getFileTypes,
serverUploadLimit,
getDocumentTypes,
getConfidentialityLevels,
getAuthPlugins,
}}
>
<ComponentEditForm
isNew={isNew}
component={component}
builderInfo={builderInfo}
onCancel={onCancel}
onRemove={onRemove}
onSubmit={onSubmit}
}) => {
if (!isKnownComponentType(component)) {
return <Fallback theme={theme} component={component} />;
}
return (
<BuilderContext.Provider
value={{
uniquifyKey,
supportedLanguageCodes,
richTextColors,
theme,
getFormComponents,
getValidatorPlugins,
getRegistrationAttributes,
getPrefillPlugins,
getPrefillAttributes,
getFileTypes,
serverUploadLimit,
getDocumentTypes,
getConfidentialityLevels,
getAuthPlugins,
}}
>
<ComponentEditForm
isNew={isNew}
component={component}
builderInfo={builderInfo}
onCancel={onCancel}
onRemove={onRemove}
onSubmit={onSubmit}
/>
</BuilderContext.Provider>
);
};

interface FallbackProps {
component: FallbackSchema;
theme: BuilderContextType['theme'];
}

const Fallback: React.FC<FallbackProps> = ({component, theme}) => (
<>
<FormattedMessage
tagName="p"
description="Informational message about unsupported component"
defaultMessage="The component type <code>{type}</code> is unknown. We can only display the JSON definition."
values={{
type: component.type ?? '-',
code: chunks => <code>{chunks}</code>,
}}
/>
<JSONEditor
wrapperProps={{className: 'json-editor'}}
value={component}
onChange={() => alert('Editing is not possible in unknown components.')}
theme={theme}
readOnly
/>
</BuilderContext.Provider>
</>
);

export default ComponentConfiguration;
29 changes: 9 additions & 20 deletions src/components/ComponentEditForm.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {AnyComponentSchema} from '@open-formulieren/types';
import {Form, Formik} from 'formik';
import {ExtendedComponentSchema} from 'formiojs/types/components/schema';
import {cloneDeep, merge} from 'lodash';
Expand All @@ -6,8 +7,7 @@ import {FormattedMessage, useIntl} from 'react-intl';
import {toFormikValidationSchema} from 'zod-formik-adapter';

import {BuilderContext} from '@/context';
import {Fallback, getRegistryEntry, isKnownComponentType} from '@/registry';
import {AnyComponentSchema, FallbackSchema} from '@/types';
import {getRegistryEntry} from '@/registry';

import GenericComponentPreview from './ComponentPreview';

Expand All @@ -22,13 +22,11 @@ export interface BuilderInfo {

export interface ComponentEditFormProps {
isNew: boolean;
// it is (currently) possible someone drags a component type into the canvas that we
// don't know (yet), so we need to handle FallbackSchema.
component: AnyComponentSchema | FallbackSchema;
component: AnyComponentSchema;
builderInfo: BuilderInfo;
onCancel: (e: React.MouseEvent<HTMLButtonElement>) => void;
onRemove: (e: React.MouseEvent<HTMLButtonElement>) => void;
onSubmit: (component: AnyComponentSchema | FallbackSchema) => void;
onSubmit: (component: AnyComponentSchema) => void;
}

type ButtonRowProps = Pick<ComponentEditFormProps, 'onCancel' | 'onRemove'> & {
Expand Down Expand Up @@ -76,7 +74,7 @@ const ComponentEditForm: React.FC<ComponentEditFormProps> = ({
const hasPreview = registryEntry.preview !== null;

let initialValues = cloneDeep(component);
if (isNew && isKnownComponentType(component)) {
if (isNew) {
// Formio.js mutates components when adding children (like fieldset layout component),
// which apparently goes all the way to our default value definition, which is
// supposed to be static.
Expand All @@ -86,17 +84,12 @@ const ComponentEditForm: React.FC<ComponentEditFormProps> = ({
initialValues = merge(defaultValues, initialValues);
}

// we infer the specific schema from the EditForm component obtained from the registry.
// This gives a specific schema rather than AnyComponentSchema and allows us to type
// check the values accordingly.
type ComponentSchema = React.ComponentProps<typeof EditForm>['component'];

const Wrapper = hasPreview ? LayoutWithPreview : LayoutWithoutPreview;

// Markup (mostly) taken from formio's default templates - there's room for improvement here
// to de-bootstrapify it.
return (
<Formik<ComponentSchema>
<Formik<typeof component>
validateOnChange={false}
validateOnBlur
initialValues={initialValues}
Expand Down Expand Up @@ -148,11 +141,7 @@ const ComponentEditForm: React.FC<ComponentEditFormProps> = ({
<div className="formio-component formio-component-label-hidden">
<div className="formio-form">
<div className="formio-component-tabs">
{isKnownComponentType(component) ? (
<EditForm component={component} />
) : (
<Fallback.edit component={component} />
)}
<EditForm component={component} />
</div>
</div>
</div>
Expand All @@ -175,8 +164,8 @@ const ComponentEditForm: React.FC<ComponentEditFormProps> = ({
type EditFormLayoutProps = PropsWithChildren<
Pick<ComponentEditFormProps, 'onCancel' | 'onRemove'> & {
onSubmit: () => void;
onComponentChange: (value: AnyComponentSchema | FallbackSchema) => void;
component: AnyComponentSchema | FallbackSchema;
onComponentChange: (value: AnyComponentSchema) => void;
component: AnyComponentSchema;
}
>;

Expand Down
34 changes: 2 additions & 32 deletions src/components/ComponentPreview.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,6 @@ const Template: StoryFn<typeof ComponentPreview> = ({component}) => (
<ComponentPreview onComponentChange={fn()} component={component} />
);

export const Default: Story = {
render: Template,

args: {
component: {
id: 'foo',
type: 'textfield',
label: 'A text field',
validate: {
required: false,
},
},
},
};

export const Fallback: Story = {
render: Template,

args: {
component: {
id: 'fallback',
// should never accidentally be an actual type
type: '85230383-896e-40ce-a1a9-35a090b73f17',
} as any,
},

play: async ({canvasElement}) => {
const canvas = within(canvasElement);
await canvas.findByTestId('jsonPreview');
},
};

export const TextField: Story = {
render: Template,

Expand Down Expand Up @@ -141,6 +109,7 @@ export const Email: Story = {
label: 'Email preview',
description: 'A preview of the email Formio component',
hidden: true, // must be ignored
validateOn: 'blur',
},
},

Expand Down Expand Up @@ -174,6 +143,7 @@ export const EmailMultiple: Story = {
description: 'Description only once',
hidden: true, // must be ignored
multiple: true,
validateOn: 'blur',
},
},

Expand Down
20 changes: 8 additions & 12 deletions src/components/ComponentPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import React, {useContext, useState} from 'react';
import {FormattedMessage} from 'react-intl';

import {BuilderContext} from '@/context';
import {Fallback, getRegistryEntry, isKnownComponentType} from '@/registry';
import {AnyComponentSchema, FallbackSchema, hasOwnProperty} from '@/types';
import {getRegistryEntry} from '@/registry';
import {AnyComponentSchema, hasOwnProperty} from '@/types';

/*
Generic preview (preview + wrapper with view mode)
*/

export interface ComponentPreviewWrapperProps {
component: AnyComponentSchema | FallbackSchema;
component: AnyComponentSchema;
/** Initial values for the preview component, e.g. `{"componentKey": "some_value"}` */
initialValues: Record<string, unknown>;
/** Handler to be called when the component JSON definition changes */
onComponentChange: (value: AnyComponentSchema | FallbackSchema) => void;
onComponentChange: (value: AnyComponentSchema) => void;
children: React.ReactNode;
}

Expand Down Expand Up @@ -69,8 +69,8 @@ const ComponentPreviewWrapper: React.FC<ComponentPreviewWrapperProps> = ({
};

export interface GenericComponentPreviewProps {
component: AnyComponentSchema | FallbackSchema;
onComponentChange: (value: AnyComponentSchema | FallbackSchema) => void;
component: AnyComponentSchema;
onComponentChange: (value: AnyComponentSchema) => void;
}

/**
Expand All @@ -86,7 +86,7 @@ const GenericComponentPreview: React.FC<GenericComponentPreviewProps> = ({
component,
onComponentChange,
}) => {
const key = isKnownComponentType(component) ? component.key : '';
const {key} = component;
const entry = getRegistryEntry(component);
const {preview: PreviewComponent, defaultValue = ''} = entry;
if (PreviewComponent === null) {
Expand All @@ -109,11 +109,7 @@ const GenericComponentPreview: React.FC<GenericComponentPreviewProps> = ({
component={component}
initialValues={initialValues}
>
{isKnownComponentType(component) ? (
<PreviewComponent component={component} />
) : (
<Fallback.preview component={component} />
)}
<PreviewComponent component={component} />
</ComponentPreviewWrapper>
);
};
Expand Down
Loading

0 comments on commit 0b88686

Please sign in to comment.