React components
For the new React environment, a new viewdata is expected from the frontend based on the information gathered by the viewdata used previously in MIB Components (Default and Custom). By mapping the viewdata into new structures, both older MIB versions zero-impact requirements and React frontend requirements are met.
New structures
The new expected viewdata divides the information into two sibling structures: Schema and Data.
- Schema: Metadata information, such as mediatypes, field information (column name, field name, type, options for selection), etc.
- Data: Item information, such as the values for each field of a given item (single item for a form, multiple items for a list).
Requirements
To achieve the requirements for the new React frontend, components need to implement a new interface called IRenderableComponentV2, available and already being applied on some MIB default components.
public interface IRenderableComponentV2<TConfiguration, TData, TSchema> : IComponent<TConfiguration> where TConfiguration : IComponentConfiguration
{
Task<TData> MapData(object viewData, CancellationToken cancellationToken);
Task<TSchema> MapSchema(object viewData, CancellationToken cancellationToken);
}
- TConfiguration: May be the same configuration class already used by the component.
- TData: A new class containing only Data related information for the component.
- TSchema: A new class containing only Schema related information for the component.
- MapData and MapSchema: Both methods receive the current viewData for the component and map the related information to the new classes. This process is managed via reflection in DisplayWorkflow.
Schema and Data definition
These classes have different definitions depending on the component, as the form is responsible for the information about one item only and the list shows more than one item, for example.
The required information depends upon and have to be decided with the frontend team for both default and custom components.
Examples
Default List Schema
{
"columns": [
{
"editionField": {
"variant": string,
"config": {
"name": string,
"fieldType": string
},
"props": {
}
},
"renderConfig": {
"type": string,
"displayProperty": string
},
"disabledHide": boolean,
"sorter": boolean,
"hidden": boolean,
"defaultHidden": boolean,
"defaultOrder": int,
"title": string,
"dataIndex": string
}
],
"mediaType": string,
"filters": [
{
"mediaType": {
"value": string,
"label": string
},
"fields": [
{
"variant": string,
"config": {
"value": string,
"label": string,
"operators": [
{
"value": string,
"label": string
}
]
}
}
]
}
],
"formPageKey": string,
"configuration": {
"addNew": boolean,
"editable": boolean
},
"name": string
}
columns
An array containing all the schema information for each column of the list.
editionField
Field information required when fields are editable, how they are and must be perceived by the frontend.
variant
Variants are how admfield types are perceived by the frontend, based on antdesign components.
| AdmField Type | variant |
|---|---|
| Boolean | switch |
| Date | date |
| DateTime | date |
| UtcDateTime | date |
| Keyword | select |
| Enum | select |
| DropRelated | select |
| NullableDropRelated | select |
| Image | related |
| Related | related |
| Long | number |
| Float | number |
| Integer | number |
| Owner | user-selector |
| Password | password |
| PasswordPlain | password |
| Progress | slider |
| Source | tree-select |
| Html | textarea |
| Text | textarea |
| Time | time |
| Varchar | input |
| RowVersion | input |
| Hidden | input |
| Ipv4 | input |
| Link | input |
| OsTimezone | input |
Any other type is treated as an input variant.
props
Properties that varies depending on the admfield type.
| AdmField Type | props |
|---|---|
| Enum | SelectionOptions: all the selection options |
| DropRelated, Related, NullableDropRelated and Image | SelectionOptions: all the selection options, RelatedMediaType: related MediaType name, RelatedColumn: related column name and HasFile: set if there is a file appended to the item |
| Source | TreeViewItem: tree structure for showing the items |
| Keyword | Mode (set as "tags") and TokenSeparators: which separator must be used for different keywords |
| DateTime and UtcDateTime | ShowTime: if time must be shown or not |
| Others | Dictionary<string, string> |
disabledHide
Disable/enable hide function for the column.
sorter
Enable/disable sort function for the column.
hidden
Sets if column is visible.
defaultHidden
Sets if column is hidden by default.
defaultOrder
Sets column order.
title
Sets column title.
dataIndex
Sets column name.
mediaType
Sets the mediatype of the list.
filters
An array of mediatypes and filters for each mediatype available for the list. The value and label for config are the columnName and name for each field.
formPageKey
The edit page pagekey to which this list goes to when an item is selected.
configuration
Defines actions for the list page, such as being able to create a new item (opening the edit page), or editing an existing item on the list.
name
Name of the component.
Default List Data
{
"items": [
{
"id": 17378,
"fields": {
"ID": "17378",
"ENUM2": {
"id": 0,
"title": "Video2.0",
"value": "Video2.0"
},
"NULLABLEDROPRELATED": {
"id": 1,
"title": "Um",
"value": "1"
},
"related_fk_teste": "12",
"KEYWORDS": "key1,key2",
"UTCDATETIME": "2024/03/12 15:17:33",
"IPV4": "127.0.0.1",
"INTEGER": "10000",
"OWNER": {
"label": "Administrator",
"image": "http://environment/samples/profileimages/7B7BC2512EE1FEDC.jpeg",
"value": "1"
},
"NAME": "newName"
},
"permissions": {
"create": false,
"edit": true,
"remove": true,
"read": true
},
"checksum": "G6qzhrHa5JrXC4kENFjbzg"
}
],
"total": 826
}
fields
Field information is organized in a key/value pattern, where the key is the column name of the field. For fields with related-like behavior (such as enum, drop related, image, etc) some more information is required in the value due to the way the information is rendered by the frontend.
permissions
User permissions for this item.
checksum
Frontend name for etag.
total
Total number of items in the list, used by pagination.
Default Form Schema
{
"mediaType": string,
"fields": [
{
"variant": string,
"config": {
"label": string,
"name": string,
"rules": []
},
"props": {
"disabled": boolean
}
}
],
"title": string,
"configuration": {
"download": boolean,
"preview": boolean
}
}
fields
Description of each field of the form.
rules
May have a "required" boolean property for required fields, or "ipv4" boolean property for ipv4 fields.
configuration
Describes if the form has some actions such as download and/or preview buttons.
Default Form Data
{
"id": 18379,
"fields": {
"ENUM2": {
"id": 0,
"title": "",
"value": ""
},
"NULLABLEDROPRELATED": {
"id": 1,
"title": "Um",
"value": "1"
},
"IMAGE_FIELD": {
"src": "storage/IMAGES/00/00/02/21073_1397A3B5C8807100.gif",
"alt": "image - icoArrowRight.gif",
"title": "image - icoArrowRight.gif",
"id": 21073,
"value": "21073"
},
"RELATED_CUSTOM_ENUM": {
"id": 1,
"title": "TEF",
"value": "1"
},
"FLOAT_MONEY": null,
"ROWVERSION": 26002,
"OSTIMEZONE": "Hawaiian Standard Time",
"UTCDATETIME": "2022-06-10T16:50:00.000Z",
"IPV4": "200.137.0.1",
"HIDDEN": "** sorry, can't serialize secret properties **",
"TIME": "10:31:00",
"LINK": "http://terra.com.br",
"PASSWORDPLAIN": "** sorry, can't serialize secret properties **",
"DROPRELATED": {
"id": 1004,
"title": "PERSONAL_CORE_DISTRIBUTORS",
"value": "1004"
},
"FLOAT": null,
"LONG": 6541651651651652000,
"BOOLEAN": false,
"PASSWORD": "** sorry, can't serialize secret properties **",
"RELATED": {
"id": 20515,
"title": "mmedias/20515/{testName} {identifier}",
"value": "20515"
},
"ENUM": {
"id": 0,
"title": "Image",
"value": "Image"
},
"SOURCE": {
"id": 5,
"title": "SourceNew",
"value": "5"
},
"DATE": "2022-05-12T00:00:00.000Z",
"DATETIME": "2022-06-09T11:47:52.000Z",
"INTEGER": 11111,
"OWNER": {
"label": "Administrator",
"image": null,
"value": "1"
},
"NAME": "newname"
},
"permissions": {
"create": true,
"edit": true,
"remove": true,
"read": true
},
"checksum": "yKfCpt8J8VImczJnEoYqfA"
}
id
Id of the item.
fields
Key/values describing the values of each field, according to frontend requirements and needs.
Component visibility
If you need to control the visibility of a component based on highly customizable conditions, then ensure that the class implementing IRenderableComponentV2 also implements the IHideableComponent interface also included in NuGet package MediaiBox.Cms.FrontEnd.Model.Mvc.
This interface includes a method ShouldHideComponent which takes a ComponentContext and a CancellationToken as parameters and returns a Task<bool> indicating whether the component should be hidden.
The ComponentContext argument contains data that might be relevant for the evaluation:
- ViewData: Same object that is passed to the methods
MapSchemaandMapDatainIRenderableComponentV2.
Example:
public class MyComponent : IRenderableComponentV2<ComponentConfiguration, FormV2ViewData, FormSchema>, IHideableComponent
{
public async Task<bool> ShouldHideComponent(ComponentContext context, CancellationToken cancellationToken)
{
// Logic to determine if the component should be hidden
// Example: Check some condition against external APIs
bool shouldShide = true;
return await Task.FromResult(shouldHide);
}
// Other methods
}
Component Type Resolution
If you need to dynamically determine the type of a component that will be rendered in the front-end, implement the IComponentTypeProvider interface. You must override the GetComponentType method to return the appropriate component type based on some internal logic.
Example:
public class MyComponent : IComponentTypeProvider, IRenderableComponentV2<ComponentConfiguration, FormV2ViewData, FormSchema>
{
public string GetComponentType()
{
return "myCustomType"
}
}
In-page refreshing
In the core related list, it is possible to enable a button that refreshes the component, restoring it to its state before non-persisted user changes. In custom components that are rendered in the react frontend as related lists, it is possible to customize this refreshing behavior through the IRefreshableComponentV2 interface, which has the following contract:
public interface IRefreshableComponentV2<TConfiguration, TViewData> : IComponent<TConfiguration> where TConfiguration : IComponentConfiguration
{
Task<TViewData> MapRefreshData(DisplayComponentViewData viewData, CancellationToken cancellationToken);
}
In the endpoint called by the refresh button, this method is called right after the legacy GetRefreshRenderData method of the IRefreshableComponent interface (therefore, it is also necessary for the component to implement the IRefreshableComponent interface).