General
This is the reference for the Enterprise Framework module. The goal of this document is to provide in-depth details on most aspects of the framework. The Groovydoc (Javadoc) API covers other details of the underlying classes, but this document explains the higher-level features and behavior.
For a high-level treatment of these features, see the User Guide.
Document Conventions
This document follows certain conventions as shown below:
-
Literal values
-
File/path names
-
Class names
-
Variables, fields or parameters
-
Method names
-
Groovy or java code
See Naming Conventions for details on how elements are named.
There are a number of diagrams in these documents. We follow the given conventions for these diagrams. Some colors and shapes are used to flag specific types of elements:
Document Layout
Most modules have 3 main sets of documents:
-
Guide - General overview and key concepts document.
-
Reference - In depth reference for APIs, Domains, etc.
-
Groovydoc - The generated Groovydoc (Javadoc) from the source code.
The intent of the guide is to give you a general overview of feature, but not overwhelm you with details of the implementation. The reference documentation will explain most key fields, API calls and options. The guide generally has many links into the reference documentation.
Dashboards are fairly complex. To manage this in the documents, we use the guide for concept introduction and sometime simple examples. The reference document will explain all of the activities, events and scan actions for the dashboard. Each module will have additional activities, events and scan actions. These will be documented in a similar way:
Folder Conventions
For the most part, your application should be free to use most Micronaut-supported folder conventions. This is pretty open, so the framework and application modules that we develop will follow a specific folder layout for common artifacts.
Each major package for an application module should be organized like this:
-
product (Product Definition package for the MES Core module)
-
controller
-
domain
-
page (GEB GUI Test Pages - in src/test/groovy folder)
-
service
-
The folder layouts we will use are for the src/main/groovy source folder looks something like this under the org.simplemes.eframe package:
-
application (startup and common pages "/")
-
controller
-
domain
-
service
-
-
controller (controller support classes)
-
custom
-
controller
-
domain
-
-
domain (domain support classes)
-
misc
-
security
-
controller
-
domain
-
service
-
-
system
-
test
-
web
-
request
-
view
-
builder
-
widget
-
Domain
There are many support utilities for Domain classes used to help developers within the framework. These are defined in the API Documentation, but key classes, fields and methods are discussed here.
fieldOrder
Field Ordering
Frequently, the framework features will need to list or display your domain fields in a logical
order. Framework markers such as [efShow] will show the fields in any order you like, but you
would have to update the [efShow] marker for every new field added to the domain class.
To simplify this maintenance task, the framework supports an optional fieldOrder
static
variable in domain classes.
Philosophical Discussion Ahead! |
Field ordering is not traditionally part of a domain class’s definition. Following the 'Don’t Repeat Yourself' philosophy, a central place to store the field ordering 'hints' is needed. We chose the domain class. This is optional. If you don’t want to embed field ordering in your domain classes, then you can specify the field ordering on the respective [efShow], [efCreate] and [efEdit] markers in your .ftl files. This means updating 3 files whenever you add a new field to a domain class. This is your choice.
The field ordering can also be configured by a user to add Field Extension GUI, move core fields and remove core fields from the GUI.
Simple Ordering
Most simple domain classes will use just a simple list of fields in the order to be displayed. Any fields not listed will not be displayed.
class Product {
String product
Status status
String description
BigDecimal lotSize
static fieldOrder = ['product', 'status', 'lotSize', 'description']
}
The framework marker [efShow] can then be used to display these fields in the order you need:
<@efShow fields="order,product,qtyToBuild,qtyDone,dateCompleted"/>
Now, you can add a new field to the domain without updating your .ftl files. You only have to
remember to add the new field(s) to the fieldOrder
variable. See the
Testing fieldOrder Variable for details on how you can verify that all fields are
listed in the fieldOrder
variable.
Grouping of Field (Panels)
Simple grouping of fields is possible when you use a 'group:name' value in your
fieldOrder
variable.
An example is shown below, with the fieldOrder
setting needed for it.
class Product {
String name
String title
BigDecimal qty
Integer count
Boolean enabled
Date dateTime
DateOnly dueDate
String notes
static fieldOrder = ['name', 'title', 'qty', 'count', 'enabled', 'dueDate', 'dateTime',
'group:details', 'notes']
}
In the [efShow] marker, this will create two tabbed panels: 'Main' and 'Details'. The titles for these tabs will be pulled from the messages.properties file entry as shown below:
custom.panel.label=Custom
details.panel.label=Details
main.panel.label=Main
Any other panel labels will need to be defined in your messages.properties file.
By default, if any group is defined, all fields up to the first 'group' entry will be placed in
a panel titled 'Main'. You can change the label for this first panel as you wish by specifying
it in the fieldOrder
variable:
class Product {
static fieldOrder = ['group:first', 'product', 'status', 'lotSize',
'group:details.label', 'assemblyData', 'routing']
}
If the 'first' panel has no localized label, the text 'first' will be displayed. This allows custom panels to use the label as-is.
Testing fieldOrder Variable
We recommend that you test to your domain class tests to ensure that all fields are
accounted for in the fieldOrder
variable. The helper class
DomainTester
tests the fieldOrder
by default:
def "verify that user domain enforces constraints"() {
expect: 'the constraints are enforced'
DomainTester.test {
domain Order
requiredValues order: 'M1003', qty: 2.0 (1)
maxSize 'order', FieldSizes.MAX_CODE_LENGTH (2)
maxSize 'password', 128
notNullCheck 'userName' (3)
notNullCheck 'password'
notInFieldOrder (['authorities', 'password']) (4)
}
}
1 | Defines the required values for the domain record. |
2 | Verifies that the max length is enforced. |
3 | Verifies that null values are prevented. |
4 | Checks that the fieldOrder is defined correctly for the
domain class. Verifies that all persistent fields are listed in the fieldOrder list. |
You can also disable the fieldOrder check with the option 'fieldOrderCheck false'.
Initial Data Load
Initial data loading is one of the common setup needs for large applications. These applications usually have a number of status codes or numbering sequences that need some sort of initial values. If you don’t have some reasonable defaults, then your first-time customers may spend hours trying to configure your product. This will discourage most normal customers.
To trigger the initial data load on startup, you will need to add a method to your domain class. This method will be executed on application startup. The method should check for the existence of the record before attempting to create it. You should also minimize the logic to reduce startup time. Don’t add extensive or slow logic it you can avoid it.
static initialDataLoad() {
if (!findByKey('2000')) {
new SampleDomain(key: '2000', name: 'Ready').save()
}
if (!findByKey('2001')) {
new SampleDomain(key: '2001', name: 'Done').save()
}
}
GUI
Components CRUDTable
Services CRUDService
This section is the reference section for the GUI components used in the GUI sub-modules. These are Vue modules that are used by the GUIs to simplify GUI development.
CRUDTable
The CRUDTable
component defines the initial CRUD table for most definition
objects. This also provides the components needed to maintain these objects (add/edit/delete)
and object-specific actions.
Properties
The main properties supported are:
Property | Description |
---|---|
:columns |
The array containing the columns to be displayed in the table (Required). Elements include: field, header, and sort (boolean). |
:service |
The name of the Javascript object that interfaces to the server-side logic (Required). This service must provide the CRUDService methods. |
:domainClassName |
The variable that will hold the qualified class name of the domain class being maintained by this table (Required). |
<template>
<CrudTable :columns="columns" :service="service"
:domainClassName="domainClassName"/>
</template>
<script>
import CrudTable from 'eframe-lib/components/web/CrudTable';
import FlexTypeService from 'eframe-lib/components/custom/flexType/FlexTypeService'
export default {
components: {
CrudTable
},
data() {
return {
columns: [
{field: 'flexType', header: this.$t('label.flexType'), sort: true},
{field: 'category', header: this.$t('label.category'), sort: true},
{field: 'title', header: this.$t('label.title'), sort: true},
{field: 'fieldSummary', header: this.$t('label.fields')},
],
service: FlexTypeService,
domainClassName: 'org.simplemes.eframe.custom.domain.FlexType',
}
},
}
</script>
CRUDService
These services are used by the CRUDTable component to maintain domain objects.
The services must provide the list()
and other methods to support creation/update
of objects.
The CRUDTable
component defines the initial CRUD table for most definition
objects. This also provides the components needed to maintain these objects (add/edit/delete)
and object-specific actions.
Methods
list()
The main properties supported are:
Argument | Description |
---|---|
:options |
The options supported are the standard options from the server-side BaseCrudController . This includes: rows, first, search, and sort (e.g. sort[fieldName]=asc} (Required). |
:success |
The Javascript function called when the list call returns with data (Required). This method is passed the results as a javascript object (from the JSON). |
:error |
The Javascript function called when a server-side error is returned (Optional). This method does NOT need to display any error message. That is handled by the caller (e.g. CRUDTable). |
import InMemoriam from 'in-memoriam';
const cache = new InMemoriam(50, 60000);
export default {
// List for crud-style pages.
list(options, successFunction, errorFunction) {
const url = '/flexType/list';
window.$page.vue.axios.get(url, {params: options}).then((response) => {
if (successFunction) {
successFunction(response.data)
}
}).catch((error) => {
window.$page.handleError(error, url)
if (errorFunction) {
errorFunction(error, url)
}
})
},
};
asciidoctor-version |
2.0.10 |
safe-mode-name |
unsafe |
docdir |
/home/runner/work/simplemes-core/simplemes-core/eframe/src/main/docs/asciidoc |
docfile |
/home/runner/work/simplemes-core/simplemes-core/eframe/src/main/docs/asciidoc/reference.adoc |
doctype |
book |
imagesdir-build |
images |
imagesdir-src |
images |
imagesdir |
images |