File Management
In Back-Kit library upload and management of files related to records is handled by three components that interact together:
- File Service Client
- File Manager
- a data manipulation component that allows to interact with file fields, for instance:
These components are designed to interact with Mia Platform's Files Service, particularly the File Service Client operates as a client for the service.
File Fields
In addition to acting as a file storage service, the Files Service manages a collection of the CRUD Service, where metadata related to file storage is stored.\ A typical CRUD Service collection associated with a Files Service would include fields like:
{
"_id": {
"type": "string"
},
"name": {
"type": "string"
},
"file": {
"type": "string"
},
"size": {
"type": "number"
},
"location": {
"type": "string"
}
}
Back-Kit components that handle data from CRUD Service collections and interact with file fields expect values of file fields to be in an object (or an array of objects) following the schema mentioned above.
File properties can be specified in the data schema as:
{
"type": "object",
"format": "file"
}
or
{
"type": "array",
"format": "file"
}
File Upload with a Back-Kit Action
It is possible to upload a file using a Back-Kit Action of type file-upload
.
This enables the user to pick a file from the local file system through the native upload dialog of the browser,
which is injected in the body of a POST
called using XMLHTTPRequest facility.
Any component that implement the Back-Kit Action
interface, for instance the Button component, can be configured to perform a file-upload
action.
Configuring the file-upload
action to call the endpoint of a Files Service is possible.
An example is available in which the Gallery is used in conjunction with the Button to visualize the CRUD Service collection linked to a Files Service instance.
File Upload with form components
Once a file property is specified in the data schema and its form field is modified (e.g., using a Dynamic Form Drawer), the following routine is followed:
- The Dynamic Form Drawer notifies that a data item should be created/updated containing file fields (i.e., triggers a create-data-with-file or an update-data-with-file event). The emitted event provides information on which fields include files that should be uploaded.
- The File Manager handles the above event and requests the upload of each file to a storage service by firing an upload-file event for each file.
- The File Service Client processes the
upload-file
event by making HTTP calls to the Files Service to request the storage of the files. Upon success, the Files Service provides a response containing storage metadata about the newly uploaded file. The File Service Client then fires an uploaded-file event, containing this metadata. - The File Manager listens for
uploaded-file
events and maintains a copy of the data item created or updated by the Dynamic Form Drawer in step 1, replacing the values of file fields with the returned storage metadata information. - Once all files have been uploaded and the data item has been appropriately updated, the File Manager proceeds to request data creation/update by emitting a create-data or an update-data event. The payload sent in this event contains the fully edited data items, ensuring that the file fields now include the file storage metadata provided in step 3 instead of the actual file.
The process is exemplified below.
Upon failure while uploading one file, any new file that was being uploaded in the same transaction will be deleted, even if already uploaded, since the final create/update of the record will not be performed
By design, any file that is unlinked from the record when updating an entry, isn't deleted from the file-service
Custom Metadata
File fields may present a data-schema. This is used to describe the fields that are included in the field, and allows to specify custom fields other than the default storage metadata information.
Components like the Form Dynamic Drawer, the Form Dynamic Modal, the File Picker Drawer, the File Picker Modal allow to visualize and edit metadata fields of type string.
{
"type": "object",
"format": "file",
"dataSchema": {
"type": "object",
"properties": {
"ownerId": {
"type": "string"
}
}
}
}
{
"type": "array",
"format": "file",
"items": {
"type": "object",
"properties": {
"ownerId": {
"type": "string"
}
}
}
}
Examples
Example: Upload a file using form components
Assuming a plugin to include the following components:
{
"tag": "bk-dynamic-form-drawer",
"properties": {
"dataSchema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"image": {
"type": "object",
"format": "file"
}
}
}
}
}{
"tag": "bk-file-manager"
}a File Service Client like
{
"tag": "bk-file-client",
"properties": {
"basePath": "/files",
"dataSchema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"image": {
"type": "object",
"format": "file"
}
}
}
}
}a CRUD Client like
{
"tag": "bk-crud-client",
"properties": {
"basePath": "/v2/customers",
"dataSchema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"image": {
"type": "object",
"format": "file"
}
}
}
}
}
The Dynamic Form Drawer allows the user to request the creation of a new data item, specifying values for fields "name" and "image". Upon submission, it emits an create-data-with-file event.\ The payload of such event could look like:
{
"name": "Alexander",
"image": ... // profile.jpg
}
Field "image" stores the a File object uploaded by the user.
The meta of the event:
{
"property": "image"
}
indicating what property within the event payload includes the file to upload to a storage service.
The File Manager listens to the event, retrieves the file to upload using the event payload and meta, and fires an upload-file event with payload like:
{
"file": ... // profile.jpg
}
signaling the need to upload the file to a storage service.
The File Service Client handles upload-file
events, and consequently performs HTTP requests to a backend instance of Mia Platform's Files Service.
Following up on the example, the File Service Client emits a POST call to the endpoint "/files" (as specified in the basePath
property)
with a multipart body that includes the file to upload, like:
------WebKitFormBoundary5gRZNaxFPGnBKUaI
Content-Disposition: form-data; name="file"; filename="profile.jpg"
Content-Type: image/jpg
------WebKitFormBoundary5gRZNaxFPGnBKUaI--
Assuming the POST to be successful and the Files Service to respond with the storage metadata of the uploaded file, then the File Service Client notifies the correct upload of the file by emitting an uploaded-file event, injecting the received response in its payload, like:
{
"_id": "fileId7212704772008143",
"file": "profile.jpg",
"location": "/v2/files/download/profile.jpg",
"name": "profile.jpg",
"size": 3992
}
The File Manager listens to the uploaded-file
event, using its payload to update the content of the received data from the initial create-data-with-file
event.\
The resulting object is injected in the payload of an create-data event, like:
{
"name": "Alexander",
"image": {
"_id": "fileId7212704772008143",
"file": "profile.jpg",
"location": "/v2/files/download/profile.jpg",
"name": "profile.jpg",
"size": 3992
}
}
The CRUD Client listens to such an event, triggering a POST call to be performed to the CRUD Service, requesting the creation of the data item.
Example: Visualize Files
It is possible to visualize the CRUD Service collection of image files linked to a Files Service instance using a Gallery, a CRUD Client, and a Button.
Assuming the Files Service to be reachable at "/files" and the CRUD Service collection to be:
{
"_id": {
"type": "string"
},
"name": {
"type": "string"
},
"file": {
"type": "string"
},
"size": {
"type": "number"
},
"location": {
"type": "string"
}
}
And the components to be configured like:
Gallery:
{
"tag": "bk-gallery",
"properties": {
"thumbnailSource": "location",
"titleSource": "name",
"subTitleSource": "file"
}
}CRUD Client:
{
"tag": "bk-crud-client",
"properties": {
"basePath": "/files",
"dataSchema": {
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"name": {
"type": "string"
},
"file": {
"type": "string"
},
"size": {
"type": "number"
},
"location": {
"type": "string"
}
}
}
}
}Button:
{
"tag": "bk-button",
"properties": {
"content": "Upload File",
"iconId": "UploadOutlined",
"action": {
"type": "file-upload",
"config": {
"url": "/files/"
}
}
}
}
The Gallery renders an item for each entry of the collection, retrieving the image source form the "location" field, and displaying the fields "name" and "file" in the footer.
The Button allows to perform a file upload operation towards "/files/". Doing so, the Files Service stores the file to a storage service, while adding a new entry to the CRUD Service collection.
The CRUD Client is included to fetch the items of the collection to visualize.
In order to automatically reload the plugin after uploading the file, an onSuccess
hook can be used to chain a page refresh upon successful file upload.
{
"tag": "bk-button",
"properties": {
"content": "Upload File",
"iconId": "UploadOutlined",
"action": {
"type": "file-upload",
"config": {
"url": "/files"
},
"hooks": {
"onSuccess": {
"type": "event",
"config": {
"events": "change-query"
}
}
}
}
}
}
Emitting an empty change-query event is equivalent to refreshing the page if the CRUD Client is included in the configuration.
To ensure that only image files can be uploaded by the user through the file-upload
action, field accept
is available. Property accept
follows the syntax that is used by the input
html-element.
{
"tag": "bk-button",
"properties": {
"content": "Upload File",
"iconId": "UploadOutlined",
"action": {
"type": "file-upload",
"config": {
"url": "/files",
"accept": "image/png, image/jpeg"
}
}
}
}