Implement a custom UI component based on a Classic UI page
The example is relevant to version 8.0.2 and later.
To implement the example:
- Set up the page UI. Read more >>>
- Set up a custom component. Read more >>>
- Add the custom component to the page. Read more >>>
Display the history of the selected account on the Account timeline tab of the custom request page. The tab is a component based on the Timeline Classic UI tab displayed on the Classic UI contact page.
1. Set up the page UI
-
Create an app based on the Records & business processes template. Instructions: Create an app manually (user documentation).
For this example, create a Requests app.
-
Open the form page in the Freedom UI Designer.
For this example, open Requests form page that includes the Name field out of the box.
-
Add a field.
For this example, add the field that contains the account.
To do this:
-
Add a field of needed type to the working area of the Freedom UI Designer.
-
Click and fill out the field properties.
Element
Element type
Property
Property value
Field that contains the account
Dropdown
Title
Account
Code
UsrAccount
Lookup
Account
Enable adding new values
Clear the checkbox
-
-
Add a tab.
For this example, add the tab that contains the history of the selected account.
To do this, click and fill out the tab properties.
Element
Property
Property value
Tab that contains the history of the selected account
Title
Account timeline
-
Save the changes.
2. Set up a custom component
-
Open the Configuration section. Instructions: Open the Configuration section.
-
Select a user-made package to add the schema.
For this example, select the
UsrRequests
user-made package. -
Create the module schema. To do this, click Add → Module.
-
Fill out the schema properties.
For this example, use the following schema properties.
Property
Property value
Code
UsrTimelineModule
Title
TimelineModule
-
Apply the changes.
-
Implement the business logic of the custom component.
-
Add the dependencies. To do this, add
@creatio-devkit/common
library,Base7xViewElement
, andckeditor-base
modules as a dependency.AMD module dependencies/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function(sdk, Base7xViewElement) {
...
}); -
Declare a custom
UsrTimelineModule
component class.UsrTimelineModule/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {
/* Declare a "UsrTimelineModule" class. */
class UsrTimelineModule extends Base7xViewElement {
set primaryColumnValue(value) {
this._primaryColumnValue = value;
this._init();
}
get primaryColumnValue() {
return this._primaryColumnValue;
}
set entitySchemaName(value) {
this._entitySchemaName = value;
this._init();
}
get entitySchemaName() {
return this._entitySchemaName;
}
set cardSchemaName(value) {
this._cardSchemaName = value;
this._init();
}
get cardSchemaName() {
return this._entitySchemaName;
}
constructor() {
super("Timeline");
}
_init() {
if (this._primaryColumnValue && this._cardSchemaName && this._entitySchemaName) {
this.initContext(() => {
this._moduleId = this.sandbox.id + "_UsrTimelineModule";
this.sandbox.subscribe("GetColumnsValues", (attributeNames) => this._getColumnValues(attributeNames), null, [this._moduleId]);
this.sandbox.subscribe("GetEntityInfo", () => this._getEntityInfo(), null, [this._moduleId]);
this._loadTimelineSchemaModule();
});
}
}
_loadTimelineSchemaModule() {
this._moduleId = this.sandbox.loadModule("BaseSchemaModuleV2", {
id: this._moduleId,
renderTo: this._renderTo,
instanceConfig: {
schemaName: "TimelineSchema",
isSchemaConfigInitialized: true,
useHistoryState: false,
showMask: true,
parameters: {
viewModelConfigDiff: {
"CardSchemaName": this._cardSchemaName,
"ReferenceSchemaName": this._entitySchemaName,
"InitialConfig": {
"entities": []
}
},
},
}
});
}
_getColumnValues(attributeNames) {
const values = {};
attributeNames?.forEach((attributeName) => {
switch (attributeName) {
case "Id":
values[attributeName] = this._primaryColumnValue?.value;
break;
case "Name":
values[attributeName] = this._primaryColumnValue?.displayValue;
break;
default: break;
}
});
return values;
}
_getEntityInfo() {
return {
entitySchemaName: this._entitySchemaName,
primaryColumnValue: this._primaryColumnValue?.value,
primaryDisplayColumnValue: this._primaryColumnValue?.displayValue
};
}
getMessages() {
const messages = super.getMessages();
return Object.assign(messages, {
"GetColumnsValues": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
},
"GetEntityInfo": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
}
});
}
disconnectedCallback() {
this.sandbox.unloadModule(this._moduleId, this._renderTo);
}
}
}); -
Register the
UsrTimelineModule
module as a component.UsrTimelineModule/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {
...,
/* Register the component. */
customElements.define('usr-timeline', UsrTimelineModule);
...,
}); -
Specify that the
UsrTimelineModule
component is a view element.UsrTimelineModule/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function (sdk, Base7xViewElement) {
...,
/* Register a component as a visual element. */
sdk.registerViewElement({
type: 'usr.Timeline',
selector: 'usr-timeline',
inputs: {
primaryColumnValue: {},
cardSchemaName: {},
entitySchemaName: {}
}
});
});
-
-
Save the changes.
3. Add the custom component to the page
-
Open the form page in the Freedom UI Designer.
For this example, open Requests form page.
-
Open the source code of the Freedom UI page. To do this, click .
-
Add the dependencies. To do this, add the
UsrTimelineModule
module of the custom component as a dependency.AMD module dependencies/* Declare the AMD module. */
define("UsrRequests_FormPage", /**SCHEMA_DEPS*/["UsrTimelineModule"]/**SCHEMA_DEPS*/, function/**SCHEMA_ARGS*/()/**SCHEMA_ARGS*/ {
return {
...
}
}); -
Add a component.
- Go to the
viewConfigDiff
schema section. - Add the configuration object of the
UsrTimelineModule
element.
viewConfigDiff schema sectionviewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
...,
/* Configuration object of the "UsrTimelineModule" element. */
{
"operation": "insert",
"name": "UsrTimelineModule",
"values": {
"type": "usr.Timeline",
"layoutConfig": {
"column": 1,
"row": 1,
"colSpan": 12,
"rowSpan": 8
},
"primaryColumnValue": "$UsrAccount",
"cardSchemaName": "AccountPageV2",
"entitySchemaName": "Account"
},
"parentName": "GridContainer_0eojs6u",
"propertyName": "items",
"index": 0
},
...
]/**SCHEMA_VIEW_CONFIG_DIFF*/, - Go to the
-
Save the changes.
As a result, Freedom UI Designer will display a stub in place of the custom component.
View the result
To view the outcome of the example:
- Open the Requests section.
- Create a request that has an arbitrary name. For example, "Request's name."
- Select an arbitrary account in the Account field. For example, "Alpha Business."
- Open the Account timeline tab.
As a result, Creatio will display the Account timeline tab of the selected account on the request page. View the result >>>
Source code
- UsrTimelineModule
- UsrRequests_FormPage
/* Declare the AMD module. */
define("UsrTimelineModule", ["@creatio-devkit/common", "Base7xViewElement", "ckeditor-base"], function(sdk, Base7xViewElement) {
/* Declare a "UsrTimelineModule" class. */
class UsrTimelineModule extends Base7xViewElement {
set primaryColumnValue(value) {
this._primaryColumnValue = value;
this._init();
}
get primaryColumnValue() {
return this._primaryColumnValue;
}
set entitySchemaName(value) {
this._entitySchemaName = value;
this._init();
}
get entitySchemaName() {
return this._entitySchemaName;
}
set cardSchemaName(value) {
this._cardSchemaName = value;
this._init();
}
get cardSchemaName() {
return this._entitySchemaName;
}
constructor() {
super("Timeline");
}
_init() {
if (this._primaryColumnValue && this._cardSchemaName && this._entitySchemaName) {
this.initContext(() => {
this._moduleId = this.sandbox.id + "_UsrTimelineModule";
this.sandbox.subscribe("GetColumnsValues", (attributeNames) => this._getColumnValues(attributeNames), null, [this._moduleId]);
this.sandbox.subscribe("GetEntityInfo", () => this._getEntityInfo(), null, [this._moduleId]);
this._loadTimelineSchemaModule();
});
}
}
_loadTimelineSchemaModule() {
this._moduleId = this.sandbox.loadModule("BaseSchemaModuleV2", {
id: this._moduleId,
renderTo: this._renderTo,
instanceConfig: {
schemaName: "TimelineSchema",
isSchemaConfigInitialized: true,
useHistoryState: false,
showMask: true,
parameters: {
viewModelConfigDiff: {
"CardSchemaName": this._cardSchemaName,
"ReferenceSchemaName": this._entitySchemaName,
"InitialConfig": {
"entities": []
}
},
},
}
});
}
_getColumnValues(attributeNames) {
const values = {};
attributeNames?.forEach((attributeName) => {
switch (attributeName) {
case "Id":
values[attributeName] = this._primaryColumnValue?.value;
break;
case "Name":
values[attributeName] = this._primaryColumnValue?.displayValue;
break;
default: break;
}
});
return values;
}
_getEntityInfo() {
return {
entitySchemaName: this._entitySchemaName,
primaryColumnValue: this._primaryColumnValue?.value,
primaryDisplayColumnValue: this._primaryColumnValue?.displayValue
};
}
getMessages() {
const messages = super.getMessages();
return Object.assign(messages, {
"GetColumnsValues": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
},
"GetEntityInfo": {
mode: Terrasoft.MessageMode.PTP,
direction: Terrasoft.MessageDirectionType.SUBSCRIBE
}
});
}
disconnectedCallback() {
this.sandbox.unloadModule(this._moduleId, this._renderTo);
}
}
/* Register the component. */
customElements.define('usr-timeline', UsrTimelineModule);
/* Register a component as a visual element. */
sdk.registerViewElement({
type: 'usr.Timeline',
selector: 'usr-timeline',
inputs: {
primaryColumnValue: {},
cardSchemaName: {},
entitySchemaName: {}
}
});
return Terrasoft.UsrTimelineModule;
});
/* Declare the AMD module. */
define("UsrRequests_FormPage", /**SCHEMA_DEPS*/["UsrTimelineModule"]/**SCHEMA_DEPS*/, function/**SCHEMA_ARGS*/()/**SCHEMA_ARGS*/ {
return {
viewConfigDiff: /**SCHEMA_VIEW_CONFIG_DIFF*/[
{
"operation": "merge",
"name": "Tabs",
"values": {
"styleType": "default",
"mode": "tab",
"bodyBackgroundColor": "primary-contrast-500",
"selectedTabTitleColor": "auto",
"tabTitleColor": "auto",
"underlineSelectedTabColor": "auto",
"headerBackgroundColor": "auto"
}
},
{
"operation": "merge",
"name": "Feed",
"values": {
"dataSourceName": "PDS",
"entitySchemaName": "UsrRequests"
}
},
{
"operation": "merge",
"name": "AttachmentList",
"values": {
"columns": [
{
"id": "0e270bd7-0a80-4794-9676-46a243ddfd54",
"code": "AttachmentListDS_Name",
"caption": "#ResourceString(AttachmentListDS_Name)#",
"dataValueType": 28,
"width": 200
}
]
}
},
{
"operation": "insert",
"name": "UsrName",
"values": {
"layoutConfig": {
"column": 1,
"row": 1,
"colSpan": 1,
"rowSpan": 1
},
"type": "crt.Input",
"label": "$Resources.Strings.UsrName",
"control": "$UsrName",
"labelPosition": "auto"
},
"parentName": "SideAreaProfileContainer",
"propertyName": "items",
"index": 0
},
/* Field that contains the account. */
{
"operation": "insert",
"name": "UsrAccount",
"values": {
"layoutConfig": {
"column": 1,
"row": 2,
"colSpan": 1,
"rowSpan": 1
},
"type": "crt.ComboBox",
"label": "$Resources.Strings.UsrAccount",
"labelPosition": "auto",
"control": "$UsrAccount",
"listActions": [],
"showValueAsLink": true,
"controlActions": [],
"visible": true,
"placeholder": "",
"tooltip": ""
},
"parentName": "SideAreaProfileContainer",
"propertyName": "items",
"index": 1
},
/* Tab that contains the history of the selected account. */
{
"operation": "insert",
"name": "AccountTimelineTab",
"values": {
"type": "crt.TabContainer",
"items": [],
"caption": "#ResourceString(AccountTimelineTab_caption)#",
"iconPosition": "only-text",
"visible": true
},
"parentName": "Tabs",
"propertyName": "items",
"index": 1
},
{
"operation": "insert",
"name": "GridContainer_0eojs6u",
"values": {
"type": "crt.GridContainer",
"items": [],
"rows": "minmax(32px, max-content)",
"columns": [
"minmax(32px, 1fr)",
"minmax(32px, 1fr)"
],
"gap": {
"columnGap": "large",
"rowGap": 0
}
},
"parentName": "AccountTimelineTab",
"propertyName": "items",
"index": 0
},
/* Configuration object of the "UsrTimelineModule" element. */
{
"operation": "insert",
"name": "UsrTimelineModule",
"values": {
"type": "usr.Timeline",
"layoutConfig": {
"column": 1,
"row": 1,
"colSpan": 12,
"rowSpan": 8
},
"primaryColumnValue": "$UsrAccount",
"cardSchemaName": "AccountPageV2",
"entitySchemaName": "Account"
},
"parentName": "GridContainer_0eojs6u",
"propertyName": "items",
"index": 0
}
]/**SCHEMA_VIEW_CONFIG_DIFF*/,
viewModelConfig: /**SCHEMA_VIEW_MODEL_CONFIG*/{
"attributes": {
"Id": {
"modelConfig": {
"path": "PDS.Id"
}
},
"UsrName": {
"modelConfig": {
"path": "PDS.UsrName"
}
},
"UsrAccount": {
"modelConfig": {
"path": "PDS.UsrAccount"
}
}
}
}/**SCHEMA_VIEW_MODEL_CONFIG*/,
modelConfig: /**SCHEMA_MODEL_CONFIG*/{
"dataSources": {
"PDS": {
"type": "crt.EntityDataSource",
"config": {
"entitySchemaName": "UsrRequests"
},
"scope": "page"
}
},
"primaryDataSourceName": "PDS"
}/**SCHEMA_MODEL_CONFIG*/,
handlers: /**SCHEMA_HANDLERS*/[]/**SCHEMA_HANDLERS*/,
converters: /**SCHEMA_CONVERTERS*/{}/**SCHEMA_CONVERTERS*/,
validators: /**SCHEMA_VALIDATORS*/{}/**SCHEMA_VALIDATORS*/
};
});