Version 6.3 release note
Warning: This release note corresponds to the next (and final) minor version of major version 6.
It is now in BETA stage. It means it is not yet suitable for production but should now be used for development and testing on the projects planned for delivery after its release.
Compatibility breaking changes
These changes may require action if you are concerned:
- Some development-oriented features/tools are now restricted to the development mode this has no impact on your projects, the only impact is that you now should start your development instances in development mode especially if you work in an external IDE and/or use Maven-level tasks such as linting or SonarQube code analysis.
- The legacy FranceConnect authentication provider has been removed (it was already deprecated in previous minor versions) because it can be configured as a purely generic OpenIDConnect authentication provider (note that the generic OpenIDConnect provider is also compliant with FranceConnect+ authentication service), this has no impact if you don't use the legacy FranceConnect_ authentication provider
- Some deprecated methods and constants that have been marked "for removal" for several previous versions have been finally removed. They were already generating compilation errors in the previous versions so they are supposed to have been already refactored.
- The outdated legacy library
commons-discovery
has been removed (you can still add it as a custom shared lib if you use it, which is highly unlikely)
Deprecations
These deprecated features may be removed in the next releases, you should take action if you use them in order to anticipate their future removal:
- Some new methods and constants have been marked deprecated and should be refactored accordingly to the proposal (see Javadoc and/or deprecation logs). They are not yet marked "for removal" thus won't generate compilation errors but only warnings.
- As already announced in the breaking changes of version v6.2 the legacy iText libraries
will be removed in next major version v7, there will be also an impact on the associated helpers
PDFTool
andPDFDocumentExternalObject
helper classes that are still fully designed for iText in v6. If you use iText or the above helper classes in your code and plan to upgrade to v7 once it will be released it is now time to refactor these piece of code to use the PDFBox libraries (it won't compile any longer in v7).
Features
New features for the end-user
Cartographical search
- searchable fields of "coordinates" type open a clickable map to select coordinate
- the map renderer has been migrated to the Leaflet library (instead of Google Maps) for coordinate fields and placemaps
- a new
MAP_SETTINGS
system parameter allows for tile server configuration- it is configured to use OpenStreetMap.org by default
- Google Map's tiles are still configurable if necessary
- on-premise tile servers are also easily configurable
Context menu on lists
Added context menus to lists. When multiple rows are selected, only bulk operations are shown, while single selections display row-specific actions.
Other Quality of Life improvements
- On lists, Ctrl+Click to select a line
Quick list ordering
This feature allows user to reorder records using a persitent integer field of the business object.
New object field Reorderable
property on the integer field:
with 3 options to persist the recalculated orders in this field:
- Allows the user to reorder the rows in a list by drag&drop
- Renum thru bulk action the current search with an increment value
- Reorder in case of create/update a row to an existing order
UI guides
UI guides are tours for usage onboarding.
Group GUIDE_MAKER
This responsibility adds a new menu to access guides for makers:
- User guides: full definitions with steps settings and permissions
- Guide usages: to track who used a guide and when
- Guide recorder: helper to build a tour skeleton during UI usage
Guides can be:
- defined to be launched from any view, home page, business object and external object
- accessible during a limited period
- permitted to user groups
- defined with many steps
- into a single page
- or several asynchronous pages/dialogs
- with user interaction (to click on button, complete fields...)
The guide recorder is still experimental and will be improved in a future release:
- The maker runs the journey by right-clicking on the step elements with minimal properties,
- Simplicite then creates a guide skeleton with generic DOM selectors,
- The designer must update/complete the tour to be operational with the necessary permissions.
Group GUIDE_USER
- The user needs the responsibility
GUIDE_USER
. - Permitted guide can be automatically launched (once per user), or replayed with a button.
Enhancements
Features enhancements for the end-user
Enhanced list search UX
- a) Indexed/fulltext search can be displayed at the top of the list
- b) Full search on dialog (or docked on left) is a separated button (no more toggle between search modes)
- c) Search by column is a small toggle button in the columns header
- d) A specific search bar can be added to the top or side of the list
- e) When searching a reference, you can now select multiple references at once.
Extended search options for reference and datamap picker:
- Supports the search template if present
- Supports dialog and indexed search if allowed on object
- Forces the search by columns (even if not checked on object for backward compatibility)
- Disables the docked mode and predefined searches (not suitable for a popup)
Goes hand in hand with "Enhanced search configuration"
Search helper on a floating date
New search property on date
or datetime
field: search with helper
The user can edit complex searches based on fixed or current date.
For example to search a period
- from 4 months ago
- up to the next 15 days
is converted to new filter syntax with floating date:
>=[DATE:-4m] and <=[DATE:15d]
Child objects change logs
Retrieve redo logs of child object into the parent Change log
panel
- new
Link
optionShow change logs
- or by code
getLink("DemoProduct","demoPrdSupId").setMergeRedologs(true)
Example: Product updates are visible in the Supplier Change log
panel
Maker Experience
Features enhancements for the designer
Improved annotations
All annotations now include a desc
attribute that can be used to document the related class/method.
New annotations have also been added to annotate the business and external objects' hooks.
E.g.
@BusinessObjectAction(desc = "This actions corresponds to the MY_ACTION configured action")
public String myActionMethod(Action action) {
(...)
}
Mermaid widget
A new configurable external object class (MermaidExternalObject
) allows to display Mermaid charts.
E.g.
The chart specification can be either static as in the example above (set in the Settings field)
or dynamic using the dedicated hook getMermaidChartSpec
.
E.g.
package com.simplicite.extobjects.MyModule;
import com.simplicite.util.ObjectDB;
import com.simplicite.util.Tool;
import com.simplicite.util.tools.Parameters;
public class AppTestMermaid extends com.simplicite.webapp.web.widgets.MyMermaidExtObject {
private static final long serialVersionUID = 1L;
@Override
public String getMermaidChartSpec(Parameters params) {
// Embedded in a business object?
String obj = params.getParameter("object");
if ("MyObject".equals(obj)) {
// Retrieve the current business object instance
ObjectDB o = getGrant().getObject(params.getParameter("inst"), obj);
// Generate a dynamic specification using the current record of the business object instance
return
"graph LR\n"
+ " subgraph \"" + o.getDisplay() + "\"\n"
+ " subgraph \"" + o.getFieldValue("myField") + "\"\n"
+ " " + o.getFieldValue("myOtherField") + "\n"
+ " end\n"
+ " end\n";
}
// Else, defaults to the static specification
return super.getMermaidChartSpec(params);
}
}
"Go to definition" generalization
New contextual buttons to go to the component's definition, available for:
- View
- Crosstab
- Activity
- Timesheet
- TreeView
- External object
Enhanced search configuration
- a) 4 new properties to allow search on list (column, dialog, docked, index)
- b) preview of indexed fields when the object is indexable
- c) allows to edit a search-bar template added to the list
Edit search template on list:
Goes hand in hand with "Enhanced list search UX"
Module Git
The legacy ModuleGIT
external object has been removed. Its features are now available on the ModuleCommit
business object linked to the Module
object.
This business object now displays the Git tag(s) of each commit and a new row-level action allows to put a tag on a given commit (the push action now also pushes the tags):
Modeler search
New search prompt to outline items on model:
User Data Anonymization
New field and link properties to identify the user's data to Anonymize:
- Field: removes or randomizes the DB value
- in
m_user
(exusr_first_name
,usr_last_name
...) - or columns in other tables (with a foreign-key to m_user)
- in
- Link: deletes or removes the relationship during anonymization
- following the link deletion rule (ex: delete cascade of user's
UserSysParam
,GuideUsage
...)
- following the link deletion rule (ex: delete cascade of user's
The anonymize action is now available on list to anonymize several users in a same time.
The properties will be used in a future versions
- to anonymize other business data (ex: order amount...)
- to audit data to anonymize for verification and communication
Helper to build the History object
New action on object definition to build the history object/table:
- Specify if the history is in descending order
- Select the fields to be historized
Then the action creates or updates the history object:
- with technical fields
row_idx
,created_by_hist
andcreated_dt_hist
- and the foreign key
row_ref_id
to parent object with its referenced key fields - and the selected fields to be historized on parent updates
Finally this object can be updated manually by designers.
New Simplicite logo CSS
The new logo has been integrated into the core CSS with classes that can be assembled to achieve the desired logo:
- Color:
logo-color
: colored logo (50x50 by default)logo-back
: black versionlogo-white
: white version
- Size:
logo-xs
: extra small (1rem = 16px at 100% scale)logo-sm
: small (2rem = 32px)logo-md
: medium (4rem = 64px)logo-lg
: large (8rem = 128px)
- Animation:
logo-progress
: with loading animation
Example: <div class="logo-white logo-lg logo-progress"></div>
Technical
Technical enhancements and features
New FeatureFlags
A new class to manage the new features with the default activation.
FeatureFlag.TRUNCATE_TOO_LONG_TEXT.isActive()
:true
by default to truncate on save too long text (except rich text: html, json, grid, notepad...),false
to return an errorFeatureFlag.IMAGES_IN_EXCEL_EXPORTS.isActive()
:false
by default (because experimental in 6.3, see below), true to allow export of images in excelFeatureFlag.HISTORY_DIFF_MODE.isActive()
:true
by default to see the difference between 2 rows in list of object history
Some flags are overridable, to do so maker has to create a system parameter FEATURE_FLAGS
globally (and per user).
For example, the flag name is in lower case:
{
"truncate_too_long_text": false,
"images_in_excel_exports": true
}
and to override a flag per user session by code (in PlatformHooks.postLoadGrant
):
// to activate a feature flag only for a profile
if (getGrant().hasResponsibility("ONE_ADMIN_GROUP")) {
// do not truncate data on validate, returns an error if a text is too long
FeatureFlag.TRUNCATE_TOO_LONG_TEXT.setActive(getGrant(), false);
// export images in excel
FeatureFlag.IMAGES_IN_EXCEL_EXPORTS.setActive(getGrant(), true);
}
Overridable features will be migrated over time in future releases.
Rows difference in Object history
A new calculated field row_diff
has been created to generate on search the difference of a record with its previous one (row_id
based).
It is now used for History object, but can be added in other objects.
- History generation will add this field to object, but designer can place this field into object
- History object with active
FeatureFlag.HISTORY_DIFF_MODE
will automatically add this field (for previous 6.3 object)
It is activated by default, and overridable through the system parameter FEATURE_FLAGS
:
{
"history_diff_mode": false
}
Grouping of object histories
The previous feature, which allows merging redologs in the same parent object panel, has been extended to history panel.
The Link
property between the object and its Historic
has been changed to support 2 flags:
relologs
: same as 6.2 to merge children redologs in the parent listhistory table
: new flag to show children history in the parent history panel- grouped by user-keys and ordered by date
- with the
row_diff
column to quickly see the updated fields - respecting the visibility rules on the fields (which was not possible with system redologs)
Images in excel exports
An experimental feature allows to include images in excel exports, although it comes with the following limitations:
- image anchoring does not work as expected (images don't follow the lines/columns when reordering)
- images adapt to default row size, which is quite small
- it can severely affect the exported file size, so image inclusion will be made optional in the future
In the meantime, it can be activated through the system parameter FEATURE_FLAGS
{
"images_in_excel_exports": true
}
ECJ Java compiler
The platform now uses the Eclipse Java Compiler (ECJ) instead of the JDK compiler.
This is transparent and more efficient. It also allows to deploy the platform on a JRE instead of a JDK keeping Java custom code compilation possible.
Reminder: Java compilation can be explicitly enabled or disabled using the
server.compiler
JVM argument (defaults totrue
) which is driven by theCOMPILER
environment variable in our Docker images.
The compiler options can be customized if needed using the JAVA_COMPILER_OPTIONS
system parameter which is provided as -g -warn:unused,deprecation
in order
to make more visible (as warnings) all deprecated usages and unused variables/methods in the custom code (not that compilation warnings
are non blocking but should be fixed).
The list of possible compiler options are described in the Eclipse documentation.
JS $console tool
New global variable $console
, by default:
- uses the default navigator
console
$console.error
logs the stack trace + UI alert$console.info|log|warn
can be overridden
$app.info|warn|error...
are still accessible but it is strongly recommended to use $console
instead.
Server side events
New servlet /ui/sse
(asynchronous) to push messages from server to clients thru https
Example to bind a myEvent
message:
- Server side:
ServerSideEvent.push("myEvent", new JSONObject().put("info","hello"), userId);
userId: null to notify all registered clients or a specific user.
- Client side: simply add an event listener on
ui.ready
$ui.sse.addEventListener("myEvent", e => {
let d = JSON.parse(e.data);
console.log("myEvent message: " + d.info + " at time = " + d.time);
});
Predefined server side events:
ping
: simple ping thru SSEclose
: close the SSE connectionreset
: reopen the SSE connectionsysparam
: new system parameter flag to push changes fromgrant.setParameter("MYPARAM","value")
to client in$ui.sysparams.MYPARAM="value"
objparam
: push an object parameter to UI inobj.locals.MYPARAM
enumCounters
: refresh counters in menu when enum or status has changed during save
Improvements on external objects
Server side
- Added
getFilename
hook forExcelDocumentExternalObject
(and legacyPDFDocumentExternalObject
)
Client side
- Improved JS class
Simplicite.UI.ExternalObject
:- Set metadata
(name, id, URL)
+ business object context if any - Added
getResourceURL
function to get URL of external object's resources - Added
service
function to call server-sideservice
hook
- Set metadata
Floating date search
New filter syntax with offset on date or datetime from today's date.
[DATE<:offset>]
[DATETIME<:offset>]
offset
= a signed number with unit ('y'ears, 'm'onths, 'w'eeks, 'dw' days no week-end, 'd'ays, 'h'ours, 'm'inutes, 's'econds, 'ms')
Examples
// last 3 months
fieldDate.setFilter(">=[DATE:-3m]");
// in next 15 days
fieldDate.setFilter(">=[DATE] and <=[DATE:15d]");
// before next 12 hours
fieldDatetime.setFilter("<[DATETIME:+12h]");
This syntax can be used in predef-search of views/home page.
Custom health check
Added a new customHealthCheck
platform hook for custom health checks, e.g.:
@Override
public void customHealthCheck(HttpServletRequest request, HttpServletResponse response, boolean minimal) throws Exception {
AppLog.info("Custom health check called from " + request.getRemoteAddr());
ServletTool.success(request, response, new JSONObject()
.put("status", "OK")
.put("date", Tool.toDatetime(new Date())));
}
Custom logout confirmation page
Added a new customLogoutConfirmPage
platform hook for a custom logout confirmation page, e.g.:
@Override
public void customLogoutConfirmPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
// ZZZ must use a "try with" to commit HTTP response ZZZ
try (PrintWriter out = response.getWriter()) {
out.print("Bye bye!");
}
}
Improved OpenAPI/Swagger schemas
The OpenAPI/Swagger schemas of generic APIs have been improved to comply with stricter compliance rules:
- Added missing descriptions on definitions (business objects, errors, ...).
- Added missing
maxLength
constraints for string type attributes in OpenAPI schemas
Improved mapped API configuration
For mapped API external objects:
- Added generic mapping capabilities with case conversions, e.g.
{
"name": "My mapped API",
"objects": [ "DemoSupplier", "DemoProduct" ], // or "modules": [ "Demo" ]
"objectsCase": "pascal",
"fieldsCase": "snake",
"pathsCase": "kebab"
}
- Made
/ping
operation optional (using"ping": true|false
in configuration,true
by default for backward compatibility) and added associatedping
hook - Added optional
/health
operation (using"health": true|false
in configuration,false
by default for backward compatibility) with associatedhealth
hook
Development mode
On development environments, you must set the DEV_MODE
environment variable to true
.
Failing to do so will prevent the use of the following features :
- the
devinfo
services (e.g. used by VSCode plugin) - the
/maven
embedded Maven repository - [reminder] Java code formatting (which requires some additional JVM capabilities to be enabled)
The development mode is enabled by the server.devmode=true|false
JVM argument (positioned by the DEV_MODE
environment variable in Docker containers)
Changed scope of helper methods
The ObjectCore.(re)setAllFields*
helper methods used to iterate on all fields except technical fields (row ID and timestamp fields).
This is an issue in v6 where the characteristics of referenced fields may have an influence on the object behavior (e.g. setting them updatable means the referenced record can be updated from the referring object).
These referenced fields are thus now also ignored in these helper methods.
Platform / module version check
A module exported from a higher major version for the platform (e.g. from the future major version 7) will now be refused at module import as it may cause unexpected results.
Importing modules exported from lower major version is still supported.
beforeSave
and afterSave
front hooks
Simplicite.UI.BusinessObject
contains 2 new beforeSave
and afterSave
front hooks:
/**
* Front hook before calling Ajax object.save()
* @param ctn Form container
* @param obj Object (same as this)
* @param index record index (edit list)
* @param cbk callback(true|false) (must return 'true' to continue or 'false' to stop/reject promise)
*/
beforeSave(ctn, obj, index, cbk) {
cbk && cbk(true);
}
/**
* Front hook after calling Ajax object.save()
* @param ctn Form container
* @param obj Object (same as this)
* @param index record index (edit list)
* @param cbk callback(true|false) (must return 'true' to continue or 'false' to stop/reject promise)
*/
afterSave(ctn, obj, index, cbk) {
cbk && cbk(true);
}
Previous hooks form.beforesave
and form.beforesave
are still available but it is recommended to use the class BusinessObject.
Mail service configuration
It is now possible ti use YAML syntax instead of JSON for the mail service configuration.
Due to the generalization of the system parameter configurability
it is recommended to use SIMPLICITE_SYSPARAM_MAIL_SERVICE
instead
of MAIL_SERVICE
environment variable previously described here (using this one is now considered as deprecated)
Maven skip tests
The skipTests
Maven property is now set by default in the pom.xml
files of the module.
The reason is that in the great majority of cases the unit tests are supposed to be processed within a live Simplicité instance, not locally.
It it however possible to change this behavior by explicitly setting the "skipTests": false
in the "maven: {...}"
block of the module's settings.
In this case you should be able to launch unit tests locally if non of them need to be processed within a live Simplicité instance.
Improvements of the generic OpenIDConnect provider
The additional authorize URL parameters acr_values
and prompt
parameters are now supported in the AUTH_PROVIDERS
system parameter.
The nonce
string used by the protocol has also been increased with some additional randomness.
Environment variable based configurability
- Added
[ROOT]
,[URL]
,[ENV:<environment variable name>[:<default value>]]
and[PROP:<JVM property name>[:<default value>]]
substitutions in expressions - Added the above
[ENV:]
and[PROP:]
substitutions in module settings - Added the above
[ENV:]
and[PROP:]
substitutions in loaded values of system parameters (this does not apply to raw system parameter values read from the database usingGrant.getSystemParam("...")
) - Added the possibility to override a system parameter by an environment variable named
SIMPLICITE_SYSPARAM_<system param name>
(this applies only to loaded values of system parameters)
New helper methods
ServletTool.success(request, response, JSONObject)
for success (HTTP code 200) responsesPDFTool.getText(File|bute[])
to extract raw text content of a PDF document
Custom disposition simplification
A new StaticSiteExternalObjectDisposition
custom disposition helper class has been added.
The principle of this class is to store the credentials (auth token and Ajax key) in the browser's session storage and redirect to a "static site" external object. If this external object uses the frontend JS lib (of version 3.1.*+) these credentials are automatically used to retrieve the current's session grant.
The low level HTMLTool
class has been improved to provide disposition-related get resource methods.
An implicit rewrite has been added from */
to */index.html
in "static site" external object contents.
OCR library
- The tesseract.js JS lib has been integrated to provide with basic client-side OCR
Docker health check
Docker images now enables a default health check command (HEALTHCHECK
) calling the ping endpoint (/ping
)
with an call interval of 1 minute and a 3 seconds timeout (after a start period of 10 minutes during which
the call interval is of 30s):
HEALTHCHECK --interval=60s --timeout=3s --start-period=600s --start-interval=30s CMD curl --fail http://localhost:8080/ping || exit 1
If you have implemented a custom ping endpoint response, make sure this default health check command is compliant with it (or change it to comply with it).
The default values of the intervals, timeout and start period should be fine for most cases but may be adapted in some very particular cases (e.g. where start time is very long because it waits for a slow external system to start up).
Simplified ObjectDB search
New API to search records and apply a lambda function on each row:
// search for each row
obj.search((index,count) -> {
// - index: current row number from 0 to count-1
// - count: number of rows found
// - here obj is already loaded with the row values
String id = obj.getRowId();
obj.setFieldValue("myField", "blah");
obj.save();
// ...
if (error)
return false; // stop the loop
return true; // continue
});
Unlike other paginated search methods, this API guarantees that the lambda function, with potential update/delete on requested data, will not corrupt the search pagination:
- first it makes a paginated search to find all matching row Ids
- then it loops on those Ids to make for each row a select and call the lambda function
All thread-safe access to ObjectDB
are now facilitated with the builder BusinessObject
described below.
New BusinessObject API
The new BusinessObject
class works like a builder to chains classic data access methods
and above all, stacks the data without applying them to the ObjectDB
instance
before the final DB operations in a single synchronized block (with select, setValues, validate and save, etc.):
- Auto-close interface to destroy isolated object or restore the initial definition (with
preserveContext
) - Can change the user rights locally and work on any instance of object
- Applies all hooks (init, pre/post...)
- Resets and changes filters/orders
- Manages the Undo/Redo stack (if not
ignoreRedolog
)
Sample to search and update one isolated instance of User
try (BusinessObject bo = getGrant().getBusinessObject("User")) {
bo
// add create/read/update/delete rights
.withCRUD(true, true, true, true)
// use those filters on search
.filters(Map.of(
"usr_login", "bob%",
"usr_lang", "ENU"
))
// count from DB
.count(n -> AppLog.info("count = " + n))
// search for each row
.search((index, count, obj) -> {
try {
// here the record is already set in object fields
String login = obj.getFieldValue("usr_login");
AppLog.info("update languages of login = " + login);
// update values
bo
.withValues(Map.of(
"usr_lang", "FRA",
"usr_lang_pref", "FRA"))
.validateAndSave()
// select values from DB
.values(o -> AppLog.info("values = " + String.join(",", o.getValues())));
return true; // continue
}
catch (GetException | ValidateException | SaveException e) {
AppLog.error("There was an error", e);
return false; // stop the loop
}
})
.then(obj -> {
AppLog.info("usr_lang = " + obj.getFieldValue("usr_lang"));
});
}
finally {
// nothing to do
// - Auto-close without specific instance = destroy the instance
// - Previous user rights are restored on MyObject
}
// Example to stream a search without pagination (uses huge memory)
try (BusinessObject bo = getGrant().getBusinessObject("User")) {
bo
.filter("usr_login", "bob%")
.filter("usr_lang", "ENU")
// search in memory List<String[]>
.stream()
.forEach(row -> {
// in memory stream needs to set the record into object before update
try {
bo
.forUpdate(row)
.withValue("usr_lang", "FRA")
.validateAndSave();
}
catch (ValidateException | SaveException e) {
}
// related ObjectDB accessor
ObjectDB obj = bo.getObject();
AppLog.info("language = " + obj.getFieldValue("usr_lang"));
});
}
Sample to upsert (create if not exists, update if exists) and call one action:
try (BusinessObject bo = new BusinessObject(getGrant(), "MyObject")) {
bo
.getTmpObject() // or getInstance("MyInstance")
.withAllAccess(); // = withCRUD(true, true, true, true)
.preserveContext() // keep the instance definition to be restored on close
.forCreateOrUpdate(Map.of(
"myKeyField1", "bob",
"myKeyField2", "123"))
.withValue("myField1", "value1")
.withValue("myField2", "value2")
.validateAndSave(msg -> AppLog.info("save = "+msg))
.returns(msg -> AppLog.info("msg = "+msg))
.action("MyActionName",
Map.of("param1", "value1"),
msg -> AppLog.info("action result = "+msg));
}
catch (GetException | ValidateException | SaveException | ActionException e) {
AppLog.error("There was an error", e);
}
finally {
// nothing to do
// - Auto-close with preserveContext = restore "tmp" (or "MyInstance") previous definition
// - Previous user rights are restored on MyObject
}
Custom document storage
3 platform hooks have been added to allow custom document file storage: readDocument
, writeDocument
and deleteDocument
.
Typical usage can be using specific external cloud storage (like S3 object storage) for some business objects and/or fields.
All 3 hooks receive as argument the relative/absolute path of the file to read/write/delete to allow fine-grained management of target storages.
There is a comprehensive example module here using a custom S3 (Minio server) storage for one particular business object.
These hooks are the first building block of a future enhancement of the standard documents storage configuration. They are still to be considered as experimental as their signature might change in next versions.