Skip to content

Commit

Permalink
✨ [#2] Define type for file component, pt. 1
Browse files Browse the repository at this point in the history
Mostly describes the base schema and how a single file upload looks
like, i.e. what data is chucked over the wire when submitting the
form.
  • Loading branch information
sergei-maertens committed Oct 16, 2023
1 parent c1179d0 commit 8c0537a
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/formio/components/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {DisplayConfig, HasValidation, OFExtensions, StrictComponentSchema} from '../base';

type UnusedFileProperties = 'hideLabel' | 'placeholder' | 'disabled' | 'widget' | 'validate';

type Validator = 'required';
type TranslatableKeys = 'label' | 'description' | 'tooltip';

/**
* Shape of a single file upload from Form.io to the backend.
*/
export interface FileUploadData {
data: {
/**
* Full backend URL of the uploaded file (API endpoint).
*
* The value appears to be identical to the root `url` key.
*/
url: string;
/**
* Does not seems to be set to a meaningful value.
*/
form: '';
/**
* File name of uploaded file.
*
* The value is different from the root `name` key.
*/
name: string;
/**
* File size in bytes, (positive) integer value.
*
* The value appears to be identical to the root `size` key.
*/
size: number;
/**
* Formio base URL configuration option, set to the root of our own API.
*/
baseUrl: string;
/**
* Does not seems to be set to a meaningful value.
*/
project: '';
};
name: string;
originalName: string;
/**
* File size in bytes, (positive) integer value.
*/
size: number;
/**
* We only support file uploads to a backend URL.
*/
storage: 'url';
/**
* MIME type, determined by the browser during upload. If the OS/browser doesn't know
* it, it seems to be an empty string (see https://github.com/open-formulieren/open-forms-sdk/
* blob/27877938249cdd627294871b70291ab8dc66fd61/src/formio/components/FileField.js#L279)
*/
type: string;
/**
* Full backend URL of the uploaded file (API endpoint).
*/
url: string;
}

/**
* @group Form.io components
* @category Base types
*/
export interface BaseFileComponentSchema
extends Omit<StrictComponentSchema<FileUploadData[]>, UnusedFileProperties | 'errors'>,
DisplayConfig,
OFExtensions<TranslatableKeys>,
HasValidation<Validator> {
type: 'file';
multiple?: boolean;
}

export type SingleFileComponentSchema = BaseFileComponentSchema & {
multiple?: false;
defaultValue?: [] | [FileUploadData];
};

export type MultipleFileComponentSchema = BaseFileComponentSchema & {
multiple: true;
defaultValue?: FileUploadData[];
};

/**
* @group Form.io components
* @category Concrete types
*
* Note that while `defaultValue` is defined here, this is only to be able to type
* define the submission data type. A file upload component cannot actually have
* default values.
*/
export type FileComponentSchema = SingleFileComponentSchema | MultipleFileComponentSchema;
1 change: 1 addition & 0 deletions src/formio/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './time';
export * from './phonenumber';
export * from './postcode';
export * from './number';
export * from './file';

// Layout components
export * from './content';
2 changes: 2 additions & 0 deletions src/formio/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DateComponentSchema,
DateTimeComponentSchema,
EmailComponentSchema,
FileComponentSchema,
NumberComponentSchema,
PhoneNumberComponentSchema,
PostcodeComponentSchema,
Expand Down Expand Up @@ -42,6 +43,7 @@ export type AnyComponentSchema =
| TimeComponentSchema
| PhoneNumberComponentSchema
| PostcodeComponentSchema
| FileComponentSchema
| NumberComponentSchema
// layout
| ContentComponentSchema;
Expand Down
66 changes: 66 additions & 0 deletions test-d/formio/components/file.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {expectAssignable, expectNotAssignable} from 'tsd';

import {FileComponentSchema, FileUploadData} from '../../../lib';

// Grabbed from test env file upload, URLs obfuscated.
const anUpload: FileUploadData = {
url: 'http://localhost:8000/api/v2/submissions/files/54cc40ed-f1c4-4206-ba76-76d376ba4c3a',
data: {
url: 'http://localhost:8000/api/v2/submissions/files/54cc40ed-f1c4-4206-ba76-76d376ba4c3a',
form: '',
name: 'maykin_logo.png',
size: 8725,
baseUrl: 'http://localhost:8000/api/v2/',
project: '',
},
name: 'maykin_logo-e0568045-45f6-46d1-909a-8895c5ee061e.png',
size: 8725,
type: 'image/png',
storage: 'url',
originalName: 'maykin_logo.png',
};

// minimal file component schema
expectAssignable<FileComponentSchema>({
id: 'yejak',
type: 'file',
key: 'someFile',
label: 'Attachment',
});

// Behaviour of single vs. multiple file uploads

const explicitSingleUpload: FileComponentSchema = {
id: 'yejak',
type: 'file',
key: 'someFile',
label: 'Attachment',
multiple: false,
};
type ExplicitSingleUploadValue = (typeof explicitSingleUpload)['defaultValue'];
expectAssignable<ExplicitSingleUploadValue>([]);
expectAssignable<ExplicitSingleUploadValue>([anUpload]);
expectNotAssignable<ExplicitSingleUploadValue>([anUpload, anUpload]);

const explicitMultipleUpload: FileComponentSchema = {
id: 'yejak',
type: 'file',
key: 'someFile',
label: 'Attachment',
multiple: true,
};
type ExplicitMultipleUploadValue = (typeof explicitMultipleUpload)['defaultValue'];
expectAssignable<ExplicitMultipleUploadValue>([]);
expectAssignable<ExplicitMultipleUploadValue>([anUpload]);
expectAssignable<ExplicitMultipleUploadValue>([anUpload, anUpload]);

const implicitSingleUpload: FileComponentSchema = {
id: 'yejak',
type: 'file',
key: 'someFile',
label: 'Attachment',
};
type ImplicitSingleUploadValue = (typeof implicitSingleUpload)['defaultValue'];
expectAssignable<ImplicitSingleUploadValue>([]);
expectAssignable<ImplicitSingleUploadValue>([anUpload]);
expectNotAssignable<ImplicitSingleUploadValue>([anUpload, anUpload]);

0 comments on commit 8c0537a

Please sign in to comment.