Skip to content

Commit

Permalink
✨ Implement file tab of file component edit form
Browse files Browse the repository at this point in the history
* Expose file types from context - the backend needs to feed the
  list of possible options to the builder.
* Extend decorators and stories to handle (default) file types
* Add file name template field
* Add file type (multi) select
* Add 'use global config file types' checkbox
* Add 'maxFileSize' textbox
* Add 'maxNumberOfFiles' number field

The input validation is added as todo for a separate commit.
  • Loading branch information
sergei-maertens committed Oct 25, 2023
1 parent 29247f8 commit 408e1aa
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 7 deletions.
79 changes: 79 additions & 0 deletions .storybook/decorators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,79 @@ const DEFAULT_PREFILL_ATTRIBUTES: {[key: string]: PrefillAttributeOption[]} = {
],
};

export const DEFAULT_FILE_TYPES = [
{
label: 'any filetype',
value: '*',
},
{
label: '.heic',
value: 'image/heic',
},
{
label: '.png',
value: 'image/png',
},
{
label: '.jpg',
value: 'image/jpeg',
},
{
label: '.pdf',
value: 'application/pdf',
},
{
label: '.xls',
value: 'application/vnd.ms-excel',
},
{
label: '.xlsx',
value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
},
{
label: '.csv',
value: 'text/csv',
},
{
label: '.txt',
value: 'text/plain',
},
{
label: '.doc',
value: 'application/msword',
},
{
label: '.docx',
value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
},
{
label: 'Open Office',
value:
'application/vnd.oasis.opendocument.*,application/vnd.stardivision.*,application/vnd.sun.xml.*',
},
{
label: '.zip',
value: 'application/zip',
},
{
label: '.rar',
value: 'application/vnd.rar',
},
{
label: '.tar',
value: 'application/x-tar',
},
{
label: '.msg',
value: 'application/vnd.ms-outlook',
},
{
label: '.dwg',
value:
'application/acad.dwg,application/autocad_dwg.dwg,application/dwg.dwg,application/x-acad.dwg,application/x-autocad.dwg,application/x-dwg.dwg,drawing/dwg.dwg,image/vnd.dwg,image/x-dwg.dwg',
},
];

function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Expand All @@ -86,6 +159,8 @@ export const BuilderContextDecorator = (Story: StoryFn, context: StoryContext) =
context.parameters.builder?.defaultPrefillPlugins || DEFAULT_PREFILL_PLUGINS;
const defaultPrefillAttributes =
context.parameters.builder?.defaultPrefillAttributes || DEFAULT_PREFILL_ATTRIBUTES;
const defaultFileTypes = context.parameters.builder?.defaultFileTypes || DEFAULT_FILE_TYPES;

return (
<BuilderContext.Provider
value={{
Expand All @@ -110,6 +185,10 @@ export const BuilderContextDecorator = (Story: StoryFn, context: StoryContext) =
const container = context?.args?.prefillAttributes || defaultPrefillAttributes;
return container?.[plugin] || [{id: '', label: 'no plugins found'}];
},
getFileTypes: async () => {
return context?.args?.fileTypes || defaultFileTypes;
},
serverUploadLimit: '50MB',
}}
>
<Story />
Expand Down
12 changes: 12 additions & 0 deletions src/components/ComponentConfiguration.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Meta, StoryFn, StoryObj} from '@storybook/react';
import {fireEvent, userEvent, waitFor, within} from '@storybook/testing-library';
import React from 'react';

import {DEFAULT_FILE_TYPES} from '@/../.storybook/decorators';
import {AnyComponentSchema} from '@/types';

import ComponentConfiguration from './ComponentConfiguration';
Expand Down Expand Up @@ -50,6 +51,7 @@ export default {
],
},
supportedLanguageCodes: ['nl'],
fileTypes: DEFAULT_FILE_TYPES,
translationsStore: {
nl: {
'A select': 'Een dropdown',
Expand Down Expand Up @@ -79,6 +81,7 @@ interface TemplateArgs {
registrationAttributes: RegistrationAttributeOption[];
prefillPlugins: PrefillPluginOption[];
prefillAttributes: Record<string, PrefillAttributeOption[]>;
fileTypes: Array<{value: string; label: string}>;
isNew: boolean;
builderInfo: BuilderInfo;
onCancel: (e: React.MouseEvent<HTMLButtonElement>) => void;
Expand All @@ -95,6 +98,7 @@ const Template: StoryFn<TemplateArgs> = ({
prefillAttributes,
supportedLanguageCodes,
translationsStore,
fileTypes,
isNew,
builderInfo,
onCancel,
Expand All @@ -110,6 +114,8 @@ const Template: StoryFn<TemplateArgs> = ({
getRegistrationAttributes={async () => registrationAttributes}
getPrefillPlugins={async () => prefillPlugins}
getPrefillAttributes={async (plugin: string) => prefillAttributes[plugin]}
getFileTypes={async () => fileTypes}
serverUploadLimit="50MB"
component={component}
isNew={isNew}
builderInfo={builderInfo}
Expand Down Expand Up @@ -785,4 +791,10 @@ export const FileUpload: Story = {
schema: {},
},
},

play: async ({canvasElement}) => {
const canvas = within(canvasElement);

await userEvent.click(canvas.getByRole('link', {name: 'File'}));
},
};
4 changes: 4 additions & 0 deletions src/components/ComponentConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const ComponentConfiguration: React.FC<ComponentConfigurationProps> = ({
getRegistrationAttributes,
getPrefillPlugins,
getPrefillAttributes,
getFileTypes,
serverUploadLimit,
isNew,
component,
builderInfo,
Expand All @@ -48,6 +50,8 @@ const ComponentConfiguration: React.FC<ComponentConfigurationProps> = ({
getRegistrationAttributes,
getPrefillPlugins,
getPrefillAttributes,
getFileTypes,
serverUploadLimit,
}}
>
<ComponentEditForm
Expand Down
2 changes: 1 addition & 1 deletion src/components/formio/description.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
interface DescriptionProps {
text: string;
text: React.ReactNode;
}

const Description: React.FC<DescriptionProps> = ({text}) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/formio/multiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Description from './description';
*/
export interface CommonInputProps extends ComponentLabelProps {
name: string;
description?: string;
description?: React.ReactNode;
}

export interface MultipleProps<P extends {}, T extends unknown> {
Expand Down
2 changes: 1 addition & 1 deletion src/components/formio/textfield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface TextFieldProps {
label?: React.ReactNode;
required?: boolean;
tooltip?: string;
description?: string;
description?: React.ReactNode;
showCharCount?: boolean;
inputMask?: string;
}
Expand Down
9 changes: 9 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ export interface BuilderContextType {
getRegistrationAttributes: (componentType: string) => Promise<RegistrationAttributeOption[]>;
getPrefillPlugins: (componentType: string) => Promise<PrefillPluginOption[]>;
getPrefillAttributes: (plugin: string) => Promise<PrefillAttributeOption[]>;
getFileTypes: () => Promise<
Array<{
value: string;
label: string;
}>
>;
serverUploadLimit: string;
}

const BuilderContext = React.createContext<BuilderContextType>({
Expand All @@ -46,6 +53,8 @@ const BuilderContext = React.createContext<BuilderContextType>({
getRegistrationAttributes: async () => [],
getPrefillPlugins: async () => [],
getPrefillAttributes: async () => [],
getFileTypes: async () => [],
serverUploadLimit: '(unknown)',
});

BuilderContext.displayName = 'BuilderContext';
Expand Down
9 changes: 9 additions & 0 deletions src/registry/file/edit-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import {IntlShape} from 'react-intl';

import {buildCommonSchema} from '@/registry/validation';

/**
* @todo implement validations:
*
* - fileMaxSize must be int (bytes) or int(K|M)B (?) -> check how fileMaxSize is
* handled in the backend, if at all.
* - validate fileMaxSize <= serverUploadLimit from context, if set.
* - maxNumberOfFiles must be positive integer
*/

const schema = (intl: IntlShape) => buildCommonSchema(intl);

export default schema;
20 changes: 16 additions & 4 deletions src/registry/file/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import {
useDeriveComponentKey,
} from '@/components/builder';
import {LABELS} from '@/components/builder/messages';
import {Checkbox, Tab, TabList, TabPanel, Tabs, TextField} from '@/components/formio';
import {Tab, TabList, TabPanel, Tabs} from '@/components/formio';
import {getErrorNames} from '@/utils/errors';

import {EditFormDefinition} from '../types';
import FileTabFields from './file-tab';

/**
* Form to configure a Formio 'file' type component.
Expand Down Expand Up @@ -65,7 +66,9 @@ const EditForm: EditFormDefinition<FileComponentSchema> = () => {
/>
<BuilderTabs.Advanced hasErrors={hasAnyError('conditional')} />
<BuilderTabs.Validation hasErrors={hasAnyError('validate')} />
<Tab hasErrors={hasAnyError('file')}>
<Tab
hasErrors={hasAnyError('file', 'useConfigFiletypes', 'fileMaxSize', 'maxNumberOfFiles')}
>
<FormattedMessage
description="Component edit form tab title for 'File' tab"
defaultMessage="File"
Expand Down Expand Up @@ -100,7 +103,9 @@ const EditForm: EditFormDefinition<FileComponentSchema> = () => {
</TabPanel>

{/* File tab */}
<TabPanel></TabPanel>
<TabPanel>
<FileTabFields />
</TabPanel>

{/* Registration tab */}
<TabPanel>TODO</TabPanel>
Expand All @@ -119,9 +124,15 @@ const EditForm: EditFormDefinition<FileComponentSchema> = () => {
);
};

/**
*
* @todo options.withCredentials: true seems to be set somewhere -> session cookie
* needs to be sent by the SDK/client!
*/
EditForm.defaultValues = {
storage: 'url',
url: '',

// basic tab
label: '',
key: '',
Expand Down Expand Up @@ -151,7 +162,8 @@ EditForm.defaultValues = {
type: [],
allowedTypesLabels: [],
},
filePattern: '',
filePattern: '*',
useConfigFiletypes: false,
// registration tab
registration: {
informatieobjecttype: '',
Expand Down
Loading

0 comments on commit 408e1aa

Please sign in to comment.