Statistics blocks
Statistics blocks
widget is a tool designed to display aggregated data in a visually accessible format. This data can be sourced either from a database or from external sources.
Basics
You have the option to utilize custom field names for standard properties such as color, icon, etc. When doing so, you'll need to establish mappings for these fields to standard criteria
Custom fields
:
Live Sample
GitHub
Default fields
:
Live Sample
GitHub
How does it look?
How to add?
Example
You have the option to utilized default field names for standard properties such as color, icon, etc. When doing so, you'll not need to establish mappings for these fields to standard criteria
Step1 Create DataResponseDTO with custom fields.
@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {
private String title;
private Long value;
private String color;
private String description;
private String icon;
}
Title. Optional
Value - field that specifies formulas for data aggregation
Icon. Optional
Color. Optional
Description - comment for field. Optional
Id - We recommend assigning unique identifiers to each block. This is essential for the proper functioning of the application and for enabling drilldown.
@Service
@RequiredArgsConstructor
public class MyExampleDao extends AbstractAnySourceBaseDAO<MyExampleDTO> implements
AnySourceBaseDAO<MyExampleDTO> {
public static final String COUNT_ROW_ID = "0";
public static final String SUM_CUSTOM_FIELD_NUM = "1";
private final MyEntityRepository repository;
@Override
public String getId(final MyExampleDTO entity) {
return entity.getId();
}
@Override
public void setId(final String id, final MyExampleDTO entity) {
entity.setId(id);
}
@Override
public MyExampleDTO getByIdIgnoringFirstLevelCache(final BusinessComponent bc) {
return getStats().stream().filter(s -> Objects.equals(s.getId(), bc.getId())).findFirst().orElse(null);
}
@Override
public void delete(final BusinessComponent bc) {
throw new IllegalStateException();
}
@Override
public Page<MyExampleDTO> getList(final BusinessComponent bc, final QueryParameters queryParameters) {
return new PageImpl<>(getStats());
}
@Override
public MyExampleDTO update(BusinessComponent bc, MyExampleDTO entity) {
throw new IllegalStateException();
}
@Override
public MyExampleDTO create(final BusinessComponent bc, final MyExampleDTO entity) {
throw new IllegalStateException();
}
@NonNull
private List<MyExampleDTO> getStats() {
List<MyExampleDTO> result = new ArrayList<>();
MyExampleDTO newRow = new MyExampleDTO()
.setTitle("All record")
.setValue(repository.count())
.setIcon("team")
.setDescription("Count rows in table");
newRow.setId(COUNT_ROW_ID);
result.add(newRow);
MyExampleDTO newSum = new MyExampleDTO()
.setTitle("Custom Field Num Total")
.setValue( repository.customTotal())
.setIcon("team")
.setDescription("Custom Field Num Total");
newRow.setId(COUNT_ROW_ID);
newSum.setId(SUM_CUSTOM_FIELD_NUM);
result.add(newSum);
return result;
}
}
@Service
public class MyExampleMeta extends AnySourceFieldMetaBuilder<MyExampleDTO> {
@Override
// --8<-- [start:buildRowDependentMeta]
public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, BcDescription bc,
String id, String parentId) {
}
// --8<-- [end:buildRowDependentMeta]
@Override
public void buildIndependentMeta(FieldsMeta<MyExampleDTO> fields, BcDescription bc, String parentId) {
}
}
@Service
public class MyExampleService extends AnySourceVersionAwareResponseService<MyExampleDTO, MyExampleDTO> {
public MyExampleService() {
super(MyExampleDTO.class, MyExampleDTO.class, MyExampleMeta.class, MyExampleDao.class);
}
@Override
protected CreateResult<MyExampleDTO> doCreateEntity(MyExampleDTO entity, BusinessComponent bc) {
return new CreateResult<>(entityToDto(bc, entity));
}
@Override
protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyExampleDTO entity, MyExampleDTO data, BusinessComponent bc) {
return new ActionResultDTO<>(entityToDto(bc, entity));
}
}
Step5 Create Widget with type StatsBlock !!! tips fields. We recommend including all fields used in the widget within this block. This maintains the principle of consistency in your application
{
"name": "MyExampleList",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myExampleBc",
"fields": [
{
"title": "value",
"key": "value",
"type": "number"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
],
"options": {
}
}
!!! tips To display statistical blocks on the same screen where data is added, you need to add RefreshBC property.
You have the option to utilize custom field names for standard properties such as color, icon, etc. When doing so, you'll need to establish mappings for these fields to standard criteria
Step1 Create DataResponseDTO with custom fields.
@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {
private String customFieldTitle;
private String customFieldValue;
private String customFieldIcon;
private String customFieldDescription;
private String customField;
private String customFieldNum;
}
Title. Optional
Value - field that specifies formulas for data aggregation
Icon. Optional
Color. Optional
Description - comment for field. Optional
Id - We recommend assigning unique identifiers to each block. This is essential for the proper functioning of the application and for enabling drilldown.
@Service
@RequiredArgsConstructor
public class MyExampleDao extends AbstractAnySourceBaseDAO<MyExampleDTO> implements
AnySourceBaseDAO<MyExampleDTO> {
public static final String COUNT_ROW_ID = "0";
public static final String SUM_CUSTOM_FIELD_NUM = "1";
private final MyEntityRepository repository;
@Override
public String getId(final MyExampleDTO entity) {
return entity.getId();
}
@Override
public void setId(final String id, final MyExampleDTO entity) {
entity.setId(id);
}
@Override
public MyExampleDTO getByIdIgnoringFirstLevelCache(final BusinessComponent bc) {
return getStats().stream().filter(s -> Objects.equals(s.getId(), bc.getId())).findFirst().orElse(null);
}
@Override
public void delete(final BusinessComponent bc) {
throw new IllegalStateException();
}
@Override
public Page<MyExampleDTO> getList(final BusinessComponent bc, final QueryParameters queryParameters) {
return new PageImpl<>(getStats());
}
@Override
public MyExampleDTO update(BusinessComponent bc, MyExampleDTO entity) {
throw new IllegalStateException();
}
@Override
public MyExampleDTO create(final BusinessComponent bc, final MyExampleDTO entity) {
throw new IllegalStateException();
}
@NonNull
private List<MyExampleDTO> getStats() {
List<MyExampleDTO> result = new ArrayList<>();
MyExampleDTO newRow = new MyExampleDTO()
.setCustomFieldTitle("All record")
.setCustomFieldValue(String.valueOf(repository.count()))
.setCustomFieldIcon("team")
.setCustomFieldDescription("Count rows in table");
newRow.setId(COUNT_ROW_ID);
result.add(newRow);
MyExampleDTO newSum = new MyExampleDTO()
.setCustomFieldTitle("Custom Field Num Total")
.setCustomFieldValue(String.valueOf(repository.customTotal()))
.setCustomFieldIcon("team")
.setCustomFieldDescription("Sum customFieldNum");
newSum.setId(SUM_CUSTOM_FIELD_NUM);
result.add(newSum);
return result;
}
}
@Service
public class MyExampleMeta extends AnySourceFieldMetaBuilder<MyExampleDTO> {
@Override
// --8<-- [start:buildRowDependentMeta]
public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, BcDescription bc,
String id, String parentId) {
}
// --8<-- [end:buildRowDependentMeta]
@Override
public void buildIndependentMeta(FieldsMeta<MyExampleDTO> fields, BcDescription bc, String parentId) {
}
}
@Service
public class MyExampleService extends AnySourceVersionAwareResponseService<MyExampleDTO, MyExampleDTO> {
public MyExampleService( ) {
super(MyExampleDTO.class, MyExampleDTO.class, MyExampleMeta.class, MyExampleDao.class);
}
@Override
protected CreateResult<MyExampleDTO> doCreateEntity(MyExampleDTO entity, BusinessComponent bc) {
return new CreateResult<>(entityToDto(bc, entity));
}
@Override
protected ActionResultDTO<MyExampleDTO> doUpdateEntity(MyExampleDTO entity, MyExampleDTO data, BusinessComponent bc) {
return new ActionResultDTO<>(entityToDto(bc, entity));
}
}
Tips
fields.We recommend including all fields used in the widget within this block. This maintains the principle of consistency in your application
options.stats - This map how custom fields are matched to standard properties.
{
"name": "MyExampleList",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myExampleBc",
"fields": [
{
"title": "Custom Field Title",
"key": "customFieldTitle",
"type": "input"
},
{
"title": "Custom Field Value",
"key": "customFieldValue",
"type": "input"
},
{
"title": "Custom Field Value",
"key": "customFieldDescription",
"type": "input"
},
{
"title": "Custom Field Value",
"key": "customFieldIcon",
"type": "input"
},
{
"title": "Custom Field Total",
"key": "customFieldNum",
"type": "input"
}
],
"options": {
"stats": {
"valueFieldKey": "customFieldValue",
"titleFieldKey": "customFieldTitle",
"iconFieldKey": "customFieldIcon",
"descriptionFieldKey": "customFieldDescription"
}
}
}
Tips
To display statistical blocks on the same screen where data is added, you need to add RefreshBC property.
Main visual parts
We can modify the following parameters on this widget:
- Title. Optional
- Value - field that specifies formulas for data aggregation
- Description - comment for field. Optional
Title
Title Basic
Title - a name displayed in a block. It is optional.
There are types of:
constant title
: shows constant text.constant title empty
.
How does it look?
How to add?
Example
Step1 Add name for title to .widget.json.
{
"name": "MyExampleStat",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myexample",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColor": "#edaa"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Step1 No use parameter title to .widget.json.
{
"name": "MyExampleStat",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myexample",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColor": "#edaa"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Title Color
not applicable
Business component
This specifies the business component (BC) to which this form belongs. A business component represents a specific part of a system that handles a particular business logic or data.
see more Business component
Show condition
not applicable
Fields
Options layout
options.layout - no use in this type.
Actions
Actions
show available actions as separate buttons
see Actions
Additional properties
Icon
Icon - picture representing a particular function.Optional Example icon)
There are types of:
icon
.icon empty
.
How does it look?
How to add?
Example
Step1 Add name for title to .widget.json.
{
"name": "MyExampleStat",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myexample",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColor": "#edaa"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Step1 No use parameter title to .widget.json.
{
"name": "MyExampleStat",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myexample",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColor": "#edaa"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Color
Color
allows you to specify a field block.Optional. It can be calculated based on business logic of application
Calculated color
Constant color
How does it look?
How to add?
Example
Step 1 Add custom field for color
to corresponding DataResponseDTO. The field can contain a HEX color or be null.
@Getter
@Setter
@NoArgsConstructor
public class MyExampleDTO extends DataResponseDTO {
private String title;
private Long value;
private String color;
private String description;
private String icon;
}
Step 2 Add "bgColorKey" : custom field for color
to .widget.json.
{
"name": "MyExampleList",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myExampleBc",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColorKey": "color"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Add "bgColor" : HEX color
to .widget.json.
{
"name": "MyExampleList",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myExampleBc",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"bgColor": "#edaa"
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
],
"options": {
}
}
Widget size
By default, we use the view gridWidth field to arrange widgets in a row, each occupying 1/3 of the given size. For example, if the row has a total width of 24 spans, each widget will take up 8 spans.
How does it look?
How to add?
Example
Change gridWidth = 24 to corresponding view
{
"name": "MyExampleStat",
"title": "MyExampleStat",
"template": "DashboardView",
"url": "/screen/myexample/view/MyExampleStat",
"widgets": [
{
"widgetName": "SecondLevelMenu",
"position": 0,
"gridWidth": 24
},
{
"widgetName": "MyExampleStat",
"position": 20,
"gridWidth": 24
}
],
"rolesAllowed": [
"CXBOX_USER"
]
}
Change gridWidth = 12 to corresponding view
{
"name": "MyExampleStat",
"title": "MyExampleStat",
"template": "DashboardView",
"url": "/screen/myexample/view/MyExampleStat",
"widgets": [
{
"widgetName": "SecondLevelMenu",
"position": 0,
"gridWidth": 24
},
{
"widgetName": "MyExampleStat",
"position": 20,
"gridWidth": 12
}
],
"rolesAllowed": [
"CXBOX_USER"
]
}
Change gridWidth = 6 to corresponding view
{
"name": "MyExampleStat",
"title": "MyExampleStat",
"template": "DashboardView",
"url": "/screen/myexample/view/MyExampleStat",
"widgets": [
{
"widgetName": "SecondLevelMenu",
"position": 0,
"gridWidth": 24
},
{
"widgetName": "MyExampleStat",
"position": 20,
"gridWidth": 6
}
],
"rolesAllowed": [
"CXBOX_USER"
]
}
Drilldown
DrillDown
allows you to navigate to another view by simply tapping on it. Target view and other drill-down parts can be calculated based on business logic of application
Also, it optionally allows you to filter data on target view before it will be opened see more
DrillDown
How does it look?
How to add?
Example
Option 1
Step 1
Add fields.setDrilldown to corresponding FieldMetaBuilder.
@Override
public void buildRowDependentMeta(RowDependentFieldsMeta<MyExampleDTO> fields, BcDescription bc,
String id, String parentId) {
String urlBC ="/screen/myexample/view/myexamplelist" + "/" + PlatformMyExampleController.myExampleBc;
String urlFilterForField = URLEncoder.encode("customFieldFilterDictionary.equalsOneOf=%5B%22Low%22%2C%22High%22%5");
String urlFilter = "?filters={\""
+ PlatformMyExampleController.myExampleBc
+ "\":\""
+ urlFilterForField
+ "\"}";
fields.setDrilldown(
MyExampleDTO_.value,
DrillDownType.INNER,
urlBC + urlFilter
);
}
private String getStatusFilterValues(@NonNull String id) {
if (COUNT_NEW_ROW_ID.equals(id)) {
return CustomFieldEnum.NEW.getValue();
} else if (COUNT_NEW_IN_PROGRESS_ROW_ID.equals(id)) {
return CustomFieldEnum.NEW.getValue() + "," + CustomFieldEnum.IN_PROGRESS.getValue();
}
throw new IllegalStateException("Unexpected value: " + id);
}
Step 2
Add "drillDown": "true" to .widget.json.
{
"name": "MyExampleList",
"title": "StatsBlock title",
"type": "StatsBlock",
"bc": "myExampleBc",
"fields": [
{
"title": "value",
"key": "value",
"type": "number",
"drillDown": true
},
{
"title": "title",
"key": "title",
"type": "input"
},
{
"title": "icon",
"key": "icon",
"type": "input"
},
{
"title": "description",
"key": "description",
"type": "hint"
}
]
}
Option 2
Add "drillDownKey" : custom field
to .widget.json. See more Drilldown